Compare commits
1019 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 095fff96ff | |||
| a23211d061 | |||
| b57ea41686 | |||
| 62fb5ffb73 | |||
| 99c713967b | |||
| 9f3de07bd8 | |||
| cd74117de3 | |||
| e7d7033548 | |||
| 34db7c9dac | |||
| 272841aae9 | |||
| 389b09a5cd | |||
| 84bd876c71 | |||
| 7e45051ffd | |||
| 5570f3a313 | |||
| f4e71f7012 | |||
| 601d4e6e3a | |||
| a12092c1a1 | |||
| 94ad118c5d | |||
| 48e2978438 | |||
| 96b4c1a9e8 | |||
| cc4a69c10c | |||
| 7293677ddb | |||
| 0f2ff20375 | |||
| 7706240acb | |||
| 4cf48fd997 | |||
| 2708c1ee11 | |||
| ebb0f6ebad | |||
| 2c263a2549 | |||
| 955524c632 | |||
| 564e0d3263 | |||
| c533b2e8ea | |||
| 6073d8122a | |||
| 71ca26bba9 | |||
| 75a51be28c | |||
| a66e4ba157 | |||
| f2b9e428d3 | |||
| 5b2497b9d4 | |||
| e78424def4 | |||
| e2c94de6e6 | |||
| 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 | |||
| e7b60b7562 | |||
| 2615177907 | |||
| a83d7e2a26 | |||
| 8a2182e238 | |||
| d45455092c | |||
| da18469fd4 | |||
| 6b5bae9bee | |||
| e29a7786e4 | |||
| 55a837ca5e | |||
| 94cba6cf67 | |||
| 294685df00 | |||
| 2642b7a9a4 | |||
| 45594e4e47 | |||
| 54cd1a2e48 | |||
| a20fb982ec | |||
| 184d61e637 | |||
| 06ea56767f | |||
| 1f6e137759 | |||
| c7cf7885ae | |||
| 8e98444887 | |||
| 9bfe2e8233 | |||
| 21f4adc769 | |||
| 3b10ca5809 | |||
| 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 | |||
| c0ccef7e82 | |||
| 55e5c64c68 | |||
| da72f783ed | |||
| 8a9bfa3d33 | |||
| 82937d840a | |||
| c1bd358502 | |||
| a8a22fd9fe | |||
| adb70857fe | |||
| a680596b3e | |||
| b2986ec782 | |||
| f40f7afab3 | |||
| 59555d1ca8 | |||
| 6e2eb7d1ac | |||
| 69483067b4 | |||
| c815591565 | |||
| f82b7ec608 | |||
| 23a107682c | |||
| 26da69c875 | |||
| 8f2df2396d | |||
| dbc9cbb418 | |||
| 09c788e495 | |||
| 9af71ac0ea | |||
| 2db20f8f24 | |||
| 2c9827c227 | |||
| 825b1ab4db | |||
| c61faac06c | |||
| 6b442f03c1 | |||
| 10ab638643 | |||
| d349d0c453 | |||
| e5c948ce9c | |||
| c51255f379 | |||
| 5bbeceee56 | |||
| ee78920a88 | |||
| 138972cf18 | |||
| 1bda767cd7 | |||
| cf1402edb9 | |||
| 778144a553 | |||
| fcca51a8d9 | |||
| 3cc663ee95 | |||
| 52f15a86fd | |||
| 734bb4afb8 | |||
| 9cd48fb5d7 | |||
| cd5c3d9f13 | |||
| 73ba1c8b56 | |||
| 8199b4408a | |||
| c00e3d7393 | |||
| 5d60251da0 | |||
| 855d707b3e | |||
| 592a1c3601 | |||
| da280db0f8 | |||
| 0ee6673e68 | |||
| 8bedb3dbaa | |||
| ea0e24b430 | |||
| cd35461df6 | |||
| 40580e81c2 | |||
| 1a279b90be | |||
| e34203fe3d | |||
| 870c0f68d3 | |||
| 004059dd9f | |||
| 4290cdf8c6 | |||
| 4d038fc5e6 | |||
| 0146d62c2a | |||
| 4e6255dc2b | |||
| 4d73c3ecb8 | |||
| d0dc3ec9bc | |||
| ee922236a0 | |||
| bf088ab29c | |||
| 40102521a1 | |||
| eb491144f3 | |||
| a14748ac75 | |||
| 0c5f38a00b | |||
| feb6dd41b7 | |||
| a093524939 | |||
| 5cc7bebbe5 | |||
| 32a256619f | |||
| f93e648f69 | |||
| 41f022df99 | |||
| c84aac7e45 | |||
| 4e4fbbe48c | |||
| 7265e2b631 | |||
| 0a11f310cf | |||
| a6143780fa | |||
| 761f802ced | |||
| 2e7cc9f4b6 | |||
| 4e6e727799 | |||
| 2da444d03c | |||
| f4f234a159 | |||
| e87823aa29 | |||
| 56167a137e | |||
| 91ac4309df | |||
| 8a5bca3136 | |||
| ec8d1b5538 | |||
| 0ebe8db268 | |||
| 3bba08723f | |||
| 6a6a87a3f7 | |||
| 0ccdcfbb6d | |||
| aa084c885d | |||
| e3a8a7782e | |||
| c578ae0fa4 | |||
| f17bc1eccd | |||
| 08c31e5999 | |||
| dd341c9a22 | |||
| 733fb8e871 | |||
| 4764f0969a | |||
| 41f8c8cfa4 | |||
| 42bcc28d3e | |||
| b878faac96 | |||
| 32c1cc29f8 | |||
| 838d82589b | |||
| b62af66f4b | |||
| 794f524ae3 | |||
| a38551b3d0 | |||
| 03c4926b09 | |||
| 982bf951e1 | |||
| a887e35285 | |||
| 172f2b088d | |||
| 6d7b557c36 | |||
| 9959ebc196 | |||
| d868b8fc72 | |||
| 297c8a1a1e | |||
| e809429a8c | |||
| 200ad05f4c | |||
| 9b4276c29b | |||
| 038073d34d | |||
| 8d32ab9bdb | |||
| 9390b8bc4d | |||
| 0d165860fb | |||
| 4135fa6211 | |||
| 1d89467022 | |||
| e21ac626b3 | |||
| aa73a30ac4 | |||
| 9a8f14c7d3 | |||
| d7618d73c3 | |||
| 5aca47b357 | |||
| 666ab1319b | |||
| 50663edc76 | |||
| 1fbc37f8e7 | |||
| 5f437f8a4e | |||
| 6130c65c48 | |||
| 1e19dfd6e8 | |||
| f866243d5c | |||
| af04c6d995 | |||
| 46bf8d0188 | |||
| fc62c78136 | |||
| 93c2bf530f | |||
| 51b543a23e | |||
| dab5373231 | |||
| 17f274a7b4 | |||
| 841e5ba492 | |||
| 50339c94e7 | |||
| d2ad35ad05 | |||
| 0d65578e6a | |||
| 526df4f184 | |||
| aa6cbd1b7d | |||
| 92f0703723 | |||
| 064241333b | |||
| 39b77c783b | |||
| 0c8717a0da | |||
| 7f89a1a2cc | |||
| 5f16f81d58 | |||
| 10bbcc79d3 | |||
| ffc9771b17 | |||
| 091b115aad | |||
| c3bdc22e28 | |||
| 28d4cc86a9 | |||
| bb6e29f254 | |||
| ea0d4ba7d8 | |||
| 0504882afd | |||
| 0156f03e91 | |||
| d2acaba5c7 | |||
| 60e4128316 | |||
| dc8aa7624b | |||
| 941aeedee0 | |||
| 4d8ce3b5ea | |||
| 6044d24a48 | |||
| d597634ac6 | |||
| cf8b0329bb | |||
| 24520824e9 | |||
| 0d7b0f9fe4 | |||
| 61460f9ac0 | |||
| 14d64d535a | |||
| b00c252f17 | |||
| 0fe017df74 | |||
| 4ae7083dcf | |||
| 7d5357dec8 | |||
| 2bb2f5a233 | |||
| fee1c98a34 | |||
| e787d7d317 | |||
| ed52efa72b | |||
| 963d22b2f5 | |||
| 8714be1dc7 | |||
| 04ddd83519 | |||
| 5b81ca2716 | |||
| 6f8c7e8249 | |||
| fabad7158e | |||
| bae7e44dd8 | |||
| 926c7924df | |||
| 704a2ff217 | |||
| 871c6031b8 | |||
| afb0a57920 | |||
| 1787d2c6d9 | |||
| 1a07fb83b6 | |||
| 4d2ee292bb | |||
| 0fdde61fe5 | |||
| ae8a4912a6 | |||
| ffd8ea8751 | |||
| 4cd10a82fd | |||
| 4955d22649 | |||
| 425b761f8e | |||
| ab3bfd457f | |||
| 0faa64112a | |||
| 46519b096c | |||
| cb7d980e15 | |||
| 6c1562ac33 | |||
| 5e17e4ea8c | |||
| b8e7b14fbb | |||
| 5d8eb185bc | |||
| 7325cedba6 | |||
| e5043d6d9b | |||
| 13e53a18e3 | |||
| dd60c7620f | |||
| 83c01cabfb | |||
| a95171dbbe | |||
| 10d542ed14 | |||
| 7e1c55a0c5 | |||
| 4e25d318ec | |||
| c4228f4e63 | |||
| 1411091f60 | |||
| 6a2278949e | |||
| 374b859882 | |||
| a98bdb94b8 | |||
| de390f5d70 | |||
| 9d4968351b | |||
| e99fbb76bf | |||
| fd175d2f36 | |||
| 0db862e42b | |||
| 58f5d64f91 | |||
| bb54a94acd | |||
| e34a7eef06 | |||
| 3d177369ab | |||
| 946aff24af | |||
| 424429bff1 | |||
| 55df8daa35 | |||
| 734edeaba9 | |||
| 48452e6fe7 | |||
| 314c88a452 | |||
| 3a782a1c4b | |||
| 924b2b7e8e | |||
| 34565992ea | |||
| dbc84cc0f3 | |||
| 15de27eafd | |||
| 8a882d7bf4 | |||
| 04ee9d58bc | |||
| ee867e972f | |||
| a227547daa | |||
| ef1699f2e9 | |||
| 108f692c82 | |||
| a3026fbb61 | |||
| 33c2ca839e | |||
| 4ac4daeac1 | |||
| 49f90aa5c9 | |||
| 6788ac41c5 | |||
| 8e25deb33d | |||
| 3d31d20a46 | |||
| 7b902a4be1 | |||
| fbd48b3cfa | |||
| 9475040627 | |||
| a673a3be4b | |||
| 2d444ab0bf | |||
| 95e29f36ef | |||
| ad97f322b2 | |||
| f19281e832 | |||
| 3c91e53228 | |||
| 3f35909641 | |||
| 384ba30a61 | |||
| 33b5c225a4 | |||
| 1a3560feef | |||
| ae2e45b52f | |||
| 1bb2ef29f5 | |||
| 59ad956ba1 | |||
| 4af6ec7428 | |||
| 32b59ee8a4 | |||
| 0d5a8dee73 | |||
| 91863034e8 | |||
| f705fee90f | |||
| d10a9e08d7 | |||
| 070d7e23d5 | |||
| 1b200259c5 | |||
| e21149466e | |||
| f6528be87f | |||
| e8c2271db8 | |||
| 9f5c63d9e2 | |||
| 539048bfac | |||
| e155e68289 | |||
| 083fab7323 | |||
| 5450a7efe4 | |||
| f6860ed4af | |||
| 15ed0c2392 | |||
| 22f290c8a3 | |||
| 6d39fb23d6 | |||
| 0a523b99c7 | |||
| c537ab2082 | |||
| 63005035d7 | |||
| c8d03a625a | |||
| d11d26dc9f | |||
| 1932cf9e76 | |||
| 97e6797fea | |||
| c4105c3014 | |||
| 826b4a6305 | |||
| 0cb0874c54 | |||
| b831dd84e4 | |||
| 6775bf8a3d | |||
| 61402afd93 | |||
| c5cff674fe | |||
| 679b5c082a | |||
| e00faa8e3c | |||
| e5265f3dbb | |||
| 71e3e10280 | |||
| 9443f6d1e5 | |||
| 415c553308 | |||
| 4b783df11e | |||
| 6d7135ef29 | |||
| c0f8b6729b | |||
| a5a01b8a76 | |||
| ecd44d9d31 | |||
| fb4f0b0440 | |||
| c0bd3dda19 | |||
| d4c94ea5e4 | |||
| 1a48d161d9 | |||
| adbb9cbc40 | |||
| 40db006d62 | |||
| ed64e83807 | |||
| 644b5462f1 | |||
| 33aded7345 | |||
| d04314a9ee | |||
| fadc2e7ab4 | |||
| 8fc6d4a1de | |||
| 87c3f5549c | |||
| 1e9120c6d9 | |||
| 53a6b9fcd0 | |||
| 682fb11e9e | |||
| 17f515ef06 | |||
| 3f6bc262cd | |||
| 5f025808ab | |||
| b93c5815c7 | |||
| 1482bfcd07 | |||
| 71634f509a | |||
| 608e2d5723 | |||
| f39d2d92f7 | |||
| 264a9b66fa | |||
| bee9cce881 | |||
| ec63a025fd | |||
| 69c5f49c72 | |||
| 64d2363050 | |||
| 796f450091 | |||
| aa0f274b87 | |||
| c3103810db | |||
| 7fb021010c | |||
| b5267a0658 | |||
| 1775a58938 | |||
| 76f7371057 | |||
| 727d7ee346 | |||
| 40618bc35a | |||
| 2463d8c024 | |||
| 90c53d8116 | |||
| eb4e3bc793 | |||
| 172d43a11b | |||
| 75419ed5ae | |||
| 94978fe10a | |||
| 71493e79d5 | |||
| 48fc9d13ad | |||
| 867152fdf2 | |||
| 7d13cb4905 | |||
| 115c531be2 | |||
| fee8dc9b13 | |||
| 0bbaa15579 | |||
| aeb7cf6ff1 | |||
| 0be45abc28 | |||
| a6bff2abb0 | |||
| f4d6e63c47 | |||
| 2edabc7168 | |||
| 46e5bf24ca | |||
| ba014fc581 | |||
| 225dad9d84 | |||
| ca2914d3a9 | |||
| 85203847d5 | |||
| db2cdbaecd | |||
| 3a80c6f59e | |||
| 0137a6bfd0 | |||
| 8b4c647fd2 | |||
| d4ba61e341 | |||
| 634df3ba06 | |||
| 88766f30e4 | |||
| 14a15754fb | |||
| c919fe9ab0 | |||
| 13bf04ef2d | |||
| e42919c37f | |||
| 5a3bd0c9dd | |||
| e1907245e2 | |||
| e476b56ac1 | |||
| 776ec93d09 | |||
| fc0aafb070 | |||
| 54fa033e07 | |||
| cbd0521a0c | |||
| e958790f76 | |||
| 06bb4a9cb3 | |||
| b38a8d5e62 | |||
| 84028f78b8 | |||
| 515c45b4c8 | |||
| 0cac09aec1 | |||
| 695809d573 | |||
| e12f33a938 | |||
| 8e69174d5a | |||
| 3ea6bee3cf | |||
| c1fda715d0 | |||
| e4a7056d48 | |||
| 2107d3cbbd | |||
| ef6fc07cd3 | |||
| 56172c69a4 | |||
| a92aa1eca8 | |||
| f2931e8204 | |||
| 5d47a5f391 | |||
| 299fbe7336 | |||
| b30c8ea413 | |||
| 64dea2d730 | |||
| 9edba26910 | |||
| cf6b3d9a89 | |||
| 47f297809b | |||
| 12b4521df6 | |||
| 48291e261e | |||
| 7c9fd5be9c | |||
| 8d822d7f3c | |||
| f42a76c8fd | |||
| 8765f9effa | |||
| 276b839668 | |||
| 507b045eb9 | |||
| 1de8cfb001 | |||
| 1ab8483df5 | |||
| 969edef3b2 | |||
| 20be303dd0 | |||
| fc43f866a1 | |||
| eca04899de | |||
| 7b7fb8db44 | |||
| 313b660334 | |||
| 5b84b26b67 | |||
| 6dc567e079 | |||
| 13b26d5902 | |||
| 3d7b21c444 | |||
| fc5879beab | |||
| 251c9d1134 | |||
| 0a1bf750ba | |||
| a236264d14 | |||
| ba45a7c2f5 | |||
| 95b1ecff0d | |||
| 8ad5565148 | |||
| 5cda6a6f2c | |||
| 6f35d0710e | |||
| 0c87a2a9ea | |||
| 3ddc315826 | |||
| b888103c80 | |||
| 09e689dc2f | |||
| 0f61affac8 | |||
| 57e44cc4a7 | |||
| 876c4f2510 | |||
| 6c4364f009 | |||
| d96fc3c73b | |||
| e3da644b1c | |||
| 34bb512f03 | |||
| fae58503a8 | |||
| 0ea69d0ca4 | |||
| 3144e9d957 | |||
| 30fac5e5ce | |||
| 37cbeebaa5 | |||
| 3aa6cc3383 | |||
| 56dd3c352e | |||
| 83fa1a0281 | |||
| 5b4049e0ca | |||
| 888651ef52 | |||
| a122b2c143 | |||
| a41afa0dbf | |||
| d9b969e7a7 | |||
| 9297ac4c35 | |||
| 7ee42a9529 | |||
| 640559239c | |||
| 263574bf38 | |||
| 60cbbb0393 | |||
| 91f9f17989 | |||
| a96e345fbe | |||
| 9ffc54f0b1 | |||
| bf3428b53c | |||
| c78f6eb66d | |||
| 73f4bc3108 | |||
| 73a42284f1 | |||
| 90accf01db | |||
| 1cb60f6a6d | |||
| bfcc4b001d | |||
| 2f7852f103 | |||
| 944b3c05ab | |||
| 531a308b39 | |||
| 27cd001680 | |||
| e5ee46335d | |||
| ef72cdc0e6 | |||
| 246bd54b55 | |||
| e1147f3f60 | |||
| 3bc0104268 | |||
| 50e9a51f56 | |||
| 87fec5276d | |||
| 2b734bb8d4 | |||
| 2d93a23da9 | |||
| 1ac1b7ee2d | |||
| 81adca92c0 | |||
| d509694ba9 | |||
| 7f658bd310 | |||
| d7728cce45 | |||
| 4d649d8a33 | |||
| c3d0cc2da8 | |||
| 0b67d64ff4 | |||
| 386dc38150 | |||
| ba6b08b818 | |||
| 2cfef3a84d | |||
| 8b20e1ee6d | |||
| b254fde3ae | |||
| 876989346b | |||
| 7278bc1548 | |||
| 1728c3e898 | |||
| 80393529f1 | |||
| b9d635ac69 | |||
| cca668979f | |||
| 0e017cf512 | |||
| b1e75431ae | |||
| e12d7766d6 | |||
| e43ee68508 | |||
| 9a9aac64af | |||
| 5193a3313d | |||
| 2ff1b80650 | |||
| 7e0e51103b | |||
| 2977486866 | |||
| bb9df60004 | |||
| a1b42f61fb | |||
| b394c01f47 | |||
| c047996592 | |||
| cc2340d1b9 | |||
| 01b233e968 | |||
| c53cf3f870 | |||
| 4f0da248e3 | |||
| 44688afeb9 | |||
| 4301ed9917 | |||
| 0b26f8ce3c | |||
| 815aed53fc | |||
| 9cde0edfa3 | |||
| 70b3ba0040 | |||
| 32c89b1af9 | |||
| 21144a7ce4 | |||
| 0935a6e94b | |||
| f28f09dd40 | |||
| f564755d66 | |||
| 2af274171c | |||
| de726b7669 | |||
| 22d134e786 | |||
| 642b040f65 | |||
| 0cc883b6c3 | |||
| 902362f54f | |||
| f9c946e3ce | |||
| 9020d5bbe6 | |||
| fe973d27b9 | |||
| e9c1f41f50 | |||
| 630e3bf16f | |||
| 27df83f8e7 | |||
| 4ad9bb0d71 | |||
| 4fcd4cb2f7 | |||
| 15beb792d1 | |||
| 401daf907c | |||
| a3f6f51a7a | |||
| e4cd89131e | |||
| 32d8553b9b | |||
| 092fc45a36 | |||
| 9f58cf305f | |||
| c1370e74a2 | |||
| 3b3ec1eee2 | |||
| 803d26c7c7 | |||
| 9244f29daa | |||
| 0a9e789cdc | |||
| a761ef4b6b | |||
| 3f4df4289c | |||
| 879c70a7a0 | |||
| b0c1f69023 | |||
| 889474fb42 | |||
| 4ad6c854c8 | |||
| 521549a349 | |||
| ee06d81434 | |||
| 3f6ee90b4e | |||
| a017586c0e | |||
| 027b867afd | |||
| 67b61b55a3 | |||
| b2efeb77e1 | |||
| 2929009e63 | |||
| 4604751f80 | |||
| 6906597165 | |||
| 8235a911ab | |||
| 8af8039a00 | |||
| b399121f20 | |||
| bf519301f5 | |||
| 9f0378f969 | |||
| ea9cb7fcac | |||
| 7ba1f77a19 | |||
| 739947e008 | |||
| cfb0dd4096 | |||
| 92ff5beebc | |||
| 8bb1251dc9 | |||
| a52a122f9f | |||
| c90efed0fe | |||
| b41119232e | |||
| 9fefaf6eca | |||
| b5f3be4fcc | |||
| f6c05303ea | |||
| 18b0b8c6f4 | |||
| 9c73443aa2 | |||
| 8fd5c6e3a4 | |||
| fb57fbbe8d | |||
| 98d2b0db3f | |||
| c895dff2c8 | |||
| 5cd6111e92 | |||
| a57a34ab58 | |||
| 49baaaab85 | |||
| f8a0ce84de | |||
| 7408187507 | |||
| f2c2c5dd92 | |||
| dbefea35c2 | |||
| f887f38e17 | |||
| 080a99d6db | |||
| 7fee50883a | |||
| 9bc97780a4 | |||
| 7b3f63a2f2 | |||
| 60be8302f4 | |||
| c2ec60c6e5 | |||
| fef7369338 | |||
| 036754c54a | |||
| 8e0ccd781b | |||
| 1ee02211b9 | |||
| a2ac2e00da | |||
| a33ecec9d3 | |||
| b0937fd9d0 | |||
| d1283db786 | |||
| dc556efe0b | |||
| 0ff59e49a1 | |||
| febf5c31cc | |||
| 1665999111 | |||
| 14dd26349a | |||
| 54e356d98c | |||
| 959dd4e718 | |||
| a61b2cb2fc | |||
| 6ac5b7f9a3 | |||
| 3f26a70169 | |||
| 084bf635cb | |||
| f1a7e69c63 | |||
| 93cfc64493 | |||
| eeaa836c45 | |||
| 30d3d8c52e | |||
| eaa61098fa | |||
| 2ee087f29d | |||
| d8861f6100 | |||
| 8802ce0a32 | |||
| 7405839718 | |||
| 2d77efd8ea | |||
| 9c73926cd2 | |||
| 0c7b1e06fd | |||
| 113bd75154 | |||
| 3d268adeea | |||
| 3ac2392edb | |||
| 008f5cf915 | |||
| 77cc7fe669 | |||
| b6d352fbce | |||
| fc8426a2ee | |||
| cd78ffc069 | |||
| 5230a4abf9 | |||
| c37304d114 | |||
| 0144619ed4 | |||
| b7cc51bb3e | |||
| 96c844c6e8 | |||
| 09930b1754 | |||
| 8cf51d0f77 | |||
| d3667b0e3a | |||
| 3ae7f3a299 | |||
| 800d64c923 | |||
| fd2a1ca036 | |||
| d8e631f52b | |||
| f41e182f86 | |||
| 4876ee5d7c | |||
| 58d5f16845 | |||
| b26b072332 | |||
| ab62c62079 | |||
| dacf573548 | |||
| 11baa7956d | |||
| 88bab7736b | |||
| cf5dcb63d1 | |||
| fe92203201 | |||
| e9c2a6e0e4 | |||
| 21f665c941 | |||
| c9c96ff2e8 | |||
| 1e8964a162 | |||
| e5cbcf2614 | |||
| 995f30b7e2 | |||
| 64e0f9b48f | |||
| db7001dd6f | |||
| d70de5dac6 | |||
| 0a45192030 | |||
| bdda96854e | |||
| 638e7c19a3 | |||
| cedb63a505 | |||
| 84941639ff | |||
| cb8e4231a5 | |||
| 447759304a | |||
| 0b8f57a952 | |||
| 5808179abb | |||
| 87f3a718b4 | |||
| 6c79c6b1ff | |||
| 889daecc86 | |||
| 10de377081 | |||
| 310b237b7d | |||
| e71727c6f9 | |||
| 213d7a30b4 | |||
| bc1a0123b2 | |||
| b3c4c790dc | |||
| d96c96fc6e | |||
| 79513b6c52 | |||
| 6fca33e496 | |||
| 0184396b6a | |||
| 47963fba43 | |||
| cd95405c6a | |||
| 3936b63580 | |||
| c1c4a91bbf | |||
| 51b93a7e3f | |||
| bde11b5950 | |||
| 3aab0469ab | |||
| dd2c9d1e56 | |||
| 4dbae72eae | |||
| 2aac43485a | |||
| 6aa94d1ec5 | |||
| a9b1ca888a | |||
| 6477408858 | |||
| 1b66672166 | |||
| 207d5cb949 | |||
| 3b90855781 | |||
| 61c4b50528 | |||
| 38085c3e7d | |||
| a16099bc98 | |||
| 0342b4b5a9 | |||
| 9be222f25f | |||
| 5e242561bd | |||
| 014b49246d | |||
| d57192f76a | |||
| a52c286241 | |||
| 16bcf30092 | |||
| b2ba94f6e5 | |||
| 7d8ab781cb | |||
| 52f52b1c1b | |||
| 9a5ebce51e | |||
| 960488bef4 | |||
| 318d514b41 | |||
| 01f767486d | |||
| eba2036718 | |||
| f9a7aa3c62 | |||
| 064c69d66c | |||
| 1ef2084e3b | |||
| 0396c5e384 | |||
| a02fb42490 | |||
| b82d9d6d9a | |||
| e2855e8984 | |||
| 2bbf081f99 | |||
| f4784840fd | |||
| 3464341c04 | |||
| ff16a97ce8 | |||
| 56c666ead8 | |||
| 12ef1f30f1 | |||
| 5d7abd5f70 | |||
| 047dc0d4f5 | |||
| a1f9fdc715 | |||
| 4554052471 | |||
| 17762a9e49 | |||
| bdfc053596 | |||
| 68e93ac19a | |||
| bdd01eef2b | |||
| fc68645ba3 | |||
| 4c2d1458de | |||
| 5f51cb11fe | |||
| 661aa37d71 | |||
| 7756bd4fa1 | |||
| 19daa14f94 | |||
| afbb0e05aa | |||
| 1de329ed9b | |||
| 5915bb1f70 | |||
| 38c368d9fe | |||
| 637a8cfe65 | |||
| ef47e1d85d | |||
| 97f19915bd | |||
| a487653444 | |||
| b649b1c279 | |||
| 1a0f1244fa | |||
| 67612e1e92 | |||
| 650c4b30a5 | |||
| 3be9848da3 | |||
| d339a86b92 | |||
| 64d6e2ea55 | |||
| 77a5906ee5 | |||
| ff0547f2b9 | |||
| b9aa2e1cca | |||
| 7624764ee0 | |||
| 08d15f7728 | |||
| ebd6aa0d74 | |||
| 1b84d8bf0b | |||
| 2b1b54a646 | |||
| a65dc83721 | |||
| 78c6fea352 | |||
| 03da6d87b5 | |||
| e0e6ac402e | |||
| 288459c88b | |||
| fe41d03437 | |||
| 940933eff4 | |||
| e45b479ae3 | |||
| d3ec5a9ac2 | |||
| 7d20354ba5 | |||
| 12548099f1 | |||
| 643c66a12f | |||
| da719b4a7e | |||
| 2a3ae34294 | |||
| 27f7440165 | |||
| 73ff60a0f6 | |||
| a80843ce77 | |||
| 4a9dc216e7 | |||
| 72c9de354e | |||
| ae269b3a74 | |||
| f3bc22cdc8 | |||
| 92cc8bf6f6 | |||
| 05b6e74482 | |||
| 90fb950fc3 | |||
| 005f1ed8a0 | |||
| bb4497dd80 | |||
| 8956bc4980 | |||
| 0a91473402 | |||
| 4df12e7316 | |||
| 3ff4e0f9a6 | |||
| 6c5b1501e9 | |||
| c1fddd1b82 | |||
| 256e3a1dbb | |||
| 2fbc69cb34 | |||
| d3a06b8597 | |||
| 9d9370f2f5 | |||
| aa6ae3084e | |||
| 9bd66aa54b | |||
| c33c0a4acb | |||
| fc9ce8243a | |||
| ddf8950cc0 | |||
| f2832a0fd6 | |||
| 4660c4d5bf | |||
| 1b60c66eec | |||
| ac939a5e95 | |||
| ea0a98c9f0 | |||
| baa11f481e | |||
| 1cbb124ba0 | |||
| 883685de83 | |||
| 91864443d5 | |||
| b48d6bfd4b | |||
| a1ede75450 | |||
| db73aaeabb | |||
| 284690338c | |||
| 550a1a44ef | |||
| 5203c03257 | |||
| 1a9f56c03e | |||
| 3cf0c724f4 | |||
| 3e96b01981 | |||
| 59658441ff | |||
| a4e20114a7 | |||
| aa1315dd57 | |||
| 271149baa4 | |||
| 680f6dc317 | |||
| 0e6282e90e | |||
| e9f66dc091 | |||
| 88f6acb618 | |||
| 6f36cd3305 | |||
| b476da8ba4 | |||
| 873187e210 | |||
| 5ec21065cc | |||
| dbdbb14bac | |||
| 2cbc98a26a | |||
| 5739eb9a85 | |||
| f6887ee7d5 | |||
| 12698c5d39 | |||
| 8244932247 | |||
| 39ef896138 | |||
| 258a2a8ee7 | |||
| 0b570ba15d | |||
| 7d4e6e59d9 | |||
| 9c543e2ec8 | |||
| d9ef9282ad | |||
| 5c1058ca76 | |||
| c30cb1c04d | |||
| 5caf11789f | |||
| ef02856b45 |
@@ -0,0 +1,19 @@
|
||||
**/.git
|
||||
**/.gitlab
|
||||
**/.cache
|
||||
|
||||
buildAllJars
|
||||
|
||||
**/_Misc Files
|
||||
*.bat
|
||||
*.md
|
||||
*.sh
|
||||
*.txt
|
||||
|
||||
coreSubProjects/*.md
|
||||
coreSubProjects/*.txt
|
||||
|
||||
**/.gitignore
|
||||
**/.gitattributes
|
||||
**/.gitlab-cy.yml
|
||||
**/.gitmodules
|
||||
+701
@@ -0,0 +1,701 @@
|
||||
# DH Main
|
||||
root = true
|
||||
|
||||
# Note: please keep this and the core .editorconfig in sync
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = crlf
|
||||
indent_size = 4
|
||||
indent_style = space
|
||||
insert_final_newline = false
|
||||
max_line_length = 1000
|
||||
tab_width = 4
|
||||
trim_trailing_whitespace = false
|
||||
ij_continuation_indent_size = 8
|
||||
ij_formatter_off_tag = @formatter:off
|
||||
ij_formatter_on_tag = @formatter:on
|
||||
ij_formatter_tags_enabled = true
|
||||
ij_smart_tabs = false
|
||||
ij_visual_guides = none
|
||||
ij_wrap_on_typing = false
|
||||
|
||||
[*.java]
|
||||
indent_style = tab
|
||||
ij_smart_tabs = true
|
||||
ij_java_align_consecutive_assignments = false
|
||||
ij_java_align_consecutive_variable_declarations = false
|
||||
ij_java_align_group_field_declarations = false
|
||||
ij_java_align_multiline_annotation_parameters = false
|
||||
ij_java_align_multiline_array_initializer_expression = false
|
||||
ij_java_align_multiline_assignment = false
|
||||
ij_java_align_multiline_binary_operation = false
|
||||
ij_java_align_multiline_chained_methods = false
|
||||
ij_java_align_multiline_deconstruction_list_components = false
|
||||
ij_java_align_multiline_extends_list = false
|
||||
ij_java_align_multiline_for = false
|
||||
ij_java_align_multiline_method_parentheses = false
|
||||
ij_java_align_multiline_parameters = false
|
||||
ij_java_align_multiline_parameters_in_calls = false
|
||||
ij_java_align_multiline_parenthesized_expression = false
|
||||
ij_java_align_multiline_records = false
|
||||
ij_java_align_multiline_resources = false
|
||||
ij_java_align_multiline_ternary_operation = false
|
||||
ij_java_align_multiline_text_blocks = false
|
||||
ij_java_align_multiline_throws_list = false
|
||||
ij_java_align_subsequent_simple_methods = false
|
||||
ij_java_align_throws_keyword = false
|
||||
ij_java_align_types_in_multi_catch = false
|
||||
ij_java_annotation_parameter_wrap = off
|
||||
ij_java_array_initializer_new_line_after_left_brace = false
|
||||
ij_java_array_initializer_right_brace_on_new_line = false
|
||||
ij_java_array_initializer_wrap = normal
|
||||
ij_java_assert_statement_colon_on_next_line = false
|
||||
ij_java_assert_statement_wrap = off
|
||||
ij_java_assignment_wrap = off
|
||||
ij_java_binary_operation_sign_on_next_line = false
|
||||
ij_java_binary_operation_wrap = off
|
||||
ij_java_blank_lines_after_anonymous_class_header = 0
|
||||
ij_java_blank_lines_after_class_header = 0
|
||||
ij_java_blank_lines_after_imports = 1
|
||||
ij_java_blank_lines_after_package = 1
|
||||
ij_java_blank_lines_around_class = 1
|
||||
ij_java_blank_lines_around_field = 0
|
||||
ij_java_blank_lines_around_field_in_interface = 0
|
||||
ij_java_blank_lines_around_initializer = 0
|
||||
ij_java_blank_lines_around_method = 0
|
||||
ij_java_blank_lines_around_method_in_interface = 0
|
||||
ij_java_blank_lines_before_class_end = 1
|
||||
ij_java_blank_lines_before_imports = 1
|
||||
ij_java_blank_lines_before_method_body = 0
|
||||
ij_java_blank_lines_before_package = 1
|
||||
ij_java_block_brace_style = next_line
|
||||
ij_java_block_comment_add_space = false
|
||||
ij_java_block_comment_at_first_column = true
|
||||
ij_java_builder_methods = none
|
||||
ij_java_call_parameters_new_line_after_left_paren = false
|
||||
ij_java_call_parameters_right_paren_on_new_line = false
|
||||
ij_java_call_parameters_wrap = normal
|
||||
ij_java_case_statement_on_separate_line = true
|
||||
ij_java_catch_on_new_line = true
|
||||
ij_java_class_annotation_wrap = off
|
||||
ij_java_class_brace_style = next_line
|
||||
ij_java_class_count_to_use_import_on_demand = 5
|
||||
ij_java_class_names_in_javadoc = 1
|
||||
ij_java_deconstruction_list_wrap = normal
|
||||
ij_java_do_not_indent_top_level_class_members = false
|
||||
ij_java_do_not_wrap_after_single_annotation = false
|
||||
ij_java_do_not_wrap_after_single_annotation_in_parameter = false
|
||||
ij_java_do_while_brace_force = never
|
||||
ij_java_doc_add_blank_line_after_description = true
|
||||
ij_java_doc_add_blank_line_after_param_comments = false
|
||||
ij_java_doc_add_blank_line_after_return = false
|
||||
ij_java_doc_add_p_tag_on_empty_lines = false
|
||||
ij_java_doc_align_exception_comments = false
|
||||
ij_java_doc_align_param_comments = false
|
||||
ij_java_doc_do_not_wrap_if_one_line = true
|
||||
ij_java_doc_enable_formatting = true
|
||||
ij_java_doc_enable_leading_asterisks = true
|
||||
ij_java_doc_indent_on_continuation = false
|
||||
ij_java_doc_keep_empty_lines = true
|
||||
ij_java_doc_keep_empty_parameter_tag = true
|
||||
ij_java_doc_keep_empty_return_tag = false
|
||||
ij_java_doc_keep_empty_throws_tag = true
|
||||
ij_java_doc_keep_invalid_tags = true
|
||||
ij_java_doc_param_description_on_new_line = false
|
||||
ij_java_doc_preserve_line_breaks = false
|
||||
ij_java_doc_use_throws_not_exception_tag = true
|
||||
ij_java_else_on_new_line = true
|
||||
ij_java_enum_constants_wrap = off
|
||||
ij_java_extends_keyword_wrap = normal
|
||||
ij_java_extends_list_wrap = normal
|
||||
ij_java_field_annotation_wrap = off
|
||||
ij_java_finally_on_new_line = true
|
||||
ij_java_for_brace_force = always
|
||||
ij_java_for_statement_new_line_after_left_paren = false
|
||||
ij_java_for_statement_right_paren_on_new_line = false
|
||||
ij_java_for_statement_wrap = off
|
||||
ij_java_generate_final_locals = false
|
||||
ij_java_generate_final_parameters = false
|
||||
ij_java_if_brace_force = never
|
||||
ij_java_imports_layout = *,|,javax.**,java.**,|,$*
|
||||
ij_java_indent_case_from_switch = true
|
||||
ij_java_insert_inner_class_imports = false
|
||||
ij_java_insert_override_annotation = true
|
||||
ij_java_keep_blank_lines_before_right_brace = 10
|
||||
ij_java_keep_blank_lines_between_package_declaration_and_header = 2
|
||||
ij_java_keep_blank_lines_in_code = 10
|
||||
ij_java_keep_blank_lines_in_declarations = 10
|
||||
ij_java_keep_builder_methods_indents = false
|
||||
ij_java_keep_control_statement_in_one_line = true
|
||||
ij_java_keep_first_column_comment = true
|
||||
ij_java_keep_indents_on_empty_lines = true
|
||||
ij_java_keep_line_breaks = true
|
||||
ij_java_keep_multiple_expressions_in_one_line = true
|
||||
ij_java_keep_simple_blocks_in_one_line = false
|
||||
ij_java_keep_simple_classes_in_one_line = true
|
||||
ij_java_keep_simple_lambdas_in_one_line = true
|
||||
ij_java_keep_simple_methods_in_one_line = true
|
||||
ij_java_label_indent_absolute = false
|
||||
ij_java_label_indent_size = 0
|
||||
ij_java_lambda_brace_style = end_of_line
|
||||
ij_java_layout_static_imports_separately = true
|
||||
ij_java_line_comment_add_space = false
|
||||
ij_java_line_comment_add_space_on_reformat = false
|
||||
ij_java_line_comment_at_first_column = false
|
||||
ij_java_method_annotation_wrap = off
|
||||
ij_java_method_brace_style = next_line
|
||||
ij_java_method_call_chain_wrap = normal
|
||||
ij_java_method_parameters_new_line_after_left_paren = true
|
||||
ij_java_method_parameters_right_paren_on_new_line = false
|
||||
ij_java_method_parameters_wrap = normal
|
||||
ij_java_modifier_list_wrap = false
|
||||
ij_java_multi_catch_types_wrap = normal
|
||||
ij_java_names_count_to_use_import_on_demand = 3
|
||||
ij_java_new_line_after_lparen_in_annotation = false
|
||||
ij_java_new_line_after_lparen_in_deconstruction_pattern = true
|
||||
ij_java_new_line_after_lparen_in_record_header = false
|
||||
ij_java_packages_to_use_import_on_demand = java.awt.*,javax.swing.*
|
||||
ij_java_parameter_annotation_wrap = off
|
||||
ij_java_parentheses_expression_new_line_after_left_paren = false
|
||||
ij_java_parentheses_expression_right_paren_on_new_line = false
|
||||
ij_java_place_assignment_sign_on_next_line = false
|
||||
ij_java_prefer_longer_names = true
|
||||
ij_java_prefer_parameters_wrap = false
|
||||
ij_java_record_components_wrap = normal
|
||||
ij_java_repeat_synchronized = true
|
||||
ij_java_replace_instanceof_and_cast = false
|
||||
ij_java_replace_null_check = false
|
||||
ij_java_replace_sum_lambda_with_method_ref = false
|
||||
ij_java_resource_list_new_line_after_left_paren = false
|
||||
ij_java_resource_list_right_paren_on_new_line = false
|
||||
ij_java_resource_list_wrap = on_every_item
|
||||
ij_java_rparen_on_new_line_in_annotation = false
|
||||
ij_java_rparen_on_new_line_in_deconstruction_pattern = true
|
||||
ij_java_rparen_on_new_line_in_record_header = false
|
||||
ij_java_space_after_closing_angle_bracket_in_type_argument = false
|
||||
ij_java_space_after_colon = true
|
||||
ij_java_space_after_comma = true
|
||||
ij_java_space_after_comma_in_type_arguments = true
|
||||
ij_java_space_after_for_semicolon = true
|
||||
ij_java_space_after_quest = true
|
||||
ij_java_space_after_type_cast = true
|
||||
ij_java_space_before_annotation_array_initializer_left_brace = false
|
||||
ij_java_space_before_annotation_parameter_list = false
|
||||
ij_java_space_before_array_initializer_left_brace = false
|
||||
ij_java_space_before_catch_keyword = true
|
||||
ij_java_space_before_catch_left_brace = true
|
||||
ij_java_space_before_catch_parentheses = true
|
||||
ij_java_space_before_class_left_brace = true
|
||||
ij_java_space_before_colon = true
|
||||
ij_java_space_before_colon_in_foreach = true
|
||||
ij_java_space_before_comma = false
|
||||
ij_java_space_before_deconstruction_list = false
|
||||
ij_java_space_before_do_left_brace = true
|
||||
ij_java_space_before_else_keyword = true
|
||||
ij_java_space_before_else_left_brace = true
|
||||
ij_java_space_before_finally_keyword = true
|
||||
ij_java_space_before_finally_left_brace = true
|
||||
ij_java_space_before_for_left_brace = true
|
||||
ij_java_space_before_for_parentheses = true
|
||||
ij_java_space_before_for_semicolon = false
|
||||
ij_java_space_before_if_left_brace = true
|
||||
ij_java_space_before_if_parentheses = true
|
||||
ij_java_space_before_method_call_parentheses = false
|
||||
ij_java_space_before_method_left_brace = true
|
||||
ij_java_space_before_method_parentheses = false
|
||||
ij_java_space_before_opening_angle_bracket_in_type_parameter = false
|
||||
ij_java_space_before_quest = true
|
||||
ij_java_space_before_switch_left_brace = true
|
||||
ij_java_space_before_switch_parentheses = true
|
||||
ij_java_space_before_synchronized_left_brace = false
|
||||
ij_java_space_before_synchronized_parentheses = true
|
||||
ij_java_space_before_try_left_brace = true
|
||||
ij_java_space_before_try_parentheses = true
|
||||
ij_java_space_before_type_parameter_list = false
|
||||
ij_java_space_before_while_keyword = true
|
||||
ij_java_space_before_while_left_brace = true
|
||||
ij_java_space_before_while_parentheses = true
|
||||
ij_java_space_inside_one_line_enum_braces = false
|
||||
ij_java_space_within_empty_array_initializer_braces = true
|
||||
ij_java_space_within_empty_method_call_parentheses = false
|
||||
ij_java_space_within_empty_method_parentheses = false
|
||||
ij_java_spaces_around_additive_operators = true
|
||||
ij_java_spaces_around_annotation_eq = true
|
||||
ij_java_spaces_around_assignment_operators = true
|
||||
ij_java_spaces_around_bitwise_operators = true
|
||||
ij_java_spaces_around_equality_operators = true
|
||||
ij_java_spaces_around_lambda_arrow = true
|
||||
ij_java_spaces_around_logical_operators = true
|
||||
ij_java_spaces_around_method_ref_dbl_colon = false
|
||||
ij_java_spaces_around_multiplicative_operators = true
|
||||
ij_java_spaces_around_relational_operators = true
|
||||
ij_java_spaces_around_shift_operators = true
|
||||
ij_java_spaces_around_type_bounds_in_type_parameters = true
|
||||
ij_java_spaces_around_unary_operator = false
|
||||
ij_java_spaces_within_angle_brackets = false
|
||||
ij_java_spaces_within_annotation_parentheses = false
|
||||
ij_java_spaces_within_array_initializer_braces = false
|
||||
ij_java_spaces_within_braces = true
|
||||
ij_java_spaces_within_brackets = false
|
||||
ij_java_spaces_within_cast_parentheses = false
|
||||
ij_java_spaces_within_catch_parentheses = false
|
||||
ij_java_spaces_within_deconstruction_list = false
|
||||
ij_java_spaces_within_for_parentheses = false
|
||||
ij_java_spaces_within_if_parentheses = false
|
||||
ij_java_spaces_within_method_call_parentheses = false
|
||||
ij_java_spaces_within_method_parentheses = false
|
||||
ij_java_spaces_within_parentheses = false
|
||||
ij_java_spaces_within_record_header = false
|
||||
ij_java_spaces_within_switch_parentheses = false
|
||||
ij_java_spaces_within_synchronized_parentheses = false
|
||||
ij_java_spaces_within_try_parentheses = false
|
||||
ij_java_spaces_within_while_parentheses = false
|
||||
ij_java_special_else_if_treatment = true
|
||||
ij_java_subclass_name_suffix = Impl
|
||||
ij_java_ternary_operation_signs_on_next_line = false
|
||||
ij_java_ternary_operation_wrap = on_every_item
|
||||
ij_java_test_name_suffix = Test
|
||||
ij_java_throws_keyword_wrap = normal
|
||||
ij_java_throws_list_wrap = normal
|
||||
ij_java_use_external_annotations = false
|
||||
ij_java_use_fq_class_names = false
|
||||
ij_java_use_relative_indents = false
|
||||
ij_java_use_single_class_imports = true
|
||||
ij_java_variable_annotation_wrap = off
|
||||
ij_java_visibility = public
|
||||
ij_java_while_brace_force = always
|
||||
ij_java_while_on_new_line = true
|
||||
ij_java_wrap_comments = false
|
||||
ij_java_wrap_first_method_in_call_chain = false
|
||||
ij_java_wrap_long_lines = false
|
||||
|
||||
[*.nbtt]
|
||||
indent_style = tab
|
||||
max_line_length = 150
|
||||
ij_continuation_indent_size = 4
|
||||
ij_nbtt_keep_indents_on_empty_lines = false
|
||||
ij_nbtt_space_after_colon = true
|
||||
ij_nbtt_space_after_comma = true
|
||||
ij_nbtt_space_before_colon = true
|
||||
ij_nbtt_space_before_comma = false
|
||||
ij_nbtt_spaces_within_brackets = false
|
||||
ij_nbtt_spaces_within_parentheses = false
|
||||
|
||||
[*.properties]
|
||||
ij_properties_align_group_field_declarations = false
|
||||
ij_properties_keep_blank_lines = false
|
||||
ij_properties_key_value_delimiter = equals
|
||||
ij_properties_spaces_around_key_value_delimiter = false
|
||||
|
||||
[.editorconfig]
|
||||
ij_editorconfig_align_group_field_declarations = false
|
||||
ij_editorconfig_space_after_colon = false
|
||||
ij_editorconfig_space_after_comma = true
|
||||
ij_editorconfig_space_before_colon = false
|
||||
ij_editorconfig_space_before_comma = false
|
||||
ij_editorconfig_spaces_around_assignment_operators = true
|
||||
|
||||
[{*.ant,*.fxml,*.jhm,*.jnlp,*.jrxml,*.jspx,*.pom,*.rng,*.tagx,*.tld,*.wsdl,*.xml,*.xsd,*.xsl,*.xslt,*.xul}]
|
||||
ij_xml_align_attributes = true
|
||||
ij_xml_align_text = false
|
||||
ij_xml_attribute_wrap = normal
|
||||
ij_xml_block_comment_add_space = false
|
||||
ij_xml_block_comment_at_first_column = true
|
||||
ij_xml_keep_blank_lines = 2
|
||||
ij_xml_keep_indents_on_empty_lines = false
|
||||
ij_xml_keep_line_breaks = true
|
||||
ij_xml_keep_line_breaks_in_text = true
|
||||
ij_xml_keep_whitespaces = false
|
||||
ij_xml_keep_whitespaces_around_cdata = preserve
|
||||
ij_xml_keep_whitespaces_inside_cdata = false
|
||||
ij_xml_line_comment_at_first_column = true
|
||||
ij_xml_space_after_tag_name = false
|
||||
ij_xml_space_around_equals_in_attribute = false
|
||||
ij_xml_space_inside_empty_tag = false
|
||||
ij_xml_text_wrap = normal
|
||||
ij_xml_use_custom_settings = false
|
||||
|
||||
[{*.bash,*.sh,*.zsh}]
|
||||
indent_size = 4
|
||||
tab_width = 4
|
||||
ij_shell_binary_ops_start_line = false
|
||||
ij_shell_keep_column_alignment_padding = false
|
||||
ij_shell_minify_program = false
|
||||
ij_shell_redirect_followed_by_space = false
|
||||
ij_shell_switch_cases_indented = false
|
||||
ij_shell_use_unix_line_separator = true
|
||||
|
||||
[{*.comp,*.frag,*.fsh,*.geom,*.glsl,*.gsh,*.tesc,*.tese,*.vert,*.vsh}]
|
||||
ij_glsl_space_after_colon = true
|
||||
ij_glsl_space_after_comma = true
|
||||
ij_glsl_space_after_for_semicolon = true
|
||||
ij_glsl_space_after_quest = true
|
||||
ij_glsl_space_before_colon = false
|
||||
ij_glsl_space_before_comma = false
|
||||
ij_glsl_space_before_for_semicolon = false
|
||||
ij_glsl_space_before_quest = true
|
||||
ij_glsl_spaces_around_additive_operators = true
|
||||
ij_glsl_spaces_around_assignment_operators = true
|
||||
ij_glsl_spaces_around_bitwise_operators = true
|
||||
ij_glsl_spaces_around_equality_operators = true
|
||||
ij_glsl_spaces_around_logical_operators = true
|
||||
ij_glsl_spaces_around_multiplicative_operators = true
|
||||
ij_glsl_spaces_around_relational_operators = true
|
||||
ij_glsl_spaces_around_shift_operators = true
|
||||
ij_glsl_spaces_within_brackets = false
|
||||
ij_glsl_spaces_within_parentheses = false
|
||||
|
||||
[{*.gant,*.groovy,*.gy}]
|
||||
ij_groovy_align_group_field_declarations = false
|
||||
ij_groovy_align_multiline_array_initializer_expression = false
|
||||
ij_groovy_align_multiline_assignment = false
|
||||
ij_groovy_align_multiline_binary_operation = false
|
||||
ij_groovy_align_multiline_chained_methods = false
|
||||
ij_groovy_align_multiline_extends_list = false
|
||||
ij_groovy_align_multiline_for = true
|
||||
ij_groovy_align_multiline_list_or_map = true
|
||||
ij_groovy_align_multiline_method_parentheses = false
|
||||
ij_groovy_align_multiline_parameters = true
|
||||
ij_groovy_align_multiline_parameters_in_calls = false
|
||||
ij_groovy_align_multiline_resources = true
|
||||
ij_groovy_align_multiline_ternary_operation = false
|
||||
ij_groovy_align_multiline_throws_list = false
|
||||
ij_groovy_align_named_args_in_map = true
|
||||
ij_groovy_align_throws_keyword = false
|
||||
ij_groovy_array_initializer_new_line_after_left_brace = false
|
||||
ij_groovy_array_initializer_right_brace_on_new_line = false
|
||||
ij_groovy_array_initializer_wrap = off
|
||||
ij_groovy_assert_statement_wrap = off
|
||||
ij_groovy_assignment_wrap = off
|
||||
ij_groovy_binary_operation_wrap = off
|
||||
ij_groovy_blank_lines_after_class_header = 0
|
||||
ij_groovy_blank_lines_after_imports = 1
|
||||
ij_groovy_blank_lines_after_package = 1
|
||||
ij_groovy_blank_lines_around_class = 1
|
||||
ij_groovy_blank_lines_around_field = 0
|
||||
ij_groovy_blank_lines_around_field_in_interface = 0
|
||||
ij_groovy_blank_lines_around_method = 1
|
||||
ij_groovy_blank_lines_around_method_in_interface = 1
|
||||
ij_groovy_blank_lines_before_imports = 1
|
||||
ij_groovy_blank_lines_before_method_body = 0
|
||||
ij_groovy_blank_lines_before_package = 0
|
||||
ij_groovy_block_brace_style = end_of_line
|
||||
ij_groovy_block_comment_add_space = false
|
||||
ij_groovy_block_comment_at_first_column = true
|
||||
ij_groovy_call_parameters_new_line_after_left_paren = false
|
||||
ij_groovy_call_parameters_right_paren_on_new_line = false
|
||||
ij_groovy_call_parameters_wrap = off
|
||||
ij_groovy_catch_on_new_line = false
|
||||
ij_groovy_class_annotation_wrap = split_into_lines
|
||||
ij_groovy_class_brace_style = end_of_line
|
||||
ij_groovy_class_count_to_use_import_on_demand = 5
|
||||
ij_groovy_do_while_brace_force = never
|
||||
ij_groovy_else_on_new_line = false
|
||||
ij_groovy_enable_groovydoc_formatting = true
|
||||
ij_groovy_enum_constants_wrap = off
|
||||
ij_groovy_extends_keyword_wrap = off
|
||||
ij_groovy_extends_list_wrap = off
|
||||
ij_groovy_field_annotation_wrap = split_into_lines
|
||||
ij_groovy_finally_on_new_line = false
|
||||
ij_groovy_for_brace_force = never
|
||||
ij_groovy_for_statement_new_line_after_left_paren = false
|
||||
ij_groovy_for_statement_right_paren_on_new_line = false
|
||||
ij_groovy_for_statement_wrap = off
|
||||
ij_groovy_ginq_general_clause_wrap_policy = 2
|
||||
ij_groovy_ginq_having_wrap_policy = 1
|
||||
ij_groovy_ginq_indent_having_clause = true
|
||||
ij_groovy_ginq_indent_on_clause = true
|
||||
ij_groovy_ginq_on_wrap_policy = 1
|
||||
ij_groovy_ginq_space_after_keyword = true
|
||||
ij_groovy_if_brace_force = never
|
||||
ij_groovy_import_annotation_wrap = 2
|
||||
ij_groovy_imports_layout = *,|,javax.**,java.**,|,$*
|
||||
ij_groovy_indent_case_from_switch = true
|
||||
ij_groovy_indent_label_blocks = true
|
||||
ij_groovy_insert_inner_class_imports = false
|
||||
ij_groovy_keep_blank_lines_before_right_brace = 2
|
||||
ij_groovy_keep_blank_lines_in_code = 2
|
||||
ij_groovy_keep_blank_lines_in_declarations = 2
|
||||
ij_groovy_keep_control_statement_in_one_line = true
|
||||
ij_groovy_keep_first_column_comment = true
|
||||
ij_groovy_keep_indents_on_empty_lines = false
|
||||
ij_groovy_keep_line_breaks = true
|
||||
ij_groovy_keep_multiple_expressions_in_one_line = false
|
||||
ij_groovy_keep_simple_blocks_in_one_line = false
|
||||
ij_groovy_keep_simple_classes_in_one_line = true
|
||||
ij_groovy_keep_simple_lambdas_in_one_line = true
|
||||
ij_groovy_keep_simple_methods_in_one_line = true
|
||||
ij_groovy_label_indent_absolute = false
|
||||
ij_groovy_label_indent_size = 0
|
||||
ij_groovy_lambda_brace_style = end_of_line
|
||||
ij_groovy_layout_static_imports_separately = true
|
||||
ij_groovy_line_comment_add_space = false
|
||||
ij_groovy_line_comment_add_space_on_reformat = false
|
||||
ij_groovy_line_comment_at_first_column = true
|
||||
ij_groovy_method_annotation_wrap = split_into_lines
|
||||
ij_groovy_method_brace_style = end_of_line
|
||||
ij_groovy_method_call_chain_wrap = off
|
||||
ij_groovy_method_parameters_new_line_after_left_paren = false
|
||||
ij_groovy_method_parameters_right_paren_on_new_line = false
|
||||
ij_groovy_method_parameters_wrap = off
|
||||
ij_groovy_modifier_list_wrap = false
|
||||
ij_groovy_names_count_to_use_import_on_demand = 3
|
||||
ij_groovy_packages_to_use_import_on_demand = java.awt.*,javax.swing.*
|
||||
ij_groovy_parameter_annotation_wrap = off
|
||||
ij_groovy_parentheses_expression_new_line_after_left_paren = false
|
||||
ij_groovy_parentheses_expression_right_paren_on_new_line = false
|
||||
ij_groovy_prefer_parameters_wrap = false
|
||||
ij_groovy_resource_list_new_line_after_left_paren = false
|
||||
ij_groovy_resource_list_right_paren_on_new_line = false
|
||||
ij_groovy_resource_list_wrap = off
|
||||
ij_groovy_space_after_assert_separator = true
|
||||
ij_groovy_space_after_colon = true
|
||||
ij_groovy_space_after_comma = true
|
||||
ij_groovy_space_after_comma_in_type_arguments = true
|
||||
ij_groovy_space_after_for_semicolon = true
|
||||
ij_groovy_space_after_quest = true
|
||||
ij_groovy_space_after_type_cast = true
|
||||
ij_groovy_space_before_annotation_parameter_list = false
|
||||
ij_groovy_space_before_array_initializer_left_brace = false
|
||||
ij_groovy_space_before_assert_separator = false
|
||||
ij_groovy_space_before_catch_keyword = true
|
||||
ij_groovy_space_before_catch_left_brace = true
|
||||
ij_groovy_space_before_catch_parentheses = true
|
||||
ij_groovy_space_before_class_left_brace = true
|
||||
ij_groovy_space_before_closure_left_brace = true
|
||||
ij_groovy_space_before_colon = true
|
||||
ij_groovy_space_before_comma = false
|
||||
ij_groovy_space_before_do_left_brace = true
|
||||
ij_groovy_space_before_else_keyword = true
|
||||
ij_groovy_space_before_else_left_brace = true
|
||||
ij_groovy_space_before_finally_keyword = true
|
||||
ij_groovy_space_before_finally_left_brace = true
|
||||
ij_groovy_space_before_for_left_brace = true
|
||||
ij_groovy_space_before_for_parentheses = true
|
||||
ij_groovy_space_before_for_semicolon = false
|
||||
ij_groovy_space_before_if_left_brace = true
|
||||
ij_groovy_space_before_if_parentheses = true
|
||||
ij_groovy_space_before_method_call_parentheses = false
|
||||
ij_groovy_space_before_method_left_brace = true
|
||||
ij_groovy_space_before_method_parentheses = false
|
||||
ij_groovy_space_before_quest = true
|
||||
ij_groovy_space_before_record_parentheses = false
|
||||
ij_groovy_space_before_switch_left_brace = true
|
||||
ij_groovy_space_before_switch_parentheses = true
|
||||
ij_groovy_space_before_synchronized_left_brace = true
|
||||
ij_groovy_space_before_synchronized_parentheses = true
|
||||
ij_groovy_space_before_try_left_brace = true
|
||||
ij_groovy_space_before_try_parentheses = true
|
||||
ij_groovy_space_before_while_keyword = true
|
||||
ij_groovy_space_before_while_left_brace = true
|
||||
ij_groovy_space_before_while_parentheses = true
|
||||
ij_groovy_space_in_named_argument = true
|
||||
ij_groovy_space_in_named_argument_before_colon = false
|
||||
ij_groovy_space_within_empty_array_initializer_braces = false
|
||||
ij_groovy_space_within_empty_method_call_parentheses = false
|
||||
ij_groovy_spaces_around_additive_operators = true
|
||||
ij_groovy_spaces_around_assignment_operators = true
|
||||
ij_groovy_spaces_around_bitwise_operators = true
|
||||
ij_groovy_spaces_around_equality_operators = true
|
||||
ij_groovy_spaces_around_lambda_arrow = true
|
||||
ij_groovy_spaces_around_logical_operators = true
|
||||
ij_groovy_spaces_around_multiplicative_operators = true
|
||||
ij_groovy_spaces_around_regex_operators = true
|
||||
ij_groovy_spaces_around_relational_operators = true
|
||||
ij_groovy_spaces_around_shift_operators = true
|
||||
ij_groovy_spaces_within_annotation_parentheses = false
|
||||
ij_groovy_spaces_within_array_initializer_braces = false
|
||||
ij_groovy_spaces_within_braces = true
|
||||
ij_groovy_spaces_within_brackets = false
|
||||
ij_groovy_spaces_within_cast_parentheses = false
|
||||
ij_groovy_spaces_within_catch_parentheses = false
|
||||
ij_groovy_spaces_within_for_parentheses = false
|
||||
ij_groovy_spaces_within_gstring_injection_braces = false
|
||||
ij_groovy_spaces_within_if_parentheses = false
|
||||
ij_groovy_spaces_within_list_or_map = false
|
||||
ij_groovy_spaces_within_method_call_parentheses = false
|
||||
ij_groovy_spaces_within_method_parentheses = false
|
||||
ij_groovy_spaces_within_parentheses = false
|
||||
ij_groovy_spaces_within_switch_parentheses = false
|
||||
ij_groovy_spaces_within_synchronized_parentheses = false
|
||||
ij_groovy_spaces_within_try_parentheses = false
|
||||
ij_groovy_spaces_within_tuple_expression = false
|
||||
ij_groovy_spaces_within_while_parentheses = false
|
||||
ij_groovy_special_else_if_treatment = true
|
||||
ij_groovy_ternary_operation_wrap = off
|
||||
ij_groovy_throws_keyword_wrap = off
|
||||
ij_groovy_throws_list_wrap = off
|
||||
ij_groovy_use_flying_geese_braces = false
|
||||
ij_groovy_use_fq_class_names = false
|
||||
ij_groovy_use_fq_class_names_in_javadoc = true
|
||||
ij_groovy_use_relative_indents = false
|
||||
ij_groovy_use_single_class_imports = true
|
||||
ij_groovy_variable_annotation_wrap = off
|
||||
ij_groovy_while_brace_force = never
|
||||
ij_groovy_while_on_new_line = false
|
||||
ij_groovy_wrap_chain_calls_after_dot = false
|
||||
ij_groovy_wrap_long_lines = false
|
||||
|
||||
[{*.har,*.json,*.png.mcmeta,mcmod.info,pack.mcmeta}]
|
||||
indent_size = 4
|
||||
ij_json_array_wrapping = split_into_lines
|
||||
ij_json_keep_blank_lines_in_code = 0
|
||||
ij_json_keep_indents_on_empty_lines = false
|
||||
ij_json_keep_line_breaks = true
|
||||
ij_json_keep_trailing_comma = false
|
||||
ij_json_object_wrapping = split_into_lines
|
||||
ij_json_property_alignment = do_not_align
|
||||
ij_json_space_after_colon = true
|
||||
ij_json_space_after_comma = true
|
||||
ij_json_space_before_colon = false
|
||||
ij_json_space_before_comma = false
|
||||
ij_json_spaces_within_braces = false
|
||||
ij_json_spaces_within_brackets = false
|
||||
ij_json_wrap_long_lines = false
|
||||
|
||||
[{*.htm,*.html,*.sht,*.shtm,*.shtml}]
|
||||
ij_html_add_new_line_before_tags = body,div,p,form,h1,h2,h3
|
||||
ij_html_align_attributes = true
|
||||
ij_html_align_text = false
|
||||
ij_html_attribute_wrap = normal
|
||||
ij_html_block_comment_add_space = false
|
||||
ij_html_block_comment_at_first_column = true
|
||||
ij_html_do_not_align_children_of_min_lines = 0
|
||||
ij_html_do_not_break_if_inline_tags = title,h1,h2,h3,h4,h5,h6,p
|
||||
ij_html_do_not_indent_children_of_tags = html,body,thead,tbody,tfoot
|
||||
ij_html_enforce_quotes = false
|
||||
ij_html_inline_tags = a,abbr,acronym,b,basefont,bdo,big,br,cite,cite,code,dfn,em,font,i,img,input,kbd,label,q,s,samp,select,small,span,strike,strong,sub,sup,textarea,tt,u,var
|
||||
ij_html_keep_blank_lines = 2
|
||||
ij_html_keep_indents_on_empty_lines = false
|
||||
ij_html_keep_line_breaks = true
|
||||
ij_html_keep_line_breaks_in_text = true
|
||||
ij_html_keep_whitespaces = false
|
||||
ij_html_keep_whitespaces_inside = span,pre,textarea
|
||||
ij_html_line_comment_at_first_column = true
|
||||
ij_html_new_line_after_last_attribute = never
|
||||
ij_html_new_line_before_first_attribute = never
|
||||
ij_html_quote_style = double
|
||||
ij_html_remove_new_line_before_tags = br
|
||||
ij_html_space_after_tag_name = false
|
||||
ij_html_space_around_equality_in_attribute = false
|
||||
ij_html_space_inside_empty_tag = false
|
||||
ij_html_text_wrap = normal
|
||||
|
||||
[{*.kt,*.kts}]
|
||||
ij_kotlin_align_in_columns_case_branch = false
|
||||
ij_kotlin_align_multiline_binary_operation = false
|
||||
ij_kotlin_align_multiline_extends_list = false
|
||||
ij_kotlin_align_multiline_method_parentheses = false
|
||||
ij_kotlin_align_multiline_parameters = true
|
||||
ij_kotlin_align_multiline_parameters_in_calls = false
|
||||
ij_kotlin_allow_trailing_comma = false
|
||||
ij_kotlin_allow_trailing_comma_on_call_site = false
|
||||
ij_kotlin_assignment_wrap = off
|
||||
ij_kotlin_blank_lines_after_class_header = 0
|
||||
ij_kotlin_blank_lines_around_block_when_branches = 0
|
||||
ij_kotlin_blank_lines_before_declaration_with_comment_or_annotation_on_separate_line = 1
|
||||
ij_kotlin_block_comment_add_space = false
|
||||
ij_kotlin_block_comment_at_first_column = true
|
||||
ij_kotlin_call_parameters_new_line_after_left_paren = false
|
||||
ij_kotlin_call_parameters_right_paren_on_new_line = false
|
||||
ij_kotlin_call_parameters_wrap = off
|
||||
ij_kotlin_catch_on_new_line = false
|
||||
ij_kotlin_class_annotation_wrap = split_into_lines
|
||||
ij_kotlin_continuation_indent_for_chained_calls = true
|
||||
ij_kotlin_continuation_indent_for_expression_bodies = true
|
||||
ij_kotlin_continuation_indent_in_argument_lists = true
|
||||
ij_kotlin_continuation_indent_in_elvis = true
|
||||
ij_kotlin_continuation_indent_in_if_conditions = true
|
||||
ij_kotlin_continuation_indent_in_parameter_lists = true
|
||||
ij_kotlin_continuation_indent_in_supertype_lists = true
|
||||
ij_kotlin_else_on_new_line = false
|
||||
ij_kotlin_enum_constants_wrap = off
|
||||
ij_kotlin_extends_list_wrap = off
|
||||
ij_kotlin_field_annotation_wrap = split_into_lines
|
||||
ij_kotlin_finally_on_new_line = false
|
||||
ij_kotlin_if_rparen_on_new_line = false
|
||||
ij_kotlin_import_nested_classes = false
|
||||
ij_kotlin_imports_layout = *,java.**,javax.**,kotlin.**,^
|
||||
ij_kotlin_insert_whitespaces_in_simple_one_line_method = true
|
||||
ij_kotlin_keep_blank_lines_before_right_brace = 2
|
||||
ij_kotlin_keep_blank_lines_in_code = 2
|
||||
ij_kotlin_keep_blank_lines_in_declarations = 2
|
||||
ij_kotlin_keep_first_column_comment = true
|
||||
ij_kotlin_keep_indents_on_empty_lines = false
|
||||
ij_kotlin_keep_line_breaks = true
|
||||
ij_kotlin_lbrace_on_next_line = false
|
||||
ij_kotlin_line_break_after_multiline_when_entry = true
|
||||
ij_kotlin_line_comment_add_space = false
|
||||
ij_kotlin_line_comment_add_space_on_reformat = false
|
||||
ij_kotlin_line_comment_at_first_column = true
|
||||
ij_kotlin_method_annotation_wrap = split_into_lines
|
||||
ij_kotlin_method_call_chain_wrap = off
|
||||
ij_kotlin_method_parameters_new_line_after_left_paren = false
|
||||
ij_kotlin_method_parameters_right_paren_on_new_line = false
|
||||
ij_kotlin_method_parameters_wrap = off
|
||||
ij_kotlin_name_count_to_use_star_import = 5
|
||||
ij_kotlin_name_count_to_use_star_import_for_members = 3
|
||||
ij_kotlin_packages_to_use_import_on_demand = java.util.*,kotlinx.android.synthetic.**,io.ktor.**
|
||||
ij_kotlin_parameter_annotation_wrap = off
|
||||
ij_kotlin_space_after_comma = true
|
||||
ij_kotlin_space_after_extend_colon = true
|
||||
ij_kotlin_space_after_type_colon = true
|
||||
ij_kotlin_space_before_catch_parentheses = true
|
||||
ij_kotlin_space_before_comma = false
|
||||
ij_kotlin_space_before_extend_colon = true
|
||||
ij_kotlin_space_before_for_parentheses = true
|
||||
ij_kotlin_space_before_if_parentheses = true
|
||||
ij_kotlin_space_before_lambda_arrow = true
|
||||
ij_kotlin_space_before_type_colon = false
|
||||
ij_kotlin_space_before_when_parentheses = true
|
||||
ij_kotlin_space_before_while_parentheses = true
|
||||
ij_kotlin_spaces_around_additive_operators = true
|
||||
ij_kotlin_spaces_around_assignment_operators = true
|
||||
ij_kotlin_spaces_around_equality_operators = true
|
||||
ij_kotlin_spaces_around_function_type_arrow = true
|
||||
ij_kotlin_spaces_around_logical_operators = true
|
||||
ij_kotlin_spaces_around_multiplicative_operators = true
|
||||
ij_kotlin_spaces_around_range = false
|
||||
ij_kotlin_spaces_around_relational_operators = true
|
||||
ij_kotlin_spaces_around_unary_operator = false
|
||||
ij_kotlin_spaces_around_when_arrow = true
|
||||
ij_kotlin_variable_annotation_wrap = off
|
||||
ij_kotlin_while_on_new_line = false
|
||||
ij_kotlin_wrap_elvis_expressions = 1
|
||||
ij_kotlin_wrap_expression_body_functions = 0
|
||||
ij_kotlin_wrap_first_method_in_call_chain = false
|
||||
|
||||
[{*.markdown,*.md}]
|
||||
ij_markdown_force_one_space_after_blockquote_symbol = true
|
||||
ij_markdown_force_one_space_after_header_symbol = true
|
||||
ij_markdown_force_one_space_after_list_bullet = true
|
||||
ij_markdown_force_one_space_between_words = true
|
||||
ij_markdown_format_tables = true
|
||||
ij_markdown_insert_quote_arrows_on_wrap = true
|
||||
ij_markdown_keep_indents_on_empty_lines = false
|
||||
ij_markdown_keep_line_breaks_inside_text_blocks = true
|
||||
ij_markdown_max_lines_around_block_elements = 1
|
||||
ij_markdown_max_lines_around_header = 1
|
||||
ij_markdown_max_lines_between_paragraphs = 1
|
||||
ij_markdown_min_lines_around_block_elements = 1
|
||||
ij_markdown_min_lines_around_header = 1
|
||||
ij_markdown_min_lines_between_paragraphs = 1
|
||||
ij_markdown_wrap_text_if_long = true
|
||||
ij_markdown_wrap_text_inside_blockquotes = true
|
||||
|
||||
[{*.toml,Cargo.lock,Cargo.toml.orig,Gopkg.lock,Pipfile,poetry.lock}]
|
||||
ij_toml_keep_indents_on_empty_lines = false
|
||||
|
||||
[{*.yaml,*.yml}]
|
||||
indent_size = 4
|
||||
ij_yaml_align_values_properties = do_not_align
|
||||
ij_yaml_autoinsert_sequence_marker = true
|
||||
ij_yaml_block_mapping_on_new_line = false
|
||||
ij_yaml_indent_sequence_value = true
|
||||
ij_yaml_keep_indents_on_empty_lines = false
|
||||
ij_yaml_keep_line_breaks = true
|
||||
ij_yaml_sequence_on_new_line = false
|
||||
ij_yaml_space_before_colon = false
|
||||
ij_yaml_spaces_within_braces = true
|
||||
ij_yaml_spaces_within_brackets = true
|
||||
+12
@@ -5,6 +5,7 @@ run/
|
||||
out/
|
||||
*.iml
|
||||
.gradle/
|
||||
.gradle-cache/
|
||||
output/
|
||||
bin/
|
||||
libs/
|
||||
@@ -22,9 +23,20 @@ hs_err_pid*
|
||||
|
||||
**/src/generated/
|
||||
Merged/
|
||||
# Folder created by the buildAll scripts
|
||||
buildAllJars/
|
||||
|
||||
# file from notepad++
|
||||
*.bak
|
||||
|
||||
# file genearated via MC version switching using preprocessor
|
||||
build.properties
|
||||
|
||||
# Sqlite databases
|
||||
*.sqlite
|
||||
*.sqlite-journal
|
||||
*.sqlite-shm
|
||||
*.sqlite-wal
|
||||
|
||||
# Don't add access transformers to git as they're dynamically generated
|
||||
accesstransformer.cfg
|
||||
|
||||
+84
-226
@@ -1,41 +1,22 @@
|
||||
# use Eclipse's JDK
|
||||
image: gradle:eclipse-temurin
|
||||
# The ci should always use an unix/unix-like OS to work
|
||||
|
||||
# The ci should always use a unix(-like) OS to work
|
||||
image: eclipse-temurin:21
|
||||
|
||||
# all stages need to be defined here
|
||||
# TODO: Make stages depend on what is in versionProperties
|
||||
stages:
|
||||
# TODO: Make stages depending on what is in versionProperties
|
||||
- build_1_18_2
|
||||
- build
|
||||
- api
|
||||
- pages
|
||||
|
||||
variables:
|
||||
# Pull core when building
|
||||
GIT_SUBMODULE_STRATEGY: recursive
|
||||
# Pull core when building
|
||||
GIT_SUBMODULE_STRATEGY: recursive
|
||||
|
||||
|
||||
# 1.18.2 build
|
||||
build_1_18_2:
|
||||
stage: build_1_18_2
|
||||
script:
|
||||
# this both runs the unit tests and assembles the code
|
||||
- ./gradlew build -PmcVer="1.18.2" --gradle-user-home cache/;
|
||||
image: eclipse-temurin:17
|
||||
artifacts:
|
||||
name: "NightlyBuild_1_18_2-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
|
||||
paths:
|
||||
- fabric/build/libs/*.jar
|
||||
- forge/build/libs/*.jar
|
||||
- quilt/build/libs/*.jar
|
||||
exclude:
|
||||
# TODO: There is a lot of duplicate stuff here, fix it later
|
||||
- fabric/build/libs/*-all.jar
|
||||
- fabric/build/libs/*-sources.jar
|
||||
- forge/build/libs/*-all.jar
|
||||
- forge/build/libs/*-sources.jar
|
||||
- quilt/build/libs/*-all.jar
|
||||
- quilt/build/libs/*-sources.jar
|
||||
expire_in: 1 day
|
||||
when: always
|
||||
# These can be extended so code is a bit less duplicated
|
||||
.build_java:
|
||||
#image: eclipse-temurin:17
|
||||
cache:
|
||||
key: "gradleCache"
|
||||
policy: pull-push
|
||||
@@ -45,203 +26,80 @@ build_1_18_2:
|
||||
allow_failure: true
|
||||
|
||||
|
||||
build:
|
||||
stage: build
|
||||
parallel:
|
||||
matrix:
|
||||
- MC_VER: ["1.16.5", "1.17.1", "1.18.2", "1.19.2", "1.19.4", "1.20.1", "1.20.2", "1.20.4", "1.20.6", "1.21"]
|
||||
script:
|
||||
# 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 build -PmcVer="${MC_VER}" -PinfoGitCommit="${CI_COMMIT_SHA}" -PinfoGitBranch="${CI_COMMIT_BRANCH}" -PinfoBuildSource="GitLab CI (${CI_PIPELINE_ID})" --gradle-user-home cache/;
|
||||
- ./gradlew mergeJars -PmcVer="${MC_VER}" -PinfoGitCommit="${CI_COMMIT_SHA}" -PinfoGitBranch="${CI_COMMIT_BRANCH}" -PinfoBuildSource="GitLab CI (${CI_PIPELINE_ID})" --gradle-user-home cache/;
|
||||
artifacts:
|
||||
name: "NightlyBuild_${MC_VER}-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
|
||||
paths:
|
||||
- Merged/*.jar
|
||||
- quilt/build/libs/*.jar
|
||||
- fabric/build/libs/*.jar
|
||||
- forge/build/libs/*.jar
|
||||
- neoforge/build/libs/*.jar
|
||||
exclude:
|
||||
# TODO: There is a lot of duplicate stuff here, try to maybe make it smaller
|
||||
- fabric/build/libs/*-all.jar
|
||||
- fabric/build/libs/*-dev.jar
|
||||
- fabric/build/libs/*-sources.jar
|
||||
- quilt/build/libs/*-all.jar
|
||||
- quilt/build/libs/*-dev.jar
|
||||
- quilt/build/libs/*-sources.jar
|
||||
- forge/build/libs/*-all.jar
|
||||
- forge/build/libs/*-dev.jar
|
||||
- forge/build/libs/*-sources.jar
|
||||
- neoforge/build/libs/*-all.jar
|
||||
- neoforge/build/libs/*-dev.jar
|
||||
- neoforge/build/libs/*-sources.jar
|
||||
expire_in: 14 days
|
||||
when: always
|
||||
extends: .build_java
|
||||
|
||||
|
||||
api:
|
||||
stage: api
|
||||
needs: []
|
||||
script:
|
||||
# this should only run for the API
|
||||
- ./gradlew api:clean --gradle-user-home cache/;
|
||||
# this also runs unit tests
|
||||
- ./gradlew api:build --gradle-user-home cache/;
|
||||
- ./gradlew api:addSourcesToCompiledJar --gradle-user-home cache/;
|
||||
artifacts:
|
||||
name: "Api_NightlyBuild-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
|
||||
paths:
|
||||
- coreSubProjects/api/build/libs/merged/*.jar
|
||||
# can be uncommented if we don't want a jar with the source code
|
||||
# - coreSubProjects/api/build/libs/*.jar
|
||||
exclude:
|
||||
- coreSubProjects/api/build/libs/merged/*-all.jar
|
||||
- coreSubProjects/api/build/libs/merged/*-sources.jar
|
||||
expire_in: 1 day
|
||||
when: always
|
||||
extends: .build_java
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# ============================== Previos CI for future reference ============================== #
|
||||
## all stages need to be defined here
|
||||
# # Don't build the standalone jar yet because it isn't done yet
|
||||
# # - build_standalone
|
||||
#stages:
|
||||
# - build_19
|
||||
# - build_18_2
|
||||
# - build_18_1
|
||||
# - build_17_1
|
||||
# - build_16_5
|
||||
#
|
||||
#variables:
|
||||
# # Pull core when building
|
||||
# GIT_SUBMODULE_STRATEGY: recursive
|
||||
#
|
||||
#
|
||||
#before_script:
|
||||
# - echo $CI_JOB_ID
|
||||
# # Writing GE_JOB_ID variable to environment file, will need the value in the next stage.
|
||||
# - echo GE_JOB_ID=$CI_JOB_ID >> generate_jars.env
|
||||
#
|
||||
#
|
||||
## The standalone build
|
||||
##build_standalone:
|
||||
## stage: build_standalone
|
||||
## script:
|
||||
## # make sure any previously merged jars are removed before running this job.
|
||||
## # note: if the merged folder doesn't exist "rm -R Merged" will throw an error, which can be ignored
|
||||
## # the "|| true" makes that step always succeed.
|
||||
## - ./gradlew core:build --gradle-user-home cache/;
|
||||
##
|
||||
## # Copy the file with the shortest name to the root DistantHorizons.jar so it can be sent off
|
||||
## - cp $(find core/build/libs/ | awk 'function base(f){sub(".*/", "", f); return f;} {print length(base($0)), $0}'| sort -n | head -2 | grep -P "[0-9][0-9] core/build/libs/*" | #sed -r "s/([0-9][0-9] )//g") DistantHorizons.jar
|
||||
## # build using Java 16
|
||||
## image: eclipse-temurin:16
|
||||
## artifacts:
|
||||
## name: "NightlyBuild_standalone-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
|
||||
## paths:
|
||||
## # Get the standalone jar
|
||||
## - DistantHorizons.jar
|
||||
## expire_in: 1 day
|
||||
## # even if one build fails, upload the successful jars
|
||||
## when: always
|
||||
## cache:
|
||||
## key: "gradleCache"
|
||||
## policy: pull-push
|
||||
## paths:
|
||||
## - .gradle
|
||||
## - cache/
|
||||
## allow_failure: true
|
||||
#
|
||||
#
|
||||
## 1.16.5 build
|
||||
#build_16_5:
|
||||
# stage: build_16_5
|
||||
# script:
|
||||
# # make sure any previously merged jars are removed before running this job.
|
||||
# # note: if the merged folder doesn't exist "rm -R Merged" will throw an error, which can be ignored
|
||||
# # the "|| true" makes that step always succeed.
|
||||
# - ./gradlew test --gradle-user-home cache/;
|
||||
# - ./gradlew build -PmcVer="1.16.5" --gradle-user-home cache/;
|
||||
# # build using Java 16
|
||||
# image: eclipse-temurin:16
|
||||
# artifacts:
|
||||
# name: "Merged_NightlyBuild_1_16_5-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
|
||||
# paths:
|
||||
# # relative to the root directory
|
||||
# - Merged
|
||||
# expire_in: 1 day
|
||||
# # even if one build fails, upload the successful jars
|
||||
# when: always
|
||||
# cache:
|
||||
# key: "gradleCache"
|
||||
# policy: pull-push
|
||||
# paths:
|
||||
# - .gradle
|
||||
# - cache/
|
||||
# allow_failure: true
|
||||
#
|
||||
## 1.17.1 build
|
||||
#build_17_1:
|
||||
# stage: build_17_1
|
||||
# script:
|
||||
# - ./gradlew test --gradle-user-home cache/;
|
||||
# - ./gradlew build -PmcVer="1.17.1" --gradle-user-home cache/;
|
||||
# image: eclipse-temurin:16
|
||||
# artifacts:
|
||||
# name: "Merged_NightlyBuild_1_17_1-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
|
||||
# paths:
|
||||
# - Merged
|
||||
# expire_in: 1 day
|
||||
# when: always
|
||||
# cache:
|
||||
# key: "gradleCache"
|
||||
# policy: pull-push
|
||||
# paths:
|
||||
# - .gradle
|
||||
# - cache/
|
||||
# allow_failure: true
|
||||
#
|
||||
## 1.18.1 build
|
||||
#build_18_1:
|
||||
# stage: build_18_1
|
||||
# script:
|
||||
# - ./gradlew test --gradle-user-home cache/;
|
||||
# - ./gradlew build -PmcVer="1.18.1" --gradle-user-home cache/;
|
||||
# # build using Java 17
|
||||
# image: eclipse-temurin:17
|
||||
# artifacts:
|
||||
# name: "Merged_NightlyBuild_1_18_1-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
|
||||
# paths:
|
||||
# - Merged
|
||||
# expire_in: 1 day
|
||||
# when: always
|
||||
# cache:
|
||||
# key: "gradleCache"
|
||||
# policy: pull-push
|
||||
# paths:
|
||||
# - .gradle
|
||||
# - cache/
|
||||
# allow_failure: true
|
||||
#
|
||||
## 1.18.2 build
|
||||
#build_18_2:
|
||||
# stage: build_18_2
|
||||
# script:
|
||||
# - ./gradlew test --gradle-user-home cache/;
|
||||
# - ./gradlew build -PmcVer="1.18.2" --gradle-user-home cache/;
|
||||
# image: eclipse-temurin:17
|
||||
# artifacts:
|
||||
# name: "Merged_NightlyBuild_1_18_2-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
|
||||
# paths:
|
||||
# - Merged
|
||||
# expire_in: 1 day
|
||||
# when: always
|
||||
# cache:
|
||||
# key: "gradleCache"
|
||||
# policy: pull-push
|
||||
# paths:
|
||||
# - .gradle
|
||||
# - cache/
|
||||
# allow_failure: true
|
||||
#
|
||||
## 1.19 build
|
||||
#build_19:
|
||||
# stage: build_19
|
||||
# script:
|
||||
# - ./gradlew test --gradle-user-home cache/;
|
||||
# - ./gradlew build -PmcVer="1.19" --gradle-user-home cache/;
|
||||
# image: eclipse-temurin:17
|
||||
# artifacts:
|
||||
# name: "Merged_NightlyBuild_1_19-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
|
||||
# paths:
|
||||
# - Merged
|
||||
# expire_in: 1 day
|
||||
# when: always
|
||||
# cache:
|
||||
# key: "gradleCache"
|
||||
# policy: pull-push
|
||||
# paths:
|
||||
# - .gradle
|
||||
# - cache/
|
||||
# allow_failure: true
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# unused deployment stage
|
||||
#deploy:
|
||||
# stage: deploy
|
||||
# image: registry.gitlab.com/gitlab-org/release-cli:latest
|
||||
# script:
|
||||
# - echo 'running release_job'
|
||||
# - echo 'Previous Job ID is printed below'
|
||||
# - echo $GE_JOB_ID
|
||||
# # Specifying that this job requires artifacts from the previous job to succeed
|
||||
# needs:
|
||||
# - job: build
|
||||
# artifacts: true
|
||||
# release:
|
||||
# name: 'Unstable Jars for Latest Commit' #: $CI_COMMIT_SHORT_SHA'
|
||||
# description: 'Created automatically using the release-cli.'
|
||||
# # tag_name is a mendatory field and can not be an empty string
|
||||
# tag_name: 'Unstable-$CI_COMMIT_SHORT_SHA'
|
||||
# assets:
|
||||
# links:
|
||||
# - name: 'Fabric Jars'
|
||||
# url: 'https://gitlab.com/jeseibel/minecraft-lod-mod/cw/-/jobs/${GE_JOB_ID}/artifacts/file/fabric/build/libs'
|
||||
# - name: 'Forge Jars'
|
||||
# url: 'https://gitlab.com/jeseibel/minecraft-lod-mod/cw/-/jobs/${GE_JOB_ID}/artifacts/file/forge/build/libs'
|
||||
|
||||
# generate and publish API javadocs
|
||||
pages:
|
||||
stage: pages
|
||||
needs: []
|
||||
script:
|
||||
# this should only run for the API
|
||||
- ./gradlew api:clean --gradle-user-home cache/;
|
||||
# this also runs unit tests
|
||||
- ./gradlew api:build --gradle-user-home cache/;
|
||||
- ./gradlew api:javadoc --gradle-user-home cache/;
|
||||
- mkdir public
|
||||
- cp -r $CI_PROJECT_DIR/coreSubProjects/api/build/docs/javadoc/. public
|
||||
artifacts:
|
||||
paths:
|
||||
- public
|
||||
allow_failure: false
|
||||
extends: .build_java
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
## Chcek off each item in this list before submitting:
|
||||
## Check off each item in this list before submitting:
|
||||
|
||||
<!--
|
||||
To mark a section as complete either put an "x" in between the square brackets, example: "[x]"
|
||||
@@ -6,13 +6,13 @@ Or click the checkbox once the issue has been created.
|
||||
-->
|
||||
|
||||
1. [ ] Check the FAQ to see if your issue has already been reported and has a solution:
|
||||
[Problems-and-solutions](https://gitlab.com/jeseibel/minecraft-lod-mod/-/wikis/2-frequently-asked-questions/2-problems-and-solutions/Problems-and-Solutions)
|
||||
[Problems-and-solutions](https://gitlab.com/jeseibel/distant-horizons/-/wikis/2-frequently-asked-questions/2-problems-and-solutions/Problems-and-Solutions)
|
||||
|
||||
2. [ ] Make sure you are not using any mods on the incompatible list:
|
||||
[Mod support FAQ](https://gitlab.com/jeseibel/minecraft-lod-mod/-/wikis/2-frequently-asked-questions/4-mod-support/Mod-Support)
|
||||
[Mod support FAQ](https://gitlab.com/jeseibel/distant-horizons/-/wikis/2-frequently-asked-questions/4-mod-support/Mod-Support)
|
||||
|
||||
3. [ ] Check the existing issues to verify that your bug hasn't already been submitted:
|
||||
[Issues](https://gitlab.com/jeseibel/minecraft-lod-mod/-/issues/)
|
||||
[Issues](https://gitlab.com/jeseibel/distant-horizons/-/issues/)
|
||||
|
||||
4. [ ] Upload Minecraft's crash report and/or log. \
|
||||
Minecraft crash reports are located in: `.minecraft/crash-reports` \
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
- [ ] Check the existing [feature requests](https://gitlab.com/jeseibel/minecraft-lod-mod/-/issues/?sort=updated_desc&state=opened&label_name%5B%5D=Feature) to verify that your feature hasn't already been suggested.
|
||||
- [ ] Check the existing [feature requests](https://gitlab.com/jeseibel/distant-horizons/-/issues/?sort=updated_desc&state=opened&label_name%5B%5D=Feature) to verify that your feature hasn't already been suggested.
|
||||
|
||||
1. **Describe the feature**:
|
||||
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
1. Check the existing [improvement requests](https://gitlab.com/jeseibel/minecraft-lod-mod/-/issues/?sort=updated_desc&state=all&label_name%5B%5D=Improvement) to verify that your improvement hasn't already been suggested.
|
||||
1. Check the existing [improvement requests](https://gitlab.com/jeseibel/distant-horizons/-/issues/?sort=updated_desc&state=all&label_name%5B%5D=Improvement) to verify that your improvement hasn't already been suggested.
|
||||
|
||||
2. **Describe the improvement**:
|
||||
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
FROM eclipse-temurin:17-jdk
|
||||
|
||||
WORKDIR /home/build/
|
||||
COPY ./gradlew .
|
||||
RUN chmod +x ./gradlew
|
||||
CMD echo "\r========== [CLEAN: $MC_VER] ==========" && \
|
||||
./gradlew clean -PmcVer="$MC_VER" --gradle-user-home .gradle-cache/ && \
|
||||
echo "\r========== [BUILD: $MC_VER] ==========" && \
|
||||
./gradlew build -PmcVer="$MC_VER" --gradle-user-home .gradle-cache/ && \
|
||||
echo "\r========== [MERGE: $MC_VER] ==========" && \
|
||||
./gradlew mergeJars -PmcVer="$MC_VER" --gradle-user-home .gradle-cache/ && \
|
||||
echo "\r========== [DONE: $MC_VER] =========="
|
||||
@@ -1,66 +1,94 @@
|
||||
# <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?
|
||||
|
||||
Distant Horizons is a Minecraft mod that adds a Level Of Detail (LOD) system to\
|
||||
render simplified chunks outside the normal render distance\
|
||||
allowing for an increased view distance without harming performance.
|
||||
Distant Horizons is a mod which implements a [Level of Detail](https://en.wikipedia.org/wiki/Level_of_detail_(computer_graphics)) system to Minecraft.\
|
||||
This allows for far greater render distances without harming performance by gradually lowering the quality of distant terrain.
|
||||
|
||||
In other words: this mod lets you see farther without turning your game into a slide show.\
|
||||
If you want to see a quick demo, check out a video covering the mod here:
|
||||
Below is a video demonstrating the system:
|
||||
|
||||
<a href="https://youtu.be/_04BZ8W2bDM" target="_blank"></a>
|
||||
<a href="https://youtu.be/SxQdbtjGEsc" target="_blank"></a>
|
||||
|
||||
<br>
|
||||
|
||||
## Minecraft and Library Versions
|
||||
|
||||
This branch supports the following versions of Minecraft:
|
||||
### This branch supports the following versions of Minecraft:
|
||||
|
||||
> **NOTE: At the moment only 1.18.2 fabric works/build/runs**
|
||||
#### 1.20.4, 1.20.3 (Default)
|
||||
Fabric: 0.15.1\
|
||||
Fabric API: 0.91.2+1.20.4\
|
||||
Forge: 49.0.30\
|
||||
NeoForge: 118-beta\
|
||||
Parchment: 1.20.2:2023.12.10\
|
||||
Modmenu: 9.0.0-pre.1
|
||||
|
||||
#### 1.19 (BROKE)
|
||||
Forge: 41.0.19\
|
||||
Fabric: 0.14.7\
|
||||
Fabric API: 0.55.3+1.19\
|
||||
Modmenu: 4.0.0
|
||||
#### 1.20.2
|
||||
Fabric: 0.14.24\
|
||||
Fabric API: 0.90.4+1.20.2\
|
||||
Forge: 48.0.13\
|
||||
Parchment: 1.20.1:2023.09.03\
|
||||
Modmenu: 8.0.0
|
||||
|
||||
#### 1.18.2 (ONLY FABRIC WORKS)
|
||||
Fabric: 0.14.14\
|
||||
Fabric API: 0.67.1+1.18.2\
|
||||
Forge: 40.0.32\
|
||||
Parchment=2022.11.06\
|
||||
#### 1.20.1, 1.20
|
||||
Fabric: 0.14.24\
|
||||
Fabric API: 0.90.4+1.20.1\
|
||||
Forge: 47.2.1\
|
||||
Parchment: 1.20.1:2023.09.03\
|
||||
Modmenu: 7.2.2
|
||||
|
||||
#### 1.19.4
|
||||
Fabric: 0.14.24\
|
||||
Fabric API: 0.87.1+1.19.4\
|
||||
Forge: 45.2.4\
|
||||
Parchment: 1.19.4:2023.06.26\
|
||||
Modmenu: 6.3.1
|
||||
|
||||
#### 1.19.2
|
||||
Fabric: 0.14.24\
|
||||
Fabric API: 0.76.1+1.19.2\
|
||||
Forge: 43.3.2\
|
||||
Parchment: 1.19.2:2022.11.27\
|
||||
Modmenu: 4.2.0-beta.2
|
||||
|
||||
#### 1.18.2
|
||||
Fabric: 0.14.24\
|
||||
Fabric API: 0.76.0+1.18.2\
|
||||
Forge: 40.2.10\
|
||||
Parchment: 1.18.2:2022.11.06\
|
||||
Modmenu: 3.2.5
|
||||
|
||||
#### 1.18.1, 1.18 (CEASING DEVELOPMENT SOON)
|
||||
Forge: 39.1.2\
|
||||
Fabric: 0.13.3\
|
||||
Fabric API: 0.42.6+1.18\
|
||||
Modmenu: 3.0.1
|
||||
|
||||
#### 1.17.1, 1.17 (BROKE)
|
||||
Forge: 37.1.1\
|
||||
Fabric: 0.13.2\
|
||||
#### 1.17.1, 1.17
|
||||
Fabric: 0.14.24\
|
||||
Fabric API: 0.46.1+1.17\
|
||||
Forge: 37.1.1\
|
||||
Parchment: 1.17.1:2021.12.12\
|
||||
Modmenu: 2.0.14
|
||||
|
||||
#### 1.16.5, 1.16.5 (BROKE)
|
||||
Forge: 36.2.28\
|
||||
Fabric: 0.13.2\
|
||||
#### 1.16.5, 1.16.4
|
||||
Fabric: 0.14.24\
|
||||
Fabric API: 0.42.0+1.16\
|
||||
Forge: 36.2.39\
|
||||
Parchment: 1.16.5:2022.03.06\
|
||||
Modmenu: 1.16.22
|
||||
<br><br>
|
||||
|
||||
### Versions no longer supported
|
||||
- 1.18.1, 1.18
|
||||
- 1.19.1, 1.19
|
||||
- 1.19.3
|
||||
|
||||
<br>
|
||||
|
||||
### Plugin and Library versions
|
||||
|
||||
Fabric loom: 1.1-snapshot\
|
||||
Forge gradle: 5.1.67\
|
||||
Gradle: 8.5\
|
||||
Fabric loom: 1.4-SNAPSHOT\
|
||||
Architectury loom (Forge gradle replacement): 1.4-SNAPSHOT\
|
||||
Sponge vanilla gradle: 0.2.1-SNAPSHOT\
|
||||
Sponge mixin gradle: 0.7-SNAPSHOT\
|
||||
Java Compiler plugin: Manifold Preprocessor
|
||||
Java Preprocessor plugin: Manifold Preprocessor
|
||||
|
||||
<br>
|
||||
|
||||
@@ -72,7 +100,7 @@ Java Compiler plugin: Manifold Preprocessor
|
||||
Visit https://www.oracle.com/java/technologies/downloads/ for installers.
|
||||
* Git or someway to clone git projects. <br>
|
||||
Visit https://git-scm.com/ for installers.
|
||||
* (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:**
|
||||
1. Install the Manifold plugin
|
||||
@@ -85,17 +113,15 @@ Java Compiler plugin: Manifold Preprocessor
|
||||
3. Make sure eclipse has the JDK 17 installed. (This is needed so that eclipse can run minecraft)
|
||||
4. Import the project into eclipse
|
||||
|
||||
|
||||
<br>
|
||||
|
||||
## Switching Versions
|
||||
|
||||
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.)
|
||||
>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`). \
|
||||
> If anyone knows how to solve this issue please let us know here: \
|
||||
> https://gitlab.com/jeseibel/minecraft-lod-mod/-/issues/233
|
||||
|
||||
If running in an IDE, to ensure the IDE noticed the version change, run any gradle command to refresh gradle.\
|
||||
In IntelliJ, you will also need to do a gradle sync if it didn't happen automatically.
|
||||
|
||||
<br>
|
||||
|
||||
## Compiling
|
||||
@@ -107,22 +133,31 @@ From the File Explorer:
|
||||
1. Download and extract the project zip
|
||||
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)
|
||||
4. Run the commands: `./gradlew assemble`
|
||||
5. The compiled jar file will be in the folder `Merged`
|
||||
4. Run the commands: `./gradlew assemble` (You may need to use a `.\` on Windows)
|
||||
5. Merge the jars with `./gradlew mergeJars`
|
||||
6. The compiled jar file will be in the folder `Merged`
|
||||
|
||||
From the command line:
|
||||
1. `git clone --recurse-submodules https://gitlab.com/jeseibel/minecraft-lod-mod.git`
|
||||
2. `cd minecraft-lod-mod`
|
||||
1. `git clone --recurse-submodules https://gitlab.com/jeseibel/distant-horizons.git`
|
||||
2. `cd distant-horizons`
|
||||
3. `./gradlew assemble`
|
||||
4. The compiled jar file will be in the folder `Merged`
|
||||
4. `./gradlew mergeJars`
|
||||
5. The compiled jar file will be in the folder `Merged`
|
||||
|
||||
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. \
|
||||
> Example: `./gradlew assemble -PmcVer=1.18.2`
|
||||
>Note: You can add the argument `-PmcVer=?` to tell gradle to build a selected MC version instead of having to modify the `gradle.properties` file.\
|
||||
> For example: `./gradlew assemble -PmcVer=1.18.2`
|
||||
|
||||
<br>
|
||||
|
||||
<Br>
|
||||
## Compiling with Docker
|
||||
|
||||
`./compile <version>`
|
||||
|
||||
You can also locally compile the DH jars without a Java environment by using Docker. Where `<version>` is the version of Minecraft to compile for (ie `1.20.1`), or the keyword `all`. See [Versions](#minecraft-and-library-versions) for a list of all supported values.
|
||||
|
||||
<br>
|
||||
|
||||
## Other commands
|
||||
|
||||
@@ -130,6 +165,7 @@ Run tests with: `./gradlew test`
|
||||
|
||||
`./gradlew clean` to delete any compiled code.
|
||||
|
||||
<br>
|
||||
|
||||
## Note to self
|
||||
|
||||
@@ -137,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.
|
||||
|
||||
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>
|
||||
(In IntelliJ it's at the top where it says "choose sources" when browsing a Minecraft class)
|
||||
|
||||
@@ -145,12 +181,12 @@ If your IDE fails to auto-detect the source jars when browsing Minecraft classes
|
||||
|
||||
## Other Useful commands
|
||||
|
||||
Run the standalone jar: `./gradlew run`\
|
||||
Build the standalone jar: `./gradlew core:build`\
|
||||
Only build Fabric: `./gradlew fabric:assemble` or `./gradlew fabric:build`\
|
||||
Only build Forge: `./gradlew fabric:assemble` or `./gradlew forge:build`\
|
||||
Run the Fabric client (for debugging): `./gradlew fabric:runClient`\
|
||||
Run the Forge client (for debugging): `./gradlew forge:runClient`
|
||||
Run the standalone jar: `./gradlew run` <br>
|
||||
Build the standalone jar: `./gradlew core:build` <br>
|
||||
Only build Fabric: `./gradlew fabric:assemble` or `./gradlew fabric:build` <br>
|
||||
Only build Forge: `./gradlew forge:assemble` or `./gradlew forge:build` <br>
|
||||
Run the Fabric client (for debugging): `./gradlew fabric:runClient` <br>
|
||||
Run the Forge client (for debugging): `./gradlew forge:runClient` <br>
|
||||
|
||||
To build all versions: `./buildAll` (all builds will end up in the `Merged` folder)
|
||||
|
||||
@@ -158,17 +194,17 @@ To build all versions: `./buildAll` (all builds will end up in the `Merged` fold
|
||||
|
||||
## Open Source Acknowledgements
|
||||
|
||||
Forgix (To merge multiple mod versions into one jar) [_Used to be_ [_DHJarMerger_](https://github.com/Ran-helo/DHJarMerger)]\
|
||||
Forgix (To merge multiple mod versions into one jar) [_Formerly_ [_DHJarMerger_](https://github.com/Ran-helo/DHJarMerger)]\
|
||||
https://github.com/PacifistMC/Forgix
|
||||
|
||||
XZ for Java (data compression)\
|
||||
https://tukaani.org/xz/java.html
|
||||
LZ4 for Java (data compression)\
|
||||
https://github.com/lz4/lz4-java
|
||||
|
||||
Json & Toml for Java (config handling)\
|
||||
NightConfig for JSON & TOML (config handling)\
|
||||
https://github.com/TheElectronWill/night-config
|
||||
|
||||
SVG Salamander for SVG support\
|
||||
SVG Salamander for SVG support (not being used atm)\
|
||||
https://github.com/blackears/svgSalamander
|
||||
|
||||
FlatLaf for theming (for development testing, may remove later)\
|
||||
https://www.formdev.com/flatlaf/
|
||||
sqlite-jdbc\
|
||||
https://github.com/xerial/sqlite-jdbc
|
||||
|
||||
+219
-127
@@ -1,59 +1,52 @@
|
||||
plugins {
|
||||
id "java"
|
||||
|
||||
// Plugin to handle dependencies
|
||||
id "com.github.johnrengelman.shadow" version '7.1.2' apply false
|
||||
// Plugin to put dependencies inside our final jar
|
||||
id "com.github.johnrengelman.shadow" version '8.1.1' apply false
|
||||
|
||||
// Plugin to create merged jars
|
||||
id "io.github.pacifistmc.forgix" version "1.2.6"
|
||||
id "io.github.pacifistmc.forgix" version "1.2.9"
|
||||
|
||||
// Manifold preprocessor
|
||||
id "systems.manifold.manifold-gradle-plugin" version "0.0.2-alpha"
|
||||
|
||||
// Provides mc libraries to core
|
||||
// id "org.spongepowered.gradle.vanilla" version '0.2.1-SNAPSHOT' apply false
|
||||
// Architectury is used here only as a replacement for forge's own loom
|
||||
id "dev.architectury.loom" version "1.6-SNAPSHOT" apply false
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Creates the list of preprocessors to use.
|
||||
*
|
||||
* @param mcVers array of all MC versions
|
||||
* @param mcIndex array index of the currently active MC version
|
||||
*/
|
||||
def writeBuildGradlePredefine(List<String> mcVers, int mcIndex) {
|
||||
ArrayList<String> redefineList = new ArrayList<String>()
|
||||
|
||||
for (int i = 0; i < mcVers.size(); i++) {
|
||||
String mcStr = mcVers[i].replace(".", "_")
|
||||
if (mcIndex < i) {
|
||||
redefineList.add("PRE_MC_" + mcStr)
|
||||
}
|
||||
if (mcIndex == i) {
|
||||
redefineList.add("MC_" + mcStr)
|
||||
}
|
||||
if (mcIndex >= i) {
|
||||
redefineList.add("POST_MC_" + mcStr)
|
||||
}
|
||||
}
|
||||
|
||||
def writeBuildGradlePredefine(List<String> mcVers, int mcIndex)
|
||||
{
|
||||
// Build the list of preprocessors to use
|
||||
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++)
|
||||
{
|
||||
String verStr = mcVers[i].replace(".", "_");
|
||||
sb.append("MC_" + verStr + "=" + i.toString() + "\n");
|
||||
|
||||
if (mcIndex == i)
|
||||
sb.append("MC_VER=" + i.toString() + "\n");
|
||||
}
|
||||
|
||||
|
||||
// Check if this is a development build
|
||||
if (mod_version.toLowerCase().contains("dev")) {
|
||||
if (mod_version.toLowerCase().contains("dev"))
|
||||
{
|
||||
// WARNING: only use this for logging, we don't want to have confusion
|
||||
// when a method doesn't work correctly in the release build.
|
||||
sb.append("DEV_BUILD")
|
||||
sb.append("=\n")
|
||||
sb.append("DEV_BUILD=\n");
|
||||
}
|
||||
|
||||
// Build the MC version preprocessors
|
||||
for (String redefinedVersion : redefineList) {
|
||||
sb.append(redefinedVersion)
|
||||
sb.append("=\n")
|
||||
}
|
||||
new File(projectDir, "build.properties").text = sb.toString()
|
||||
}
|
||||
|
||||
@@ -61,7 +54,7 @@ def writeBuildGradlePredefine(List<String> mcVers, int mcIndex) {
|
||||
// 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 + "]"
|
||||
//println "Added prop [key:" + prop.key + ", value:" + prop.value + "]"
|
||||
}
|
||||
// Sets up manifold stuff
|
||||
writeBuildGradlePredefine(rootProject.mcVers, rootProject.mcIndex)
|
||||
@@ -73,19 +66,31 @@ writeBuildGradlePredefine(rootProject.mcVers, rootProject.mcIndex)
|
||||
rootProject.versionStr = rootProject.mod_version + "-" + rootProject.minecraft_version // + "-" + new Date().format("yyyy_MM_dd_HH_mm")
|
||||
// Forgix settings (used for merging jars)
|
||||
forgix {
|
||||
group = "com.seibel.lod"
|
||||
group = "com.seibel.distanthorizons"
|
||||
mergedJarName = "DistantHorizons-${rootProject.versionStr}.jar"
|
||||
|
||||
if (findProject(":forge"))
|
||||
forge {
|
||||
jarLocation = "build/libs/DistantHorizons-forge-${rootProject.versionStr}.jar"
|
||||
}
|
||||
|
||||
forge {
|
||||
jarLocation = "build/libs/DistantHorizons-forge-${rootProject.versionStr}.jar"
|
||||
}
|
||||
if (findProject(":neoforge"))
|
||||
custom {
|
||||
projectName = "neoforge"
|
||||
jarLocation = "build/libs/DistantHorizons-neoforge-${rootProject.versionStr}.jar"
|
||||
}
|
||||
|
||||
fabric {
|
||||
jarLocation = "build/libs/DistantHorizons-fabric-${rootProject.versionStr}.jar"
|
||||
}
|
||||
if (findProject(":fabric"))
|
||||
fabric {
|
||||
jarLocation = "build/libs/DistantHorizons-fabric-${rootProject.versionStr}.jar"
|
||||
}
|
||||
|
||||
removeDuplicate "com.seibel.lod.api"
|
||||
removeDuplicate "com.seibel.lod.core"
|
||||
if (findProject(":quilt"))
|
||||
quilt {
|
||||
jarLocation = "build/libs/DistantHorizons-quilt-${rootProject.versionStr}.jar"
|
||||
}
|
||||
|
||||
removeDuplicate "com.seibel.distanthorizons"
|
||||
}
|
||||
|
||||
subprojects { p ->
|
||||
@@ -99,16 +104,21 @@ subprojects { p ->
|
||||
apply plugin: "com.github.johnrengelman.shadow"
|
||||
if (isMinecraftSubProject)
|
||||
apply plugin: "systems.manifold.manifold-gradle-plugin"
|
||||
if (p == project(":core"))
|
||||
apply plugin: "application"
|
||||
// apply plugin: "org.spongepowered.gradle.vanilla" // Provides minecraft libraries
|
||||
|
||||
// Apply forge's loom
|
||||
if ((findProject(":forge") && p == project(":forge")) ||
|
||||
(findProject(":neoforge") && p == project(":neoforge"))
|
||||
)
|
||||
{
|
||||
apply plugin: "dev.architectury.loom"
|
||||
}
|
||||
|
||||
|
||||
// Set the manifold version (may not be required tough)
|
||||
manifold {
|
||||
manifoldVersion = rootProject.manifold_version
|
||||
}
|
||||
|
||||
|
||||
|
||||
// set up custom configurations (configurations are a way to handle dependencies)
|
||||
configurations {
|
||||
@@ -117,13 +127,37 @@ subprojects { p ->
|
||||
// have implemented dependencies automatically embedded in the final jar
|
||||
implementation.extendsFrom(shadowMe)
|
||||
|
||||
// Configuration fpr core & api
|
||||
coreProjects
|
||||
shadowMe.extendsFrom(coreProjects)
|
||||
|
||||
|
||||
// FIXME this additional configuration is necessary because forge
|
||||
// needs forgeRuntimeLibrary, although adding it to shadowMe
|
||||
// causes runtime issues where the libraries aren't properly added
|
||||
forgeShadowMe
|
||||
// this should match shadowMe pretty closely
|
||||
implementation.extendsFrom(forgeShadowMe)
|
||||
shadowMe.extendsFrom(forgeShadowMe)
|
||||
forgeRuntimeLibrary.extendsFrom(forgeShadowMe)
|
||||
|
||||
|
||||
if (isMinecraftSubProject && p != project(":common")) {
|
||||
// Shadow common
|
||||
common
|
||||
shadowCommon // Don't use shadow from the shadow plugin because we don't want IDEA to index this.
|
||||
compileClasspath.extendsFrom common
|
||||
runtimeClasspath.extendsFrom common
|
||||
developmentForge.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
|
||||
@@ -131,60 +165,64 @@ subprojects { p ->
|
||||
shadowFabricLike
|
||||
compileClasspath.extendsFrom fabricLike
|
||||
runtimeClasspath.extendsFrom fabricLike
|
||||
developmentForge.extendsFrom fabricLike
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Let the application plugin know where the main class is
|
||||
// (This will point to a non-existent class in all sub-projects except "Core")
|
||||
if (p == project(":core")) {
|
||||
application {
|
||||
mainClass.set("com.seibel.lod.core.jar.JarMain")
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
//=====================//
|
||||
// shared dependencies //
|
||||
//=====================//
|
||||
|
||||
|
||||
// Manifold
|
||||
if (isMinecraftSubProject)
|
||||
if (isMinecraftSubProject) {
|
||||
annotationProcessor("systems.manifold:manifold-preprocessor:${rootProject.manifold_version}")
|
||||
|
||||
}
|
||||
|
||||
// Log4j
|
||||
// TODO: Change to shadowMe later to work in the standalone jar
|
||||
// We cannot do this now as it would break Quilt
|
||||
implementation("org.apache.logging.log4j:log4j-api:${rootProject.log4j_version}")
|
||||
implementation("org.apache.logging.log4j:log4j-core:${rootProject.log4j_version}")
|
||||
|
||||
// JOML
|
||||
implementation("org.joml:joml:${rootProject.joml_version}")
|
||||
|
||||
if (project.hasProperty("embed_joml") && embed_joml == "true")
|
||||
forgeShadowMe("org.joml:joml:${rootProject.joml_version}")
|
||||
else
|
||||
implementation("org.joml:joml:${rootProject.joml_version}")
|
||||
|
||||
// JUnit tests
|
||||
implementation("org.junit.jupiter:junit-jupiter:5.8.2")
|
||||
implementation("org.junit.jupiter:junit-jupiter-engine:5.8.2")
|
||||
implementation("junit:junit:4.13")
|
||||
|
||||
// FastUtil
|
||||
// Note: MC 1.16 uses 8.2.1, and versions after use 8.5.12
|
||||
// We cannot relocate this library since we call some MC classes that reference it
|
||||
implementation("it.unimi.dsi:fastutil:${rootProject.fastutil_version}")
|
||||
|
||||
|
||||
// Compression
|
||||
shadowMe("org.tukaani:xz:1.9")
|
||||
forgeShadowMe("org.lz4:lz4-java:${rootProject.lz4_version}") // LZ4
|
||||
forgeShadowMe("org.tukaani:xz:${rootProject.xz_version}") // LZMA
|
||||
|
||||
// Sqlite Database
|
||||
forgeShadowMe("org.xerial:sqlite-jdbc:${rootProject.sqlite_jdbc_version}")
|
||||
|
||||
// NightConfig (includes Toml & Json)
|
||||
shadowMe("com.electronwill.night-config:toml:${rootProject.nightconfig_version}")
|
||||
shadowMe("com.electronwill.night-config:json:${rootProject.nightconfig_version}")
|
||||
forgeShadowMe("com.electronwill.night-config:toml:${rootProject.nightconfig_version}")
|
||||
forgeShadowMe("com.electronwill.night-config:json:${rootProject.nightconfig_version}")
|
||||
|
||||
// Theming
|
||||
shadowMe("com.formdev:flatlaf:${rootProject.flatlaf_version}")
|
||||
// SVG (not needed atm)
|
||||
// forgeShadowMe("com.formdev:svgSalamander:${rootProject.svgSalamander_version}")
|
||||
|
||||
// Netty
|
||||
// Breaks 1.16.5
|
||||
//forgeShadowMe("io.netty:netty-all:${rootProject.netty_version}")
|
||||
|
||||
// SVG
|
||||
shadowMe("com.formdev:svgSalamander:${rootProject.svgSalamander_version}")
|
||||
shadowMe("com.formdev:flatlaf-extras:${rootProject.flatlaf_version}")
|
||||
|
||||
|
||||
// Remember, for lwjgl dependancies that arent included in Minecraft, you need to also need to add it to the ShadowJar thing
|
||||
shadowMe("org.lwjgl:lwjgl-jawt:3.2.2") {
|
||||
// Remember, for lwjgl dependencies that arent included in Minecraft, you need to also need to add it to the ShadowJar thing
|
||||
forgeShadowMe("org.lwjgl:lwjgl-jawt:${rootProject.lwjgl_version}") {
|
||||
exclude group: "org.lwjgl", module: "lwjgl" // This module is imported by Minecraft so exclude it
|
||||
}
|
||||
|
||||
@@ -197,7 +235,7 @@ subprojects { p ->
|
||||
|
||||
// Add core
|
||||
if (isMinecraftSubProject) {
|
||||
shadowMe(project(":core")) {
|
||||
coreProjects(project(":core")) {
|
||||
// Remove Junit test libraries
|
||||
exclude group: "org.junit.jupiter", module: "junit-jupiter"
|
||||
exclude group: "org.junit.jupiter", module: "junit-jupiter-engine"
|
||||
@@ -209,7 +247,7 @@ subprojects { p ->
|
||||
|
||||
// Add the api
|
||||
if (p != project(":api")) {
|
||||
shadowMe(project(":api")) {
|
||||
coreProjects(project(":api")) {
|
||||
// Remove Junit test libraries
|
||||
exclude group: "org.junit.jupiter", module: "junit-jupiter"
|
||||
exclude group: "org.junit.jupiter", module: "junit-jupiter-engine"
|
||||
@@ -222,8 +260,8 @@ subprojects { p ->
|
||||
// Add common
|
||||
if (isMinecraftSubProject && p != project(":common")) {
|
||||
// Common
|
||||
common(project(path: ":common")) { transitive false }
|
||||
shadowCommon(project(path: ":common")) { transitive false }
|
||||
common(project(":common")) { transitive false }
|
||||
shadowCommon(project(":common")) { transitive false }
|
||||
|
||||
// FabricLike
|
||||
if (findProject(":fabricLike") && p != project(":fabricLike")) {
|
||||
@@ -238,30 +276,38 @@ subprojects { p ->
|
||||
configurations = [project.configurations.shadowMe]
|
||||
if (isMinecraftSubProject && p != project(":common")) {
|
||||
configurations.push(project.configurations.shadowCommon) // Shadow the common subproject
|
||||
relocate "com.seibel.lod.common", "loaderCommon.${p.name}.com.seibel.lod.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.lod.fabriclike", "loaderCommon.${p.name}.com.seibel.lod.fabriclike" // Move the loader files to a different location
|
||||
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
|
||||
// Only ever shadow the dependencies we use otherwise some stuff would break when running on an external client
|
||||
relocate "org.lwjgl.system.jawt", "${librariesLocation}.lwjgl.system.jawt"
|
||||
|
||||
// Compression
|
||||
relocate "org.tukaani", "${librariesLocation}.tukaani"
|
||||
// Compression (LZ4)
|
||||
relocate "net.jpountz", "${librariesLocation}.jpountz"
|
||||
|
||||
// Sqlite Database
|
||||
//At the moment, there is a bug in this library which doesnt allow it to be relocated
|
||||
// relocate "org.sqlite", "${librariesLocation}.sqlite"
|
||||
|
||||
// JOML
|
||||
if (project.hasProperty("embed_joml") && embed_joml == "true")
|
||||
relocate "org.joml", "${librariesLocation}.joml"
|
||||
|
||||
// NightConfig (includes Toml & Json)
|
||||
relocate "com.electronwill.nightconfig", "${librariesLocation}.electronwill.nightconfig"
|
||||
|
||||
// Theming
|
||||
relocate 'com.formdev.flatlaf', 'distanthorizons.libraries.formdev.flatlaf'
|
||||
|
||||
// SVG
|
||||
relocate "com.kitfox.svg", "${librariesLocation}.kitfox.svg"
|
||||
// SVG (not needed atm)
|
||||
// relocate "com.kitfox.svg", "${librariesLocation}.kitfox.svg"
|
||||
|
||||
// Netty
|
||||
relocate "io.netty", "${librariesLocation}.netty"
|
||||
|
||||
mergeServiceFiles()
|
||||
}
|
||||
@@ -272,10 +318,15 @@ subprojects { p ->
|
||||
// Put stuff from gradle.properties into the mod info
|
||||
processResources {
|
||||
def resourceTargets = [ // Location of where to inject the properties
|
||||
// Holds info like git commit
|
||||
// TODO: For some reason this script doesnt work with the core project
|
||||
"build_info.json",
|
||||
|
||||
// Properties for each of the loaders
|
||||
"fabric.mod.json",
|
||||
"quilt.mod.json",
|
||||
"META-INF/mods.toml",
|
||||
"META-INF/neoforge.mods.toml",
|
||||
|
||||
// The mixins for each of the loaders
|
||||
"DistantHorizons."+ p.name +".fabricLike.mixins.json"
|
||||
@@ -283,7 +334,7 @@ subprojects { p ->
|
||||
def intoTargets = ["$buildDir/resources/main/"] // Location of the built resources folder
|
||||
|
||||
// Fix forge version numbering system as it is weird
|
||||
// For whatever reason forge uses [1.18, 1.18.1, 1.18.2) instead of the standard ["1.18", "1.18.1", "1.18.2"] which make more sense
|
||||
// For whatever reason forge uses [1.18, 1.18.1, 1.18.2) instead of the standard ["1.18", "1.18.1", "1.18.2"]
|
||||
def compatible_forgemc_versions = "${compatible_minecraft_versions}".replaceAll("\"", "").replaceAll("]", ",)")
|
||||
// println compatible_forgemc_versions
|
||||
|
||||
@@ -296,12 +347,24 @@ subprojects { p ->
|
||||
quilt_contributors.push("\"${dev.strip()}\": \"Developer\"")
|
||||
}
|
||||
quilt_contributors.reverse()
|
||||
// println quilt_contributors.join(", ")
|
||||
//println quilt_contributors.join(", ")
|
||||
|
||||
// TODOI: Find something we can use so we can basically re-map only when the jar is shadowed and relocated
|
||||
// TODO: Find something we can use so we can basically re-map only when the jar is shadowed and relocated
|
||||
// println p.tasks.findByName('shadowJar')
|
||||
|
||||
|
||||
// These "hasProperty"'s are so that they can be passed through the cli (ie in the CI)
|
||||
try {
|
||||
if (infoGitCommit == "null")
|
||||
infoGitCommit = 'git rev-parse --verify HEAD'.execute().text.trim()
|
||||
if (infoGitBranch == "null")
|
||||
infoGitBranch = 'git symbolic-ref --short HEAD'.execute().text.trim()
|
||||
} catch (Exception e) {
|
||||
infoGitCommit = infoGitBranch = "Git not found"
|
||||
println "Git or Git project not found"
|
||||
}
|
||||
|
||||
// The left side is what gets replaced in the mod info and the right side is where to get it from in the gradle.properties
|
||||
def replaceProperties = [
|
||||
version : mod_version,
|
||||
mod_name : mod_readable_name,
|
||||
@@ -316,16 +379,23 @@ subprojects { p ->
|
||||
compatible_minecraft_versions: compatible_minecraft_versions,
|
||||
compatible_forgemc_versions : compatible_forgemc_versions,
|
||||
java_version : java_version,
|
||||
quilt_contributors : "{"+quilt_contributors.join(", ")+"}"
|
||||
]
|
||||
// The left side is what gets replaced in the mod info and the right side is where to get it from in the gradle.properties
|
||||
quilt_contributors : "{"+quilt_contributors.join(", ")+"}",
|
||||
|
||||
info_git_commit : infoGitBranch,
|
||||
info_git_branch : infoGitCommit,
|
||||
info_build_source : infoBuildSource,
|
||||
|
||||
fabric_incompatibility_list : fabric_incompatibility_list,
|
||||
fabric_recommend_list : fabric_recommend_list,
|
||||
]
|
||||
|
||||
// replace any properties in the sub-projects with the values defined here
|
||||
inputs.properties replaceProperties
|
||||
replaceProperties.put "project", project
|
||||
filesMatching(resourceTargets) {
|
||||
expand replaceProperties
|
||||
}
|
||||
|
||||
|
||||
intoTargets.each { target ->
|
||||
if (file(target).exists()) {
|
||||
copy {
|
||||
@@ -337,6 +407,23 @@ subprojects { p ->
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ==================== Delete un-needed files ====================
|
||||
exclude "DistantHorizons.fabricLike.mixins.json" // This isnt required atm, but we will be using it later
|
||||
|
||||
// exclude "*.distanthorizons.accesswidener"
|
||||
//// include "${accessWidenerVersion}.distanthorizons.accesswidener"
|
||||
|
||||
// Jank solution to remove all unused accesswideners
|
||||
// The line above would work..., except that (neo)forge (well, mainly architectury) requires the original accesswidener file, meaning we require this jank solution to keep it
|
||||
exclude { file ->
|
||||
if (file.name.contains(".distanthorizons.accesswidener") && file.name != "${accessWidenerVersion}.distanthorizons.accesswidener") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -344,9 +431,11 @@ subprojects { p ->
|
||||
jar {
|
||||
from "LICENSE.txt"
|
||||
manifest {
|
||||
attributes 'Implementation-Title': rootProject.mod_name,
|
||||
'Implementation-Version': rootProject.mod_version,
|
||||
'Main-Class': 'com.seibel.lod.core.jar.JarMain' // When changing the main of the jar change this line
|
||||
attributes(
|
||||
'Implementation-Title': rootProject.mod_name,
|
||||
'Implementation-Version': rootProject.mod_version,
|
||||
'Main-Class': 'com.seibel.distanthorizons.core.jar.JarMain' // When changing the main of the jar change this line
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -366,27 +455,37 @@ subprojects { p ->
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// Run mergeJars when running build
|
||||
// TODO: Fix later
|
||||
// if (isMinecraftSubProject) {
|
||||
// build.finalizedBy(mergeJars)
|
||||
// assemble.finalizedBy(mergeJars)
|
||||
// }
|
||||
}
|
||||
|
||||
allprojects { p ->
|
||||
// Does the same as "p == project(":common") || p == project(":fabric") || p == project(":quilt") || p == project(":forge")"
|
||||
// Does the same as "p == project(":common") || p == project(":fabric") || p == project(":quilt") || p == project(":forge") || p == project("WhateverWeAddLaterOn")"
|
||||
// Useful later on so we dont have duplicated code
|
||||
def isMinecraftSubProject = p != project(":core") && p != project(":api")
|
||||
|
||||
|
||||
apply plugin: "java"
|
||||
apply plugin: "maven-publish"
|
||||
|
||||
|
||||
archivesBaseName = rootProject.mod_name
|
||||
version = project.name + "-" + rootProject.versionStr
|
||||
group = rootProject.maven_group
|
||||
|
||||
// this is the text that appears at the top of the overview (home) page
|
||||
// and is used when bookmarking a page
|
||||
javadoc.title = rootProject.mod_name + "-" + project.name
|
||||
|
||||
// Some annotations arent "technically" part of the official java standard,
|
||||
// so we define it ourself here
|
||||
javadoc {
|
||||
configure( options ) {
|
||||
tags(
|
||||
'todo:X"',
|
||||
'apiNote:a:API Note:',
|
||||
'implSpec:a:Implementation Requirements:',
|
||||
'implNote:a:Implementation Note:'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
repositories {
|
||||
@@ -425,15 +524,17 @@ allprojects { p ->
|
||||
}
|
||||
}
|
||||
|
||||
// Required for ModMenu
|
||||
maven { url "https://maven.terraformersmc.com/" }
|
||||
|
||||
// Required for Mixins & VanillaGradle
|
||||
// VanillaGradle and Mixins in common
|
||||
maven { url "https://repo.spongepowered.org/maven/" }
|
||||
|
||||
// Required for Canvas (mod)
|
||||
// Canvas mod
|
||||
maven { url "https://maven.vram.io/" }
|
||||
// ModMenu mod
|
||||
maven { url "https://maven.terraformersmc.com/" }
|
||||
|
||||
// neoforge
|
||||
maven { url "https://maven.neoforged.net/releases/" }
|
||||
|
||||
// These 3 are for importing mods that arnt on CursedForge, Modrinth, GitHub, GitLab or anywhere opensource
|
||||
flatDir {
|
||||
dirs "${rootDir}/mods/fabric"
|
||||
@@ -453,6 +554,7 @@ allprojects { p ->
|
||||
includeGroup "forge-mod"
|
||||
}
|
||||
}
|
||||
// TODO: If neoforged is ever needed, should we use that, or call it a forge mod?
|
||||
}
|
||||
|
||||
// Adds some dependencies that are in vanilla but not in core
|
||||
@@ -462,10 +564,11 @@ allprojects { p ->
|
||||
// Set the OS lwjgl is using to the current os
|
||||
project.ext.lwjglNatives = "natives-" + os.toFamilyName()
|
||||
|
||||
dependencies { // All of these dependancies 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)
|
||||
implementation platform("org.lwjgl:lwjgl-bom:${rootProject.lwjgl_version}") // TODO: Use Minecraft's version for lwjgl_version (which changes each 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
|
||||
|
||||
// REMEMBER: Dont shadow stuff here, these are just the libs that are included in Minecraft so that the core can use
|
||||
implementation "org.lwjgl:lwjgl"
|
||||
implementation "org.lwjgl:lwjgl-assimp"
|
||||
implementation "org.lwjgl:lwjgl-glfw"
|
||||
@@ -488,15 +591,15 @@ allprojects { p ->
|
||||
implementation("com.google.code.findbugs:jsr305:3.0.2")
|
||||
implementation("com.google.common:google-collect:0.5")
|
||||
implementation("com.google.guava:guava:31.1-jre")
|
||||
implementation("it.unimi.dsi:fastutil:8.5.11")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
task copyCommonLoaderResources(type: Copy) {
|
||||
from project(":common").file("src/main/resources/${accessWidenerVersion}.lod.accesswidener")
|
||||
from project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener")
|
||||
into(file(p.file("build/resources/main")))
|
||||
rename "${accessWidenerVersion}.lod.accesswidener", "lod.accesswidener"
|
||||
rename "${accessWidenerVersion}.distanthorizons.accesswidener", "distanthorizons.accesswidener"
|
||||
|
||||
|
||||
// Move the fabricLike mixin to its different places for each subproject
|
||||
if (findProject(":fabricLike")) {
|
||||
@@ -511,17 +614,6 @@ allprojects { p ->
|
||||
into p.file("build/resources/main")
|
||||
}
|
||||
|
||||
// TODO: This method doesnt seem to actually remove it from the jar, probably called at incorrect spots
|
||||
task deleteDuplicatedCommonLoaderResources(type: Delete) {
|
||||
// Delete the duplicated fabricLike.mixins.json
|
||||
delete p.file("build/resources/main/DistantHorizons.fabricLike.mixins.json")
|
||||
|
||||
// Delete all the duplicated accesswideners
|
||||
delete fileTree(p.file("build/resources/main")) {
|
||||
include "*.lod.accesswidener"
|
||||
}
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
if (isMinecraftSubProject) {
|
||||
options.release = rootProject.java_version as Integer
|
||||
|
||||
@@ -1,15 +1,22 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "==================== Note: All build jars will be in the folder called 'buildAllJars' ===================="
|
||||
mkdir -p buildAllJars | true
|
||||
|
||||
# Loop trough everything in the version properties folder
|
||||
for d in versionProperties/*; do
|
||||
# Get the name of the version that is going to be compiled
|
||||
version=$(echo "$d" | sed "s/versionProperties\///" | sed "s/.properties//")
|
||||
|
||||
# Clean out the folders and build 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)
|
||||
echo "Cleaning workspace to build $version"
|
||||
sh gradlew clean -PmcVer=$version --no-daemon | true
|
||||
echo "Building $version"
|
||||
sh gradlew build -PmcVer=$version --no-daemon | true
|
||||
# The "| true" at the end of those 2 are just to make sure the script continues even if a build fails
|
||||
echo "==================== Cleaning workspace to build $version ===================="
|
||||
sh gradlew clean -PmcVer=$version --no-daemon || true
|
||||
echo "====================Building $version ===================="
|
||||
sh gradlew build -PmcVer=$version --no-daemon || true
|
||||
echo "==================== Merging $version ===================="
|
||||
sh gradlew mergeJars -PmcVer=$version --no-daemon || true
|
||||
echo "==================== Moving jar ===================="
|
||||
mv Merged/*.jar buildAllJars/ || true
|
||||
# The "| true" at the end of those are just to make sure the script continues even if a build fails
|
||||
done
|
||||
|
||||
+20
-20
@@ -1,25 +1,25 @@
|
||||
@echo off
|
||||
|
||||
echo Windows build all script needs to be rewritten
|
||||
echo I dont use Windows so I cant really make this
|
||||
echo So if someone does use Windows and knows how to script stuff then can you please port the "buildall" script I made for Unix
|
||||
@echo off & setlocal enabledelayedexpansion
|
||||
@rem Note for devs: If this script doesnt work, please look at the unix buildAll script
|
||||
@rem This script was originally created on linux, so there may be some problems with this translation
|
||||
|
||||
|
||||
echo ==================== Note: All build jars will be in the folder called 'buildAllJars' ====================
|
||||
mkdir buildAllJars
|
||||
|
||||
@rem Loop trough everything in the version properties folder
|
||||
for %%f in (versionProperties\*) do (
|
||||
@rem Get the name of the version that is going to be compiled
|
||||
set version=%%~nf
|
||||
|
||||
@REM Old BAT script if you need some help with this task
|
||||
@rem Clean out the folders, build it, and merge it
|
||||
echo ==================== Cleaning workspace to build !version! ====================
|
||||
call .\gradlew.bat clean -PmcVer="!version!" --no-daemon
|
||||
echo ==================== Building !version! ====================
|
||||
call .\gradlew.bat build -PmcVer="!version!" --no-daemon
|
||||
echo ==================== Merging !version! ====================
|
||||
call .\gradlew.bat mergeJars -PmcVer="!version!" --no-daemon
|
||||
echo ==================== Moving jar ====================
|
||||
move Merged\*.jar buildAllJars\
|
||||
)
|
||||
|
||||
@REM SETLOCAL
|
||||
@REM CALL :buildVersion "1.19"
|
||||
@REM CALL :buildVersion "1.18.2"
|
||||
@REM CALL :buildVersion "1.18.1"
|
||||
@REM CALL :buildVersion "1.17.1"
|
||||
@REM CALL :buildVersion "1.16.5"
|
||||
@REM EXIT /B %ERRORLEVEL%
|
||||
@REM
|
||||
@REM :buildVersion
|
||||
@REM @echo on
|
||||
@REM call ./gradlew.bat clean -PmcVer="%~1" --no-daemon
|
||||
@REM call ./gradlew.bat build -PmcVer="%~1" --no-daemon
|
||||
@REM @echo off
|
||||
@REM EXIT /B 0
|
||||
endlocal
|
||||
|
||||
@@ -0,0 +1,239 @@
|
||||
import java.io.*;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URI;
|
||||
import java.net.URL;
|
||||
import java.net.URLEncoder;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class AWToAT {
|
||||
private static final Map<String, String> ACCESS_POINT_MAP = new HashMap<>();
|
||||
|
||||
static {
|
||||
ACCESS_POINT_MAP.put("accessible", "public");
|
||||
ACCESS_POINT_MAP.put("extendable", "public-f");
|
||||
ACCESS_POINT_MAP.put("mutable", "public-f");
|
||||
}
|
||||
|
||||
public String minecraftVersion;
|
||||
|
||||
public File remap(File file, String minecraftVersion) {
|
||||
this.minecraftVersion = minecraftVersion.replace("_", ".");
|
||||
File atFile = createATFile(file);
|
||||
processFile(file, atFile);
|
||||
return atFile;
|
||||
}
|
||||
|
||||
private File createATFile(File file) {
|
||||
File metaInf = new File(file.getParentFile(), "META-INF");
|
||||
if (!metaInf.exists() && !metaInf.mkdir()) throw new RuntimeException("Error creating META-INF folder");
|
||||
File atFile = new File(metaInf, "accesstransformer.cfg");
|
||||
try {
|
||||
atFile.createNewFile();
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Error creating new file", e);
|
||||
}
|
||||
return atFile;
|
||||
}
|
||||
|
||||
private void processFile(File file, File atFile) {
|
||||
/* Validates if we need to recreate the Access Transformer file if it's out of date */
|
||||
// Get the hash of the file
|
||||
String fileHash = getFileHash(file);
|
||||
try (Scanner atScanner = new Scanner(atFile)) {
|
||||
// Check if the AT file is up-to-date by comparing the hash of the file with the hash stored in the AT file
|
||||
boolean hashFound = false;
|
||||
while (atScanner.hasNextLine()) {
|
||||
String line = atScanner.nextLine();
|
||||
if (hashCheck(line, fileHash)) {
|
||||
hashFound = true;
|
||||
}
|
||||
}
|
||||
|
||||
// If the AT file is up-to-date, print a message and return
|
||||
if (hashFound) {
|
||||
System.out.println("Access Transformer file is already up to date.");
|
||||
return;
|
||||
}
|
||||
} catch (FileNotFoundException ignored) {
|
||||
// If the AT file does not exist, continue
|
||||
}
|
||||
|
||||
/* Creates the Access Transformer file */
|
||||
// Opens a scanner for reading the Access Widener file and a writer for writing to the Access Transformer file
|
||||
try (Scanner scanner = new Scanner(file); FileWriter writer = new FileWriter(atFile)) {
|
||||
// Create an ExecutorService with a fixed thread pool size equal to the number of available processors
|
||||
ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors());
|
||||
// List to hold Future objects representing results of computation
|
||||
List<Future<String>> futures = new ArrayList<>();
|
||||
|
||||
// Write the hash of the file to the AT file
|
||||
writer.write("#DH_MAPPING_HASH:" + fileHash + "\n");
|
||||
|
||||
// Read each line from the file
|
||||
while (scanner.hasNextLine()) {
|
||||
String line = scanner.nextLine();
|
||||
// Skip lines starting with "accessWidener", "#" or blank lines
|
||||
if (line.startsWith("accessWidener") || line.startsWith("#") || line.isBlank()) continue;
|
||||
|
||||
// Submit the line to the executor service for processing
|
||||
// The processing is done by the processLine method
|
||||
futures.add(executor.submit(() -> processLine(line.split(" "))));
|
||||
}
|
||||
|
||||
// Write the results to the output file
|
||||
// The results are obtained by calling the get method on each Future
|
||||
for (Future<String> future : futures) {
|
||||
writer.write(future.get());
|
||||
}
|
||||
|
||||
// Shutdown the executor service to free up resources
|
||||
executor.shutdown();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error reading or writing to file", e);
|
||||
}
|
||||
}
|
||||
|
||||
private String processLine(String[] fields) {
|
||||
// fields[0] = access point like "accessible", "extendable", "mutable"
|
||||
// fields[1] = type like "field", "method", "class"
|
||||
// fields[2] = class name
|
||||
// fields[3] = field/method name
|
||||
// fields[4] = field/method descriptor
|
||||
|
||||
try {
|
||||
// Store the original field/method name
|
||||
String originalName = "";
|
||||
|
||||
// If there is a class name, replace the slashes with dots in the package name
|
||||
if (fields.length > 2) fields[2] = fields[2].replace("/", ".");
|
||||
|
||||
// If there is a field/method name, store the original name and remap it to SRG
|
||||
if (fields.length > 3) {
|
||||
originalName = fields[3];
|
||||
fields[3] = remapToSRG(fields[2], fields[3]);
|
||||
}
|
||||
|
||||
StringBuilder line = new StringBuilder(ACCESS_POINT_MAP.getOrDefault(fields[0], "public")).append(" ");
|
||||
switch (fields[1]) {
|
||||
case "field":
|
||||
line.append(fields[2]).append(" ").append(fields[3]).append(" #").append(originalName);
|
||||
// It'll be like: access-point class-name field-name-SRG # field-name-Mojmap
|
||||
// Eg: public net.minecraft.client.Minecraft f_90981_ # instance
|
||||
break;
|
||||
case "method":
|
||||
line.append(fields[2]).append(" ").append(fields[3]).append(fields[4]).append(" #").append(originalName);
|
||||
// It'll be like: access-point class-name method-name-SRG method-descriptor # method-name-Mojmap
|
||||
// Eg: public net.minecraft.client.Minecraft m_172797_()Lnet/minecraft/client/Minecraft; # getInstance
|
||||
break;
|
||||
default:
|
||||
line.append(fields[2]);
|
||||
// It'll be like: access-point class-name
|
||||
// Eg: public net.minecraft.client.Minecraft
|
||||
break;
|
||||
}
|
||||
line.append("\n");
|
||||
return line.toString();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Error processing line", e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hashCheck(String line, String fileHash) {
|
||||
if (line.startsWith("#DH_MAPPING_HASH:")) {
|
||||
String hash = line.substring(17);
|
||||
return hash.equals(fileHash);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public String getFileHash(File file) {
|
||||
try {
|
||||
MessageDigest shaDigest = MessageDigest.getInstance("SHA-256");
|
||||
try (InputStream fis = new FileInputStream(file)) {
|
||||
byte[] byteArray = new byte[1024];
|
||||
int bytesCount;
|
||||
|
||||
// Read file data and update in message digest
|
||||
while ((bytesCount = fis.read(byteArray)) != -1) {
|
||||
shaDigest.update(byteArray, 0, bytesCount);
|
||||
}
|
||||
}
|
||||
|
||||
byte[] bytes = shaDigest.digest();
|
||||
|
||||
// Convert byte array into signum representation
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (byte aByte : bytes) {
|
||||
sb.append(Integer.toString((aByte & 0xff) + 0x100, 16).substring(1));
|
||||
}
|
||||
|
||||
// Return complete hash
|
||||
return sb.toString();
|
||||
} catch (NoSuchAlgorithmException | IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// WARNING: BELOW LIES HIGHLY CURSED CODE AND MIGHT EVEN BE ILLEGAL
|
||||
|
||||
|
||||
|
||||
|
||||
// Flag to track if there was an error in the GET request
|
||||
boolean error = false;
|
||||
|
||||
/**
|
||||
* This method returns a field or method name from Mojang mappings as SRG mappings.
|
||||
* It makes a GET request to the Linkie API to fetch the SRG name.
|
||||
*
|
||||
* @param clazz The class name
|
||||
* @param name The field or method name
|
||||
* @return The SRG name
|
||||
* @throws Exception If there is an error in the GET request or the SRG name is not found in the response
|
||||
*/
|
||||
private String remapToSRG(String clazz, String name) throws Exception {
|
||||
// Encode the class and field/method name to be used in the URL
|
||||
String query = URLEncoder.encode(clazz + "." + name, StandardCharsets.UTF_8);
|
||||
// Construct the URL for the GET request
|
||||
String urlString = "https://linkieapi.shedaniel.me/api/search?namespace=mojang&query=" + query + "&version=" + this.minecraftVersion + "&limit=1&allowClasses=false&allowFields=true&allowMethods=true&translate=mojang_srg";
|
||||
URL url = new URI(urlString).toURL();
|
||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||
conn.setRequestMethod("GET");
|
||||
int responseCode = conn.getResponseCode();
|
||||
if (responseCode == HttpURLConnection.HTTP_OK) {
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
|
||||
String inputLine;
|
||||
StringBuilder content = new StringBuilder();
|
||||
// Read the response line by line
|
||||
while ((inputLine = in.readLine()) != null) {
|
||||
content.append(inputLine);
|
||||
}
|
||||
in.close();
|
||||
conn.disconnect();
|
||||
// Regex to find the SRG name in the response
|
||||
Pattern pattern = Pattern.compile("\"l\"\\s*:\\s*\\{[^}]*\"i\"\\s*:\\s*\"([^\"]*)\"");
|
||||
Matcher matcher = pattern.matcher(content.toString());
|
||||
if (matcher.find()) return matcher.group(1);
|
||||
else throw new Exception("Couldn't find the SRG mapping for name: " + name + "\nCould not find 'i' in 'l' object in the response"); // `i` is the SRG name which is stored in the `l` JSON object
|
||||
} else {
|
||||
if (error) {
|
||||
// If there was an error in the GET request, and we already tried again, throw an exception
|
||||
throw new Exception("The GET request failed");
|
||||
}
|
||||
// If there was an error in the GET request, wait 2.5 seconds and try again as we probably got rate limited
|
||||
error = true;
|
||||
Thread.sleep(2500);
|
||||
return remapToSRG(clazz, name);
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -56,7 +56,7 @@ a project may be further defined and clarified by project maintainers.
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the team lead James Seibel through Discord at `@BackSun#4157`. All
|
||||
reported by contacting the team lead James Seibel through Discord at `@backsun`. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
|
||||
+12
-5
@@ -1,17 +1,23 @@
|
||||
|
||||
// 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}.lod.accesswidener"))
|
||||
accessWideners(project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener"))
|
||||
version(rootProject.minecraft_version)
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// We depend on fabric loader here to use the fabric @Environment annotations and get the mixin dependencies
|
||||
// Do NOT use other classes from fabric loader
|
||||
// modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
|
||||
|
||||
// So mixins can be written in common
|
||||
compileOnly group:'org.spongepowered', name:'mixin', version:'0.8.5'
|
||||
}
|
||||
@@ -30,3 +36,4 @@ publishing {
|
||||
// Add repositories to publish to here.
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
package com.seibel.distanthorizons.common;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiAfterDhInitEvent;
|
||||
import com.seibel.distanthorizons.api.methods.events.abstractEvents.DhApiBeforeDhInitEvent;
|
||||
import com.seibel.distanthorizons.common.wrappers.DependencySetup;
|
||||
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftDedicatedServerWrapper;
|
||||
import com.seibel.distanthorizons.core.api.internal.SharedApi;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.config.ConfigBase;
|
||||
import com.seibel.distanthorizons.core.config.eventHandlers.presets.ThreadPresetConfigEventHandler;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.jar.ModJarInfo;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModAccessor;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IModChecker;
|
||||
import com.seibel.distanthorizons.coreapi.DependencyInjection.ApiEventInjector;
|
||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.dedicated.DedicatedServer;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* Base for all mod loader initializers
|
||||
* and handles most setup.
|
||||
*/
|
||||
public abstract class AbstractModInitializer
|
||||
{
|
||||
protected static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
|
||||
|
||||
private CommandDispatcher<CommandSourceStack> commandDispatcher;
|
||||
|
||||
|
||||
|
||||
//==================//
|
||||
// abstract methods //
|
||||
//==================//
|
||||
|
||||
protected abstract void createInitialBindings();
|
||||
protected abstract IEventProxy createClientProxy();
|
||||
protected abstract IEventProxy createServerProxy(boolean isDedicated);
|
||||
protected abstract void initializeModCompat();
|
||||
|
||||
protected abstract void subscribeRegisterCommandsEvent(Consumer<CommandDispatcher<CommandSourceStack>> eventHandler);
|
||||
|
||||
protected abstract void subscribeClientStartedEvent(Runnable eventHandler);
|
||||
protected abstract void subscribeServerStartingEvent(Consumer<MinecraftServer> eventHandler);
|
||||
protected abstract void runDelayedSetup();
|
||||
|
||||
|
||||
|
||||
//===================//
|
||||
// initialize events //
|
||||
//===================//
|
||||
|
||||
public void onInitializeClient()
|
||||
{
|
||||
DependencySetup.createClientBindings();
|
||||
|
||||
LOGGER.info("Initializing " + ModInfo.READABLE_NAME);
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDhInitEvent.class, null);
|
||||
|
||||
this.startup();
|
||||
this.printModInfo(true);
|
||||
|
||||
this.createClientProxy().registerEvents();
|
||||
this.createServerProxy(false).registerEvents();
|
||||
|
||||
this.initializeModCompat();
|
||||
|
||||
LOGGER.info(ModInfo.READABLE_NAME + " Initialized");
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterDhInitEvent.class, null);
|
||||
|
||||
// Client uses config for auto-updater, so it's initialized here instead of post-init stage
|
||||
this.initConfig();
|
||||
|
||||
this.subscribeClientStartedEvent(this::postInit);
|
||||
}
|
||||
|
||||
public void onInitializeServer()
|
||||
{
|
||||
DependencySetup.createServerBindings();
|
||||
|
||||
LOGGER.info("Initializing " + ModInfo.READABLE_NAME);
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDhInitEvent.class, null);
|
||||
|
||||
this.startup();
|
||||
this.printModInfo(false);
|
||||
|
||||
// This prevents returning uninitialized Config values,
|
||||
// resulting from a circular reference mid-initialization in a static class
|
||||
// noinspection ResultOfMethodCallIgnored
|
||||
ThreadPresetConfigEventHandler.INSTANCE.toString();
|
||||
|
||||
this.createServerProxy(true).registerEvents();
|
||||
|
||||
LOGGER.info(ModInfo.READABLE_NAME + " Initialized");
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterDhInitEvent.class, null);
|
||||
|
||||
this.subscribeRegisterCommandsEvent(dispatcher -> { this.commandDispatcher = dispatcher; });
|
||||
|
||||
this.subscribeServerStartingEvent(server ->
|
||||
{
|
||||
MinecraftDedicatedServerWrapper.INSTANCE.dedicatedServer = (DedicatedServer)server;
|
||||
|
||||
this.initConfig();
|
||||
this.postInit();
|
||||
this.initCommands();
|
||||
|
||||
LOGGER.info("Dedicated server initialized at " + server.getServerDirectory());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
//===========================//
|
||||
// inner initializer methods //
|
||||
//===========================//
|
||||
|
||||
private void startup()
|
||||
{
|
||||
DependencySetup.createSharedBindings();
|
||||
SharedApi.init();
|
||||
this.createInitialBindings();
|
||||
}
|
||||
|
||||
private void printModInfo(boolean printGitInfo)
|
||||
{
|
||||
LOGGER.info(ModInfo.READABLE_NAME + ", Version: " + ModInfo.VERSION);
|
||||
|
||||
if (printGitInfo)
|
||||
{
|
||||
// Useful for dev builds
|
||||
LOGGER.info("DH Branch: " + ModJarInfo.Git_Branch);
|
||||
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)
|
||||
{
|
||||
IModChecker modChecker = SingletonInjector.INSTANCE.get(IModChecker.class);
|
||||
if (modChecker.isModLoaded(modId))
|
||||
{
|
||||
//noinspection unchecked
|
||||
ModAccessorInjector.INSTANCE.bind((Class<? extends IModAccessor>) accessorClass, accessorConstructor.get());
|
||||
}
|
||||
}
|
||||
|
||||
private void initConfig()
|
||||
{
|
||||
ConfigBase.INSTANCE = new ConfigBase(ModInfo.ID, ModInfo.NAME, Config.class, 2);
|
||||
Config.completeDelayedSetup();
|
||||
}
|
||||
|
||||
private void postInit()
|
||||
{
|
||||
LOGGER.info("Post-Initializing Mod");
|
||||
this.runDelayedSetup();
|
||||
LOGGER.info("Mod Post-Initialized");
|
||||
}
|
||||
|
||||
private void initCommands() { /* currently unimplemented */ }
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// helper classes //
|
||||
//================//
|
||||
|
||||
public interface IEventProxy
|
||||
{
|
||||
void registerEvents();
|
||||
}
|
||||
|
||||
}
|
||||
+13
-16
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
* 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
|
||||
@@ -16,20 +16,17 @@
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.quilt.wrappers.modAccessor;
|
||||
|
||||
import com.seibel.lod.core.wrapperInterfaces.modAccessor.IStarlightAccessor;
|
||||
package com.seibel.distanthorizons.common.util;
|
||||
|
||||
|
||||
public class StarlightAccessor implements IStarlightAccessor {
|
||||
|
||||
@Override
|
||||
public String getModName() {
|
||||
return "Starlight-Fabric-1.18.X";
|
||||
}
|
||||
|
||||
public StarlightAccessor() {
|
||||
|
||||
}
|
||||
/**
|
||||
* Added to MC's dynamic textures via mixins
|
||||
* in order to denote whether a texture is a lightmap or not. <br><br>
|
||||
*
|
||||
* If not done any dynamic texture could be used as the lightmap
|
||||
* which causes some weird rendering bugs.
|
||||
*/
|
||||
public interface ILightTextureMarker
|
||||
{
|
||||
void markLightTexture();
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.util;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
|
||||
public class ProxyUtil
|
||||
{
|
||||
|
||||
public static ILevelWrapper getLevelWrapper(LevelAccessor level)
|
||||
{
|
||||
ILevelWrapper levelWrapper;
|
||||
if (level instanceof ServerLevel)
|
||||
{
|
||||
levelWrapper = ServerLevelWrapper.getWrapper((ServerLevel) level);
|
||||
}
|
||||
else
|
||||
{
|
||||
levelWrapper = ClientLevelWrapper.getWrapper((ClientLevel) level);
|
||||
}
|
||||
|
||||
return levelWrapper;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.gui.ClassicConfigGUI;
|
||||
import com.seibel.distanthorizons.common.wrappers.gui.LangWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.level.KeyedClientLevelManager;
|
||||
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftDedicatedServerWrapper;
|
||||
import com.seibel.distanthorizons.core.level.IKeyedClientLevelManager;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.config.IConfigGui;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.config.ILangWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftClientWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftRenderWrapper;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
|
||||
|
||||
/**
|
||||
* Binds all necessary dependencies, so we
|
||||
* can access them in Core. <br>
|
||||
* This needs to be called before any Core classes
|
||||
* are loaded.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @author Ran
|
||||
* @version 12-1-2021
|
||||
*/
|
||||
public class DependencySetup
|
||||
{
|
||||
|
||||
public static void createSharedBindings()
|
||||
{
|
||||
SingletonInjector.INSTANCE.bind(ILangWrapper.class, LangWrapper.INSTANCE);
|
||||
SingletonInjector.INSTANCE.bind(IVersionConstants.class, VersionConstants.INSTANCE);
|
||||
SingletonInjector.INSTANCE.bind(IWrapperFactory.class, WrapperFactory.INSTANCE);
|
||||
SingletonInjector.INSTANCE.bind(IKeyedClientLevelManager.class, KeyedClientLevelManager.INSTANCE);
|
||||
DependencySetupDoneCheck.isDone = true;
|
||||
}
|
||||
|
||||
//@Environment(EnvType.SERVER)
|
||||
public static void createServerBindings()
|
||||
{
|
||||
SingletonInjector.INSTANCE.bind(IMinecraftSharedWrapper.class, MinecraftDedicatedServerWrapper.INSTANCE);
|
||||
}
|
||||
|
||||
//@Environment(EnvType.CLIENT)
|
||||
public static void createClientBindings()
|
||||
{
|
||||
SingletonInjector.INSTANCE.bind(IMinecraftClientWrapper.class, MinecraftClientWrapper.INSTANCE);
|
||||
SingletonInjector.INSTANCE.bind(IMinecraftSharedWrapper.class, MinecraftClientWrapper.INSTANCE);
|
||||
SingletonInjector.INSTANCE.bind(IMinecraftRenderWrapper.class, MinecraftRenderWrapper.INSTANCE);
|
||||
SingletonInjector.INSTANCE.bind(IConfigGui.class, ClassicConfigGUI.CONFIG_CORE_INTERFACE);
|
||||
}
|
||||
|
||||
}
|
||||
+7
-5
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
* 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
|
||||
@@ -16,14 +16,16 @@
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.common.wrappers;
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class DependencySetupDoneCheck
|
||||
{
|
||||
// TODO move to DependencySetup
|
||||
public static boolean isDone = false;
|
||||
public static Supplier<Boolean> getIsCurrentThreadDistantGeneratorThread = (() -> {return false;});
|
||||
// TODO why is this here and what is its purpose?
|
||||
public static Supplier<Boolean> getIsCurrentThreadDistantGeneratorThread = (() -> { return false; });
|
||||
|
||||
}
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
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.pos.DhBlockPos;
|
||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||
import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
|
||||
/**
|
||||
* This class converts to and from Minecraft objects (Ex: Matrix4f)
|
||||
* and objects we created (Ex: Mat4f).
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 11-20-2021
|
||||
*/
|
||||
public class McObjectConverter
|
||||
{
|
||||
private static int bufferIndex(int x, int y)
|
||||
{
|
||||
return y * 4 + x;
|
||||
}
|
||||
|
||||
|
||||
/** 4x4 float matrix converter */
|
||||
@Deprecated
|
||||
public static Mat4f Convert(
|
||||
#if MC_VER < MC_1_19_4 com.mojang.math.Matrix4f
|
||||
#else org.joml.Matrix4f #endif
|
||||
mcMatrix)
|
||||
{
|
||||
FloatBuffer buffer = FloatBuffer.allocate(16);
|
||||
storeMatrix(mcMatrix, buffer);
|
||||
Mat4f matrix = new Mat4f(buffer);
|
||||
#if MC_VER < MC_1_19_4
|
||||
matrix.transpose(); // In 1.19.3 and later, we no longer need to transpose it
|
||||
#endif
|
||||
return matrix;
|
||||
}
|
||||
/** Taken from Minecraft's com.mojang.math.Matrix4f class from 1.18.2 */
|
||||
private static void storeMatrix(
|
||||
#if MC_VER < MC_1_19_4 com.mojang.math.Matrix4f
|
||||
#else org.joml.Matrix4f #endif
|
||||
matrix,
|
||||
FloatBuffer buffer)
|
||||
{
|
||||
#if MC_VER < MC_1_19_4
|
||||
matrix.store(buffer);
|
||||
#else
|
||||
// Mojang starts to use joml's Matrix4f libary in 1.19.3 so we copy their store method and use it here if its newer than 1.19.3
|
||||
buffer.put(bufferIndex(0, 0), matrix.m00());
|
||||
buffer.put(bufferIndex(0, 1), matrix.m01());
|
||||
buffer.put(bufferIndex(0, 2), matrix.m02());
|
||||
buffer.put(bufferIndex(0, 3), matrix.m03());
|
||||
buffer.put(bufferIndex(1, 0), matrix.m10());
|
||||
buffer.put(bufferIndex(1, 1), matrix.m11());
|
||||
buffer.put(bufferIndex(1, 2), matrix.m12());
|
||||
buffer.put(bufferIndex(1, 3), matrix.m13());
|
||||
buffer.put(bufferIndex(2, 0), matrix.m20());
|
||||
buffer.put(bufferIndex(2, 1), matrix.m21());
|
||||
buffer.put(bufferIndex(2, 2), matrix.m22());
|
||||
buffer.put(bufferIndex(2, 3), matrix.m23());
|
||||
buffer.put(bufferIndex(3, 0), matrix.m30());
|
||||
buffer.put(bufferIndex(3, 1), matrix.m31());
|
||||
buffer.put(bufferIndex(3, 2), matrix.m32());
|
||||
buffer.put(bufferIndex(3, 3), matrix.m33());
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static final Direction[] directions;
|
||||
static final EDhDirection[] lodDirections;
|
||||
static
|
||||
{
|
||||
EDhDirection[] lodDirs = EDhDirection.values();
|
||||
directions = new Direction[lodDirs.length];
|
||||
lodDirections = new EDhDirection[lodDirs.length];
|
||||
for (EDhDirection lodDir : lodDirs)
|
||||
{
|
||||
Direction dir;
|
||||
switch (lodDir.name().toUpperCase())
|
||||
{
|
||||
case "DOWN":
|
||||
dir = Direction.DOWN;
|
||||
break;
|
||||
case "UP":
|
||||
dir = Direction.UP;
|
||||
break;
|
||||
case "NORTH":
|
||||
dir = Direction.NORTH;
|
||||
break;
|
||||
case "SOUTH":
|
||||
dir = Direction.SOUTH;
|
||||
break;
|
||||
case "WEST":
|
||||
dir = Direction.WEST;
|
||||
break;
|
||||
case "EAST":
|
||||
dir = Direction.EAST;
|
||||
break;
|
||||
default:
|
||||
dir = null;
|
||||
break;
|
||||
}
|
||||
|
||||
if (dir == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Invalid direction on init mapping: " + lodDir);
|
||||
}
|
||||
directions[lodDir.ordinal()] = dir;
|
||||
lodDirections[dir.ordinal()] = lodDir;
|
||||
}
|
||||
}
|
||||
|
||||
public static BlockPos Convert(DhBlockPos wrappedPos)
|
||||
{
|
||||
return new BlockPos(wrappedPos.x, wrappedPos.y, wrappedPos.z);
|
||||
}
|
||||
public static ChunkPos Convert(DhChunkPos wrappedPos)
|
||||
{
|
||||
return new ChunkPos(wrappedPos.x, wrappedPos.z);
|
||||
}
|
||||
|
||||
public static Direction Convert(EDhDirection lodDirection)
|
||||
{
|
||||
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));
|
||||
}
|
||||
|
||||
}
|
||||
+16
-9
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
* 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
|
||||
@@ -16,10 +16,11 @@
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.common.wrappers;
|
||||
|
||||
import com.seibel.lod.core.wrapperInterfaces.IVersionConstants;
|
||||
package com.seibel.distanthorizons.common.wrappers;
|
||||
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
|
||||
import net.minecraft.SharedConstants;
|
||||
import net.minecraft.client.Minecraft;
|
||||
|
||||
/**
|
||||
@@ -42,21 +43,27 @@ public class VersionConstants implements IVersionConstants
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getWorldGenerationCountPerThread()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isVanillaRenderedChunkSquare()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getMinecraftVersion() {
|
||||
public String getMinecraftVersion()
|
||||
{
|
||||
#if MC_VER < MC_1_19_2
|
||||
return Minecraft.getInstance().getGame().getVersion().getId();
|
||||
#else
|
||||
return SharedConstants.getCurrentVersion().getId();
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,368 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import com.seibel.distanthorizons.api.interfaces.block.IDhApiBiomeWrapper;
|
||||
import com.seibel.distanthorizons.api.interfaces.block.IDhApiBlockStateWrapper;
|
||||
import com.seibel.distanthorizons.api.interfaces.override.worldGenerator.IDhApiWorldGenerator;
|
||||
import com.seibel.distanthorizons.api.interfaces.world.IDhApiLevelWrapper;
|
||||
import com.seibel.distanthorizons.api.interfaces.factories.IDhApiWrapperFactory;
|
||||
import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||
import com.seibel.distanthorizons.core.level.IDhLevel;
|
||||
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.block.IBlockStateWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvironmentWrapper;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
#if MC_VER > MC_1_17_1
|
||||
import net.minecraft.core.Holder;
|
||||
#endif
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.LevelReader;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
* This handles creating abstract wrapper objects.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 2022-12-5
|
||||
*/
|
||||
public class WrapperFactory implements IWrapperFactory
|
||||
{
|
||||
public static final WrapperFactory INSTANCE = new WrapperFactory();
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// core methods //
|
||||
//==============//
|
||||
|
||||
@Override
|
||||
public AbstractBatchGenerationEnvironmentWrapper createBatchGenerator(IDhLevel targetLevel)
|
||||
{
|
||||
if (targetLevel instanceof IDhServerLevel)
|
||||
{
|
||||
return new BatchGenerationEnvironment((IDhServerLevel) targetLevel);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalArgumentException("The target level must be a server-side level.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
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
|
||||
public IBlockStateWrapper deserializeBlockStateWrapper(String str, ILevelWrapper levelWrapper) throws IOException { return BlockStateWrapper.deserialize(str, levelWrapper); }
|
||||
@Override
|
||||
public IBlockStateWrapper getAirBlockStateWrapper() { return BlockStateWrapper.AIR; }
|
||||
|
||||
@Override
|
||||
public HashSet<IBlockStateWrapper> getRendererIgnoredBlocks(ILevelWrapper levelWrapper) { return BlockStateWrapper.getRendererIgnoredBlocks(levelWrapper); }
|
||||
|
||||
|
||||
/**
|
||||
* Note: when this is updated for different MC versions, make sure you also update the documentation in
|
||||
* {@link IDhApiWorldGenerator#generateChunks} and the type list in {@link WrapperFactory#createChunkWrapperErrorMessage}. <br><br>
|
||||
*
|
||||
* For full method documentation please see: {@link IWrapperFactory#createChunkWrapper}
|
||||
*
|
||||
* @see IWrapperFactory#createChunkWrapper
|
||||
*/
|
||||
public IChunkWrapper createChunkWrapper(Object[] objectArray) throws ClassCastException
|
||||
{
|
||||
if (objectArray.length == 1 && objectArray[0] instanceof IChunkWrapper)
|
||||
{
|
||||
try
|
||||
{
|
||||
// this path should only happen when called by Distant Horizons code
|
||||
// API implementors should never hit this path
|
||||
return (IChunkWrapper) objectArray[0];
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ClassCastException(createChunkWrapperErrorMessage(objectArray));
|
||||
}
|
||||
}
|
||||
|
||||
#if MC_VER <= MC_1_21
|
||||
else if (objectArray.length == 2)
|
||||
{
|
||||
// correct number of parameters from the API
|
||||
|
||||
// chunk
|
||||
if (!(objectArray[0] instanceof ChunkAccess))
|
||||
{
|
||||
throw new ClassCastException(createChunkWrapperErrorMessage(objectArray));
|
||||
}
|
||||
ChunkAccess chunk = (ChunkAccess) objectArray[0];
|
||||
|
||||
// level / light source
|
||||
if (!(objectArray[1] instanceof Level))
|
||||
{
|
||||
throw new ClassCastException(createChunkWrapperErrorMessage(objectArray));
|
||||
}
|
||||
// the level is needed for the DH level wrapper...
|
||||
Level level = (Level) objectArray[1];
|
||||
// ...the LevelReader is needed for chunk lighting
|
||||
LevelReader lightSource = level;
|
||||
|
||||
|
||||
// level wrapper
|
||||
ILevelWrapper levelWrapper;
|
||||
if (level instanceof ServerLevel)
|
||||
{
|
||||
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);
|
||||
}
|
||||
// incorrect number of parameters from the API
|
||||
else
|
||||
{
|
||||
throw new ClassCastException(createChunkWrapperErrorMessage(objectArray));
|
||||
}
|
||||
#else
|
||||
// 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,
|
||||
* make sure you also update the documentation in {@link IDhApiWorldGenerator#generateChunks}.
|
||||
*/
|
||||
private static String createChunkWrapperErrorMessage(Object[] objectArray)
|
||||
{
|
||||
String[] expectedClassNames;
|
||||
|
||||
#if MC_VER <= MC_1_21
|
||||
expectedClassNames = new String[]
|
||||
{
|
||||
ChunkAccess.class.getName(),
|
||||
ServerLevel.class.getName() + "] or [" + ClientLevel.class.getName()
|
||||
};
|
||||
#else
|
||||
// See preprocessor comment in createChunkWrapper() for full documentation
|
||||
not implemented for this version of Minecraft!
|
||||
#endif
|
||||
|
||||
return createWrapperErrorMessage("Chunk wrapper", expectedClassNames, objectArray);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// api methods //
|
||||
//=============//
|
||||
|
||||
// documentation should be in the API interface
|
||||
|
||||
public IDhApiBiomeWrapper getBiomeWrapper(Object[] objectArray, IDhApiLevelWrapper levelWrapper)
|
||||
{
|
||||
// confirm the API level wrapper is also a Core wrapper
|
||||
if (!(levelWrapper instanceof ILevelWrapper))
|
||||
{
|
||||
throw new ClassCastException("Unable to cast... only DH provided IDhApiLevelWrapper's can be used."); // TODO
|
||||
}
|
||||
ILevelWrapper coreLevelWrapper = (ILevelWrapper) levelWrapper;
|
||||
|
||||
|
||||
|
||||
#if MC_VER < MC_1_20_4
|
||||
if (objectArray.length != 1)
|
||||
{
|
||||
throw new ClassCastException(createBiomeWrapperErrorMessage(objectArray));
|
||||
}
|
||||
#endif
|
||||
|
||||
#if MC_VER < MC_1_18_2
|
||||
if (!(objectArray[0] instanceof Biome))
|
||||
{
|
||||
throw new ClassCastException(createBiomeWrapperErrorMessage(objectArray));
|
||||
}
|
||||
|
||||
Biome biome = (Biome) objectArray[0];
|
||||
return BiomeWrapper.getBiomeWrapper(biome, coreLevelWrapper);
|
||||
#elif MC_VER <= MC_1_21
|
||||
if (!(objectArray[0] instanceof Holder) || !(((Holder<?>) objectArray[0]).value() instanceof Biome))
|
||||
{
|
||||
throw new ClassCastException(createBiomeWrapperErrorMessage(objectArray));
|
||||
}
|
||||
|
||||
Holder<Biome> biomeHolder = (Holder<Biome>) objectArray[0];
|
||||
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
|
||||
}
|
||||
/**
|
||||
* Note: when this is updated for different MC versions,
|
||||
* make sure you also update the documentation in {@link IDhApiWrapperFactory#getBiomeWrapper}.
|
||||
*/
|
||||
private static String createBiomeWrapperErrorMessage(Object[] objectArray)
|
||||
{
|
||||
String[] expectedClassNames;
|
||||
|
||||
#if MC_VER < MC_1_18_2
|
||||
expectedClassNames = new String[] { Biome.class.getName() };
|
||||
#elif MC_VER <= MC_1_21
|
||||
expectedClassNames = new String[] { Holder.class.getName()+"<"+Biome.class.getName()+">" };
|
||||
#else
|
||||
// See preprocessor comment in createChunkWrapper() for full documentation
|
||||
not implemented for this version of Minecraft!
|
||||
#endif
|
||||
|
||||
return createWrapperErrorMessage("Biome wrapper", expectedClassNames, objectArray);
|
||||
}
|
||||
|
||||
public IDhApiBlockStateWrapper getBlockStateWrapper(Object[] objectArray, IDhApiLevelWrapper levelWrapper)
|
||||
{
|
||||
// confirm the API level wrapper is also a Core wrapper
|
||||
if (!(levelWrapper instanceof ILevelWrapper))
|
||||
{
|
||||
throw new ClassCastException("Unable to cast... only DH provided IDhApiLevelWrapper's can be used."); // TODO
|
||||
}
|
||||
ILevelWrapper coreLevelWrapper = (ILevelWrapper) levelWrapper;
|
||||
|
||||
|
||||
|
||||
#if MC_VER <= MC_1_21
|
||||
if (objectArray.length != 1)
|
||||
{
|
||||
throw new ClassCastException(createBlockStateWrapperErrorMessage(objectArray));
|
||||
}
|
||||
if (!(objectArray[0] instanceof BlockState))
|
||||
{
|
||||
throw new ClassCastException(createBlockStateWrapperErrorMessage(objectArray));
|
||||
}
|
||||
|
||||
BlockState blockState = (BlockState) objectArray[0];
|
||||
return BlockStateWrapper.fromBlockState(blockState, 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
|
||||
}
|
||||
/**
|
||||
* Note: when this is updated for different MC versions,
|
||||
* make sure you also update the documentation in {@link IDhApiWrapperFactory#getBlockStateWrapper}.
|
||||
*/
|
||||
private static String createBlockStateWrapperErrorMessage(Object[] objectArray)
|
||||
{
|
||||
String[] expectedClassNames;
|
||||
|
||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||
expectedClassNames = new String[] { Biome.class.getName() };
|
||||
#elif MC_VER <= MC_1_21
|
||||
expectedClassNames = new String[] { Holder.class.getName()+"<"+Biome.class.getName()+">" };
|
||||
#else
|
||||
// See preprocessor comment in createChunkWrapper() for full documentation
|
||||
not implemented for this version of Minecraft!
|
||||
#endif
|
||||
|
||||
return createWrapperErrorMessage("BlockState wrapper", expectedClassNames, objectArray);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// helper methods //
|
||||
//================//
|
||||
|
||||
private static String createWrapperErrorMessage(String wrapperName, String[] expectedClassNames, Object[] objectArray)
|
||||
{
|
||||
// error header
|
||||
StringBuilder message = new StringBuilder(
|
||||
wrapperName + " creation failed. \n" +
|
||||
"Expected object array parameters: \n");
|
||||
|
||||
|
||||
// expected parameters
|
||||
for (String expectedClassName : expectedClassNames)
|
||||
{
|
||||
message.append("[").append(expectedClassName).append("], \n");
|
||||
}
|
||||
|
||||
|
||||
// given parameters
|
||||
if (objectArray.length != 0)
|
||||
{
|
||||
message.append("Given parameters: ");
|
||||
for (Object obj : objectArray)
|
||||
{
|
||||
String objClassName = (obj != null) ? obj.getClass().getName() : "NULL";
|
||||
message.append("[").append(objClassName).append("], ");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
message.append(" No parameters given.");
|
||||
}
|
||||
|
||||
|
||||
return message.toString();
|
||||
}
|
||||
|
||||
}
|
||||
+354
@@ -0,0 +1,354 @@
|
||||
/*
|
||||
* 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 java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
||||
|
||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||
import net.minecraft.core.Registry;
|
||||
#elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
import net.minecraft.data.BuiltinRegistries;
|
||||
#else
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
#endif
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
#if MC_VER >= MC_1_18_2
|
||||
import net.minecraft.world.level.biome.Biomes;
|
||||
#endif
|
||||
|
||||
|
||||
/** This class wraps the minecraft BlockPos.Mutable (and BlockPos) class */
|
||||
public class BiomeWrapper implements IBiomeWrapper
|
||||
{
|
||||
// must be defined before AIR, otherwise a null pointer will be thrown
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
|
||||
#if MC_VER < MC_1_18_2
|
||||
public static final ConcurrentMap<Biome, BiomeWrapper> WRAPPER_BY_BIOME = new ConcurrentHashMap<>();
|
||||
#else
|
||||
public static final ConcurrentMap<Holder<Biome>, BiomeWrapper> WRAPPER_BY_BIOME = new ConcurrentHashMap<>();
|
||||
#endif
|
||||
|
||||
public static final ConcurrentHashMap<String, BiomeWrapper> WRAPPER_BY_RESOURCE_LOCATION = new ConcurrentHashMap<>();
|
||||
|
||||
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 */
|
||||
private static final HashSet<String> brokenResourceLocationStrings = new HashSet<>();
|
||||
|
||||
/**
|
||||
* Only display this warning once, otherwise the log may be spammed <br>
|
||||
* This is a known issue when joining Hypixel.
|
||||
*/
|
||||
private static boolean emptyStringWarningLogged = false;
|
||||
private static boolean emptyLevelSerializeFailLogged = false;
|
||||
|
||||
|
||||
|
||||
// properties //
|
||||
|
||||
#if MC_VER < MC_1_18_2
|
||||
public final Biome biome;
|
||||
#else
|
||||
public final Holder<Biome> biome;
|
||||
#endif
|
||||
|
||||
/** technically final, but since it requires a method call to generate it can't be marked as such */
|
||||
private String serialString;
|
||||
private final int hashCode;
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// constructors //
|
||||
//==============//
|
||||
|
||||
static public IBiomeWrapper getBiomeWrapper(#if MC_VER < MC_1_18_2 Biome #else Holder<Biome> #endif biome, ILevelWrapper levelWrapper)
|
||||
{
|
||||
if (biome == null)
|
||||
{
|
||||
return EMPTY_WRAPPER;
|
||||
}
|
||||
|
||||
|
||||
if (WRAPPER_BY_BIOME.containsKey(biome))
|
||||
{
|
||||
return WRAPPER_BY_BIOME.get(biome);
|
||||
}
|
||||
else
|
||||
{
|
||||
BiomeWrapper newWrapper = new BiomeWrapper(biome, levelWrapper);
|
||||
WRAPPER_BY_BIOME.put(biome, newWrapper);
|
||||
return newWrapper;
|
||||
}
|
||||
}
|
||||
private BiomeWrapper(#if MC_VER < MC_1_18_2 Biome #else Holder<Biome> #endif biome, ILevelWrapper levelWrapper)
|
||||
{
|
||||
this.biome = biome;
|
||||
this.serialString = this.serialize(levelWrapper);
|
||||
this.hashCode = Objects.hash(this.serialString);
|
||||
|
||||
//LOGGER.trace("Created BiomeWrapper ["+this.serialString+"] for ["+biome+"]");
|
||||
}
|
||||
|
||||
/** should only be used to create {@link BiomeWrapper#EMPTY_WRAPPER} */
|
||||
private BiomeWrapper()
|
||||
{
|
||||
this.biome = null;
|
||||
this.serialString = EMPTY_BIOME_STRING;
|
||||
this.hashCode = Objects.hash(this.serialString);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// methods //
|
||||
//=========//
|
||||
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
if (this == EMPTY_WRAPPER)
|
||||
{
|
||||
return EMPTY_BIOME_STRING;
|
||||
}
|
||||
|
||||
#if MC_VER < MC_1_18_2
|
||||
return biome.toString();
|
||||
#else
|
||||
return this.biome.unwrapKey().orElse(Biomes.THE_VOID).registry().toString();
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else if (obj == null || this.getClass() != obj.getClass())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
BiomeWrapper that = (BiomeWrapper) obj;
|
||||
// the serialized value is used so we can test the contents instead of the references
|
||||
return Objects.equals(this.getSerialString(), that.getSerialString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() { return this.hashCode; }
|
||||
|
||||
@Override
|
||||
public String getSerialString() { return this.serialString; }
|
||||
|
||||
@Override
|
||||
public Object getWrappedMcObject() { return this.biome; }
|
||||
|
||||
@Override
|
||||
public String toString() { return this.getSerialString(); }
|
||||
|
||||
|
||||
|
||||
//=======================//
|
||||
// serialization methods //
|
||||
//=======================//
|
||||
|
||||
public String serialize(ILevelWrapper levelWrapper)
|
||||
{
|
||||
if (this.biome == null)
|
||||
{
|
||||
return EMPTY_BIOME_STRING;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// we can't generate a serial string if the level is null
|
||||
if (levelWrapper == null)
|
||||
{
|
||||
if (!emptyLevelSerializeFailLogged)
|
||||
{
|
||||
emptyLevelSerializeFailLogged = true;
|
||||
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_BIOME_STRING;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// generate the serial string //
|
||||
|
||||
Level level = (Level)levelWrapper.getWrappedMcObject();
|
||||
net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
|
||||
|
||||
ResourceLocation resourceLocation;
|
||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||
resourceLocation = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).getKey(this.biome);
|
||||
#elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
|
||||
resourceLocation = registryAccess.registryOrThrow(Registry.BIOME_REGISTRY).getKey(this.biome.value());
|
||||
#else
|
||||
resourceLocation = registryAccess.registryOrThrow(Registries.BIOME).getKey(this.biome.value());
|
||||
#endif
|
||||
|
||||
if (resourceLocation == null)
|
||||
{
|
||||
String biomeName;
|
||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||
biomeName = this.biome.toString();
|
||||
#else
|
||||
biomeName = this.biome.value().toString();
|
||||
#endif
|
||||
|
||||
LOGGER.warn("unable to serialize: " + biomeName);
|
||||
// shouldn't normally happen, but just in case
|
||||
this.serialString = "";
|
||||
}
|
||||
else
|
||||
{
|
||||
this.serialString = resourceLocation.getNamespace() + ":" + resourceLocation.getPath();
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
// we need the final string for the concurrent hash map later
|
||||
final String finalResourceStateString = resourceLocationString;
|
||||
|
||||
if (resourceLocationString.equals(EMPTY_BIOME_STRING))
|
||||
{
|
||||
if (!emptyStringWarningLogged)
|
||||
{
|
||||
emptyStringWarningLogged = true;
|
||||
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;
|
||||
}
|
||||
else if (resourceLocationString.trim().isEmpty() || resourceLocationString.equals(""))
|
||||
{
|
||||
LOGGER.warn("Null biome string deserialized.");
|
||||
return EMPTY_WRAPPER;
|
||||
}
|
||||
|
||||
if (WRAPPER_BY_RESOURCE_LOCATION.containsKey(finalResourceStateString))
|
||||
{
|
||||
return WRAPPER_BY_RESOURCE_LOCATION.get(finalResourceStateString);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// if no wrapper is found, default to the empty wrapper
|
||||
BiomeWrapper foundWrapper = EMPTY_WRAPPER;
|
||||
try
|
||||
{
|
||||
// parse the resource location
|
||||
int separatorIndex = resourceLocationString.indexOf(":");
|
||||
if (separatorIndex == -1)
|
||||
{
|
||||
throw new IOException("Unable to parse resource location string: [" + resourceLocationString + "].");
|
||||
}
|
||||
|
||||
ResourceLocation resourceLocation;
|
||||
try
|
||||
{
|
||||
#if MC_VER < MC_1_21
|
||||
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);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
WRAPPER_BY_RESOURCE_LOCATION.putIfAbsent(finalResourceStateString, foundWrapper);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+618
@@ -0,0 +1,618 @@
|
||||
/*
|
||||
* 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.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
|
||||
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.SoundType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.EmptyBlockGetter;
|
||||
#elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.world.level.EmptyBlockGetter;
|
||||
#else
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.world.level.EmptyBlockGetter;
|
||||
#endif
|
||||
|
||||
public class BlockStateWrapper implements IBlockStateWrapper
|
||||
{
|
||||
/** example "minecraft:water" */
|
||||
public static final String RESOURCE_LOCATION_SEPARATOR = ":";
|
||||
/** example "minecraft:water_STATE_{level:0}" */
|
||||
public static final String STATE_STRING_SEPARATOR = "_STATE_";
|
||||
|
||||
|
||||
// must be defined before AIR, otherwise a null pointer will be thrown
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
|
||||
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 BlockStateWrapper AIR = new BlockStateWrapper(null, null);
|
||||
|
||||
public static final String DIRT_RESOURCE_LOCATION_STRING = "minecraft:dirt";
|
||||
|
||||
// TODO: Make this changeable through the config
|
||||
public static final String[] RENDERER_IGNORED_BLOCKS_RESOURCE_LOCATIONS = { AIR_STRING, "minecraft:barrier", "minecraft:structure_void", "minecraft:light", "minecraft:tripwire" };
|
||||
public static HashSet<IBlockStateWrapper> rendererIgnoredBlocks = null;
|
||||
|
||||
/** keep track of broken blocks so we don't log every time */
|
||||
private static final HashSet<ResourceLocation> BrokenResourceLocations = new HashSet<>();
|
||||
|
||||
|
||||
|
||||
// properties //
|
||||
|
||||
public final BlockState blockState;
|
||||
/** technically final, but since it requires a method call to generate it can't be marked as such */
|
||||
private String serialString;
|
||||
private final int hashCode;
|
||||
/**
|
||||
* Cached opacity value, -1 if not populated. <br>
|
||||
* Should be between {@link IBlockStateWrapper#FULLY_OPAQUE} and {@link IBlockStateWrapper#FULLY_OPAQUE}
|
||||
*/
|
||||
private int opacity = -1;
|
||||
/** used by the Iris shader mod to determine how each LOD should be rendered */
|
||||
private byte irisBlockMaterialId = 0;
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// constructors //
|
||||
//==============//
|
||||
|
||||
public static BlockStateWrapper fromBlockState(BlockState blockState, ILevelWrapper levelWrapper)
|
||||
{
|
||||
if (blockState == null || blockState.isAir())
|
||||
{
|
||||
return AIR;
|
||||
}
|
||||
|
||||
|
||||
if (WRAPPER_BY_BLOCK_STATE.containsKey(blockState))
|
||||
{
|
||||
return WRAPPER_BY_BLOCK_STATE.get(blockState);
|
||||
}
|
||||
else
|
||||
{
|
||||
BlockStateWrapper newWrapper = new BlockStateWrapper(blockState, levelWrapper);
|
||||
WRAPPER_BY_BLOCK_STATE.put(blockState, newWrapper);
|
||||
return newWrapper;
|
||||
}
|
||||
}
|
||||
|
||||
private BlockStateWrapper(BlockState blockState, ILevelWrapper levelWrapper)
|
||||
{
|
||||
this.blockState = blockState;
|
||||
this.serialString = this.serialize(levelWrapper);
|
||||
this.hashCode = Objects.hash(this.serialString);
|
||||
this.irisBlockMaterialId = this.calculateIrisBlockMaterialId();
|
||||
|
||||
//LOGGER.trace("Created BlockStateWrapper ["+this.serialString+"] for ["+blockState+"] with material ID ["+this.irisBlockMaterialId+"]");
|
||||
}
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// helper methods //
|
||||
//================//
|
||||
|
||||
/**
|
||||
* 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> getRendererIgnoredBlocks(ILevelWrapper levelWrapper)
|
||||
{
|
||||
// use the cached version if possible
|
||||
if (rendererIgnoredBlocks != null)
|
||||
{
|
||||
return rendererIgnoredBlocks;
|
||||
}
|
||||
|
||||
|
||||
// deserialize each of the given resource locations
|
||||
HashSet<IBlockStateWrapper> blockStateWrappers = new HashSet<>();
|
||||
for (String blockResourceLocation : RENDERER_IGNORED_BLOCKS_RESOURCE_LOCATIONS)
|
||||
{
|
||||
try
|
||||
{
|
||||
BlockStateWrapper DefaultBlockStateToIgnore = (BlockStateWrapper) deserialize(blockResourceLocation, levelWrapper);
|
||||
blockStateWrappers.add(DefaultBlockStateToIgnore);
|
||||
|
||||
if (DefaultBlockStateToIgnore == AIR)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// add all possible blockstates (to account for light blocks with different light values and such)
|
||||
List<BlockState> blockStatesToIgnore = DefaultBlockStateToIgnore.blockState.getBlock().getStateDefinition().getPossibleStates();
|
||||
for (BlockState blockState : blockStatesToIgnore)
|
||||
{
|
||||
BlockStateWrapper newBlockToIgnore = BlockStateWrapper.fromBlockState(blockState, levelWrapper);
|
||||
blockStateWrappers.add(newBlockToIgnore);
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
LOGGER.warn("Unable to deserialize rendererIgnoredBlock with the resource location: ["+blockResourceLocation+"]. Error: "+e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
rendererIgnoredBlocks = blockStateWrappers;
|
||||
return rendererIgnoredBlocks;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=================//
|
||||
// wrapper methods //
|
||||
//=================//
|
||||
|
||||
@Override
|
||||
public int getOpacity()
|
||||
{
|
||||
// use the cached opacity value if possible
|
||||
if (this.opacity != -1)
|
||||
{
|
||||
return this.opacity;
|
||||
}
|
||||
|
||||
|
||||
// this method isn't perfect, but works well enough for our use case
|
||||
int opacity;
|
||||
if (this.isAir())
|
||||
{
|
||||
opacity = FULLY_TRANSPARENT;
|
||||
}
|
||||
else if (this.isLiquid() && !this.blockState.canOcclude())
|
||||
{
|
||||
// probably not a waterlogged block (which should block light entirely)
|
||||
|
||||
// +1 to indicate that the block is translucent (in between transparent and opaque)
|
||||
opacity = FULLY_TRANSPARENT + 1;
|
||||
}
|
||||
else if (this.blockState.propagatesSkylightDown(EmptyBlockGetter.INSTANCE, BlockPos.ZERO))
|
||||
{
|
||||
opacity = FULLY_TRANSPARENT;
|
||||
}
|
||||
else
|
||||
{
|
||||
// default for all other blocks
|
||||
opacity = FULLY_OPAQUE;
|
||||
}
|
||||
|
||||
|
||||
this.opacity = opacity;
|
||||
return this.opacity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightEmission() { return (this.blockState != null) ? this.blockState.getLightEmission() : 0; }
|
||||
|
||||
@Override
|
||||
public String getSerialString() { return this.serialString; }
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (obj == null || this.getClass() != obj.getClass())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
BlockStateWrapper that = (BlockStateWrapper) obj;
|
||||
// the serialized value is used so we can test the contents instead of the references
|
||||
return Objects.equals(this.getSerialString(), that.getSerialString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() { return this.hashCode; }
|
||||
|
||||
|
||||
@Override
|
||||
public Object getWrappedMcObject() { return this.blockState; }
|
||||
|
||||
@Override
|
||||
public boolean isAir() { return this.isAir(this.blockState); }
|
||||
public boolean isAir(BlockState blockState) { return blockState == null || blockState.isAir(); }
|
||||
|
||||
@Override
|
||||
public boolean isSolid()
|
||||
{
|
||||
#if MC_VER < MC_1_20_1
|
||||
return this.blockState.getMaterial().isSolid();
|
||||
#else
|
||||
return !this.blockState.getCollisionShape(EmptyBlockGetter.INSTANCE, BlockPos.ZERO).isEmpty();
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLiquid()
|
||||
{
|
||||
if (this.isAir())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#if MC_VER < MC_1_20_1
|
||||
return this.blockState.getMaterial().isLiquid() || !this.blockState.getFluidState().isEmpty();
|
||||
#else
|
||||
return !this.blockState.getFluidState().isEmpty();
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte getIrisBlockMaterialId() { return this.irisBlockMaterialId; }
|
||||
|
||||
@Override
|
||||
public String toString() { return this.getSerialString(); }
|
||||
|
||||
|
||||
|
||||
//=======================//
|
||||
// serialization methods //
|
||||
//=======================//
|
||||
|
||||
private String serialize(ILevelWrapper levelWrapper)
|
||||
{
|
||||
if (this.blockState == null)
|
||||
{
|
||||
return AIR_STRING;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// older versions of MC have a static registry
|
||||
#if MC_VER > MC_1_17_1
|
||||
Level level = (Level)levelWrapper.getWrappedMcObject();
|
||||
net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
|
||||
#endif
|
||||
|
||||
ResourceLocation resourceLocation;
|
||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||
resourceLocation = Registry.BLOCK.getKey(this.blockState.getBlock());
|
||||
#elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
|
||||
resourceLocation = registryAccess.registryOrThrow(Registry.BLOCK_REGISTRY).getKey(this.blockState.getBlock());
|
||||
#else
|
||||
resourceLocation = registryAccess.registryOrThrow(Registries.BLOCK).getKey(this.blockState.getBlock());
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
if (resourceLocation == null)
|
||||
{
|
||||
LOGGER.warn("No ResourceLocation found, unable to serialize: " + this.blockState);
|
||||
return AIR_STRING;
|
||||
}
|
||||
|
||||
this.serialString = resourceLocation.getNamespace() + RESOURCE_LOCATION_SEPARATOR + resourceLocation.getPath()
|
||||
+ STATE_STRING_SEPARATOR + serializeBlockStateProperties(this.blockState);
|
||||
|
||||
return this.serialString;
|
||||
}
|
||||
|
||||
|
||||
/** will only work if a level is currently loaded */
|
||||
public static IBlockStateWrapper deserialize(String resourceStateString, ILevelWrapper levelWrapper) throws IOException
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
// attempt to use the existing wrapper
|
||||
if (WRAPPER_BY_RESOURCE_LOCATION.containsKey(finalResourceStateString))
|
||||
{
|
||||
return WRAPPER_BY_RESOURCE_LOCATION.get(finalResourceStateString);
|
||||
}
|
||||
|
||||
|
||||
|
||||
// if no wrapper is found, default to air
|
||||
BlockStateWrapper foundWrapper = AIR;
|
||||
try
|
||||
{
|
||||
// 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
|
||||
blockStatePropertiesString = resourceStateString.substring(stateSeparatorIndex + STATE_STRING_SEPARATOR.length());
|
||||
resourceStateString = resourceStateString.substring(0, stateSeparatorIndex);
|
||||
}
|
||||
|
||||
// parse the resource location
|
||||
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
|
||||
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 get the BlockState from all possible BlockStates
|
||||
try
|
||||
{
|
||||
|
||||
#if MC_VER > MC_1_17_1
|
||||
// use the given level if possible, otherwise try using the currently loaded one
|
||||
Level level = (levelWrapper != null ? (Level) levelWrapper.getWrappedMcObject() : null);
|
||||
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
|
||||
if (!BrokenResourceLocations.contains(resourceLocation))
|
||||
{
|
||||
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.");
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
/** used to compare and save BlockStates based on their properties */
|
||||
private static String serializeBlockStateProperties(BlockState blockState)
|
||||
{
|
||||
// get the property list for this block (doesn't contain this block state's values, just the names and possible values)
|
||||
java.util.Collection<net.minecraft.world.level.block.state.properties.Property<?>> blockPropertyCollection = blockState.getProperties();
|
||||
|
||||
// alphabetically sort the list so they are always in the same order
|
||||
List<net.minecraft.world.level.block.state.properties.Property<?>> sortedBlockPropteryList = new ArrayList<>(blockPropertyCollection);
|
||||
sortedBlockPropteryList.sort((a, b) -> a.getName().compareTo(b.getName()));
|
||||
|
||||
|
||||
StringBuilder stringBuilder = new StringBuilder();
|
||||
for (net.minecraft.world.level.block.state.properties.Property<?> property : sortedBlockPropteryList)
|
||||
{
|
||||
String propertyName = property.getName();
|
||||
|
||||
String value = "NULL";
|
||||
if (blockState.hasProperty(property))
|
||||
{
|
||||
value = blockState.getValue(property).toString();
|
||||
}
|
||||
|
||||
stringBuilder.append("{");
|
||||
stringBuilder.append(propertyName).append(RESOURCE_LOCATION_SEPARATOR).append(value);
|
||||
stringBuilder.append("}");
|
||||
}
|
||||
|
||||
return stringBuilder.toString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// Iris methods //
|
||||
//==============//
|
||||
|
||||
private byte calculateIrisBlockMaterialId()
|
||||
{
|
||||
if (this.blockState == null)
|
||||
{
|
||||
return IrisBlockMaterial.AIR;
|
||||
}
|
||||
|
||||
|
||||
String serialString = this.getSerialString().toLowerCase();
|
||||
|
||||
if (this.blockState.is(BlockTags.LEAVES)
|
||||
|| serialString.contains("bamboo")
|
||||
|| serialString.contains("cactus")
|
||||
|| serialString.contains("chorus_flower")
|
||||
|| serialString.contains("mushroom")
|
||||
)
|
||||
{
|
||||
return IrisBlockMaterial.LEAVES;
|
||||
}
|
||||
else if (this.blockState.is(Blocks.LAVA))
|
||||
{
|
||||
return IrisBlockMaterial.LAVA;
|
||||
}
|
||||
else if (this.isLiquid() || this.blockState.is(Blocks.WATER))
|
||||
{
|
||||
return IrisBlockMaterial.WATER;
|
||||
}
|
||||
else if (this.blockState.getSoundType() == SoundType.WOOD
|
||||
|| serialString.contains("root")
|
||||
#if MC_VER >= MC_1_19_4
|
||||
|| this.blockState.getSoundType() == SoundType.CHERRY_WOOD
|
||||
#endif
|
||||
)
|
||||
{
|
||||
return IrisBlockMaterial.WOOD;
|
||||
}
|
||||
else if (this.blockState.getSoundType() == SoundType.METAL
|
||||
#if MC_VER >= MC_1_19_2
|
||||
|| this.blockState.getSoundType() == SoundType.COPPER
|
||||
#endif
|
||||
#if MC_VER >= MC_1_20_4
|
||||
|| this.blockState.getSoundType() == SoundType.COPPER_BULB
|
||||
|| this.blockState.getSoundType() == SoundType.COPPER_GRATE
|
||||
#endif
|
||||
)
|
||||
{
|
||||
return IrisBlockMaterial.METAL;
|
||||
}
|
||||
else if (serialString.contains("grass_block"))
|
||||
{
|
||||
return IrisBlockMaterial.GRASS;
|
||||
}
|
||||
else if (
|
||||
serialString.contains("dirt")
|
||||
|| serialString.contains("gravel")
|
||||
|| serialString.contains("mud")
|
||||
|| serialString.contains("podzol")
|
||||
|| serialString.contains("mycelium")
|
||||
)
|
||||
{
|
||||
return IrisBlockMaterial.DIRT;
|
||||
}
|
||||
#if MC_VER >= MC_1_17_1
|
||||
else if (this.blockState.getSoundType() == SoundType.DEEPSLATE
|
||||
|| this.blockState.getSoundType() == SoundType.DEEPSLATE_BRICKS
|
||||
|| this.blockState.getSoundType() == SoundType.DEEPSLATE_TILES
|
||||
|| this.blockState.getSoundType() == SoundType.POLISHED_DEEPSLATE
|
||||
|| serialString.contains("deepslate") )
|
||||
{
|
||||
return IrisBlockMaterial.DEEPSLATE;
|
||||
}
|
||||
#endif
|
||||
else if (this.serialString.contains("snow"))
|
||||
{
|
||||
return IrisBlockMaterial.SNOW;
|
||||
}
|
||||
else if (serialString.contains("sand"))
|
||||
{
|
||||
return IrisBlockMaterial.SAND;
|
||||
}
|
||||
else if (serialString.contains("terracotta"))
|
||||
{
|
||||
return IrisBlockMaterial.TERRACOTTA;
|
||||
}
|
||||
else if (this.blockState.is(BlockTags.BASE_STONE_NETHER))
|
||||
{
|
||||
return IrisBlockMaterial.NETHER_STONE;
|
||||
}
|
||||
else if (serialString.contains("stone")
|
||||
|| serialString.contains("ore"))
|
||||
{
|
||||
return IrisBlockMaterial.STONE;
|
||||
}
|
||||
else if (this.blockState.getLightEmission() > 0)
|
||||
{
|
||||
return IrisBlockMaterial.ILLUMINATED;
|
||||
}
|
||||
else
|
||||
{
|
||||
return IrisBlockMaterial.UNKOWN;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* 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 net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
|
||||
/**
|
||||
* For wrapping/utilizing around TextureAtlasSprite
|
||||
*
|
||||
* @author Ran
|
||||
*/
|
||||
public class TextureAtlasSpriteWrapper
|
||||
{
|
||||
|
||||
/**
|
||||
* This code is from Minecraft Forge
|
||||
* Which is licensed under the terms of GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* The code has been modified to use TextureAtlasSprite
|
||||
*/
|
||||
public static int getPixelRGBA(TextureAtlasSprite sprite, int frameIndex, int x, int y)
|
||||
{
|
||||
#if MC_VER < MC_1_17_1
|
||||
return sprite.mainImage[0].getPixelRGBA(
|
||||
x + sprite.framesX[frameIndex] * sprite.getWidth(),
|
||||
y + sprite.framesY[frameIndex] * sprite.getHeight());
|
||||
#elif MC_VER < MC_1_19_4
|
||||
if (sprite.animatedTexture != null)
|
||||
{
|
||||
x += sprite.animatedTexture.getFrameX(frameIndex) * sprite.width;
|
||||
y += sprite.animatedTexture.getFrameY(frameIndex) * sprite.height;
|
||||
}
|
||||
return sprite.mainImage[0].getPixelRGBA(x, y);
|
||||
#else
|
||||
if (sprite.contents().animatedTexture != null)
|
||||
{
|
||||
x += sprite.contents().animatedTexture.getFrameX(frameIndex) * sprite.contents().width();
|
||||
y += sprite.contents().animatedTexture.getFrameY(frameIndex) * sprite.contents().width();
|
||||
}
|
||||
return sprite.contents().originalImage.getPixelRGBA(x, y);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+231
@@ -0,0 +1,231 @@
|
||||
/*
|
||||
* 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 net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.level.*;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.lighting.LevelLightEngine;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class TintGetterOverrideFast implements BlockAndTintGetter
|
||||
{
|
||||
LevelReader parent;
|
||||
|
||||
public TintGetterOverrideFast(LevelReader parent)
|
||||
{
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
private Biome _getBiome(BlockPos pos)
|
||||
{
|
||||
#if MC_VER >= MC_1_18_2
|
||||
return parent.getBiome(pos).value();
|
||||
#else
|
||||
return parent.getBiome(pos);
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver) { return colorResolver.getColor(this._getBiome(blockPos), blockPos.getX(), blockPos.getZ()); }
|
||||
|
||||
@Override
|
||||
public float getShade(Direction direction, boolean bl) { return this.parent.getShade(direction, bl); }
|
||||
|
||||
@Override
|
||||
public LevelLightEngine getLightEngine()
|
||||
{
|
||||
return parent.getLightEngine();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBrightness(LightLayer lightLayer, BlockPos blockPos)
|
||||
{
|
||||
return parent.getBrightness(lightLayer, blockPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRawBrightness(BlockPos blockPos, int i)
|
||||
{
|
||||
return parent.getRawBrightness(blockPos, i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSeeSky(BlockPos blockPos)
|
||||
{
|
||||
return parent.canSeeSky(blockPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public BlockEntity getBlockEntity(BlockPos blockPos)
|
||||
{
|
||||
return parent.getBlockEntity(blockPos);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BlockState getBlockState(BlockPos blockPos)
|
||||
{
|
||||
return parent.getBlockState(blockPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidState getFluidState(BlockPos blockPos)
|
||||
{
|
||||
return parent.getFluidState(blockPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightEmission(BlockPos blockPos)
|
||||
{
|
||||
return parent.getLightEmission(blockPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxLightLevel()
|
||||
{
|
||||
return parent.getMaxLightLevel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<BlockState> getBlockStates(AABB aABB)
|
||||
{
|
||||
return parent.getBlockStates(aABB);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockHitResult clip(ClipContext clipContext)
|
||||
{
|
||||
return parent.clip(clipContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public BlockHitResult clipWithInteractionOverride(Vec3 vec3, Vec3 vec32, BlockPos blockPos, VoxelShape voxelShape, BlockState blockState)
|
||||
{
|
||||
return parent.clipWithInteractionOverride(vec3, vec32, blockPos, voxelShape, blockState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getBlockFloorHeight(VoxelShape voxelShape, Supplier<VoxelShape> supplier)
|
||||
{
|
||||
return parent.getBlockFloorHeight(voxelShape, supplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getBlockFloorHeight(BlockPos blockPos)
|
||||
{
|
||||
return parent.getBlockFloorHeight(blockPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxBuildHeight()
|
||||
{
|
||||
return parent.getMaxBuildHeight();
|
||||
}
|
||||
|
||||
#if MC_VER >= MC_1_17_1
|
||||
@Override
|
||||
public <T extends BlockEntity> Optional<T> getBlockEntity(BlockPos blockPos, BlockEntityType<T> blockEntityType)
|
||||
{
|
||||
return parent.getBlockEntity(blockPos, blockEntityType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockHitResult isBlockInLine(ClipBlockStateContext clipBlockStateContext)
|
||||
{
|
||||
return parent.isBlockInLine(clipBlockStateContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight()
|
||||
{
|
||||
return parent.getHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinBuildHeight()
|
||||
{
|
||||
return parent.getMinBuildHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSectionsCount()
|
||||
{
|
||||
return parent.getSectionsCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinSection()
|
||||
{
|
||||
return parent.getMinSection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxSection()
|
||||
{
|
||||
return parent.getMaxSection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOutsideBuildHeight(BlockPos blockPos)
|
||||
{
|
||||
return parent.isOutsideBuildHeight(blockPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOutsideBuildHeight(int i)
|
||||
{
|
||||
return parent.isOutsideBuildHeight(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSectionIndex(int i)
|
||||
{
|
||||
return parent.getSectionIndex(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSectionIndexFromSectionY(int i)
|
||||
{
|
||||
return parent.getSectionIndexFromSectionY(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSectionYFromSectionIndex(int i)
|
||||
{
|
||||
return parent.getSectionYFromSectionIndex(i);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
+178
@@ -0,0 +1,178 @@
|
||||
/*
|
||||
* 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 net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Cursor3D;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.level.*;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.lighting.LevelLightEngine;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class TintGetterOverrideSmooth implements BlockAndTintGetter
|
||||
{
|
||||
LevelReader parent;
|
||||
public int smoothingRange;
|
||||
|
||||
public TintGetterOverrideSmooth(LevelReader parent, int smoothingRange)
|
||||
{
|
||||
this.parent = parent;
|
||||
this.smoothingRange = smoothingRange;
|
||||
}
|
||||
|
||||
private Biome _getBiome(BlockPos pos)
|
||||
{
|
||||
#if MC_VER >= MC_1_18_2
|
||||
return parent.getBiome(pos).value();
|
||||
#else
|
||||
return parent.getBiome(pos);
|
||||
#endif
|
||||
}
|
||||
|
||||
public int calculateBlockTint(BlockPos blockPos, ColorResolver colorResolver)
|
||||
{
|
||||
int i = smoothingRange;
|
||||
if (i == 0)
|
||||
return colorResolver.getColor(_getBiome(blockPos), blockPos.getX(), blockPos.getZ());
|
||||
int j = (i * 2 + 1) * (i * 2 + 1);
|
||||
int k = 0;
|
||||
int l = 0;
|
||||
int m = 0;
|
||||
Cursor3D cursor3D = new Cursor3D(blockPos.getX() - i, blockPos.getY(), blockPos.getZ() - i, blockPos.getX() + i, blockPos.getY(), blockPos.getZ() + i);
|
||||
BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
|
||||
while (cursor3D.advance())
|
||||
{
|
||||
mutableBlockPos.set(cursor3D.nextX(), cursor3D.nextY(), cursor3D.nextZ());
|
||||
int n = colorResolver.getColor(this._getBiome(mutableBlockPos), mutableBlockPos.getX(), mutableBlockPos.getZ());
|
||||
|
||||
k += (n & 0xFF0000) >> 16;
|
||||
l += (n & 0xFF00) >> 8;
|
||||
m += n & 0xFF;
|
||||
}
|
||||
return (k / j & 0xFF) << 16 | (l / j & 0xFF) << 8 | m / j & 0xFF;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver) { return this.calculateBlockTint(blockPos, colorResolver); }
|
||||
|
||||
@Override
|
||||
public float getShade(Direction direction, boolean bl) { return this.parent.getShade(direction, bl); }
|
||||
|
||||
@Override
|
||||
public LevelLightEngine getLightEngine() { return this.parent.getLightEngine(); }
|
||||
|
||||
@Override
|
||||
public int getBrightness(LightLayer lightLayer, BlockPos blockPos) { return this.parent.getBrightness(lightLayer, blockPos); }
|
||||
|
||||
@Override
|
||||
public int getRawBrightness(BlockPos blockPos, int i) { return this.parent.getRawBrightness(blockPos, i); }
|
||||
|
||||
@Override
|
||||
public boolean canSeeSky(BlockPos blockPos) { return this.parent.canSeeSky(blockPos); }
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public BlockEntity getBlockEntity(BlockPos blockPos) { return this.parent.getBlockEntity(blockPos); }
|
||||
|
||||
@Override
|
||||
public BlockState getBlockState(BlockPos blockPos) { return this.parent.getBlockState(blockPos); }
|
||||
|
||||
@Override
|
||||
public FluidState getFluidState(BlockPos blockPos) { return this.parent.getFluidState(blockPos); }
|
||||
|
||||
@Override
|
||||
public int getLightEmission(BlockPos blockPos) { return this.parent.getLightEmission(blockPos); }
|
||||
|
||||
@Override
|
||||
public int getMaxLightLevel() { return this.parent.getMaxLightLevel(); }
|
||||
|
||||
@Override
|
||||
public Stream<BlockState> getBlockStates(AABB aABB) { return this.parent.getBlockStates(aABB); }
|
||||
|
||||
@Override
|
||||
public BlockHitResult clip(ClipContext clipContext) { return this.parent.clip(clipContext); }
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public BlockHitResult clipWithInteractionOverride(Vec3 vec3, Vec3 vec32, BlockPos blockPos, VoxelShape voxelShape, BlockState blockState)
|
||||
{
|
||||
return this.parent.clipWithInteractionOverride(vec3, vec32, blockPos, voxelShape, blockState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getBlockFloorHeight(VoxelShape voxelShape, Supplier<VoxelShape> supplier) { return this.parent.getBlockFloorHeight(voxelShape, supplier); }
|
||||
|
||||
@Override
|
||||
public double getBlockFloorHeight(BlockPos blockPos) { return this.parent.getBlockFloorHeight(blockPos); }
|
||||
|
||||
@Override
|
||||
public int getMaxBuildHeight() { return this.parent.getMaxBuildHeight(); }
|
||||
|
||||
#if MC_VER >= MC_1_17_1
|
||||
@Override
|
||||
public <T extends BlockEntity> Optional<T> getBlockEntity(BlockPos blockPos, BlockEntityType<T> blockEntityType) { return this.parent.getBlockEntity(blockPos, blockEntityType); }
|
||||
|
||||
@Override
|
||||
public BlockHitResult isBlockInLine(ClipBlockStateContext clipBlockStateContext) { return this.parent.isBlockInLine(clipBlockStateContext); }
|
||||
|
||||
@Override
|
||||
public int getHeight() { return this.parent.getHeight(); }
|
||||
|
||||
@Override
|
||||
public int getMinBuildHeight() { return this.parent.getMinBuildHeight(); }
|
||||
|
||||
@Override
|
||||
public int getSectionsCount() { return this.parent.getSectionsCount(); }
|
||||
|
||||
@Override
|
||||
public int getMinSection() { return this.parent.getMinSection(); }
|
||||
|
||||
@Override
|
||||
public int getMaxSection() { return this.parent.getMaxSection(); }
|
||||
|
||||
@Override
|
||||
public boolean isOutsideBuildHeight(BlockPos blockPos) { return this.parent.isOutsideBuildHeight(blockPos); }
|
||||
|
||||
@Override
|
||||
public boolean isOutsideBuildHeight(int i) { return this.parent.isOutsideBuildHeight(i); }
|
||||
|
||||
@Override
|
||||
public int getSectionIndex(int i) { return this.parent.getSectionIndex(i); }
|
||||
|
||||
@Override
|
||||
public int getSectionIndexFromSectionY(int i) { return this.parent.getSectionIndexFromSectionY(i); }
|
||||
|
||||
@Override
|
||||
public int getSectionYFromSectionIndex(int i) { return this.parent.getSectionYFromSectionIndex(i); }
|
||||
#endif
|
||||
}
|
||||
+148
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* 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.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.Direction;
|
||||
import net.minecraft.world.level.*;
|
||||
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.state.BlockState;
|
||||
import net.minecraft.world.level.lighting.LevelLightEngine;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
#if MC_VER >= MC_1_18_2
|
||||
import net.minecraft.core.Holder;
|
||||
#endif
|
||||
|
||||
public class TintWithoutLevelOverrider implements BlockAndTintGetter
|
||||
{
|
||||
/**
|
||||
* 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 biomeWrapper, IClientLevelWrapper clientLevelWrapper)
|
||||
{
|
||||
// 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
|
||||
public int getBlockTint(@NotNull BlockPos blockPos, @NotNull ColorResolver colorResolver)
|
||||
{
|
||||
if (this.biome != null)
|
||||
{
|
||||
return colorResolver.getColor(this.biome, blockPos.getX(), blockPos.getZ());
|
||||
}
|
||||
else
|
||||
{
|
||||
// hopefully unneeded debug color
|
||||
return ColorUtil.CYAN;
|
||||
}
|
||||
}
|
||||
|
||||
private static Biome unwrap(#if MC_VER >= MC_1_18_2 Holder<Biome> #else Biome #endif biome)
|
||||
{
|
||||
#if MC_VER >= MC_1_18_2
|
||||
return biome.value();
|
||||
#else
|
||||
return biome;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// unused methods //
|
||||
//================//
|
||||
|
||||
@Override
|
||||
public float getShade(@NotNull Direction direction, boolean shade)
|
||||
{
|
||||
throw new UnsupportedOperationException("ERROR: getShade() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
||||
}
|
||||
@Override
|
||||
public @NotNull LevelLightEngine getLightEngine()
|
||||
{
|
||||
throw new UnsupportedOperationException("ERROR: getLightEngine() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
||||
}
|
||||
@Nullable
|
||||
@Override
|
||||
public BlockEntity getBlockEntity(@NotNull BlockPos pos)
|
||||
{
|
||||
throw new UnsupportedOperationException("ERROR: getBlockEntity() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull BlockState getBlockState(@NotNull BlockPos pos)
|
||||
{
|
||||
throw new UnsupportedOperationException("ERROR: getBlockState() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
||||
}
|
||||
@Override
|
||||
public @NotNull FluidState getFluidState(@NotNull BlockPos pos)
|
||||
{
|
||||
throw new UnsupportedOperationException("ERROR: getFluidState() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
||||
}
|
||||
|
||||
|
||||
#if MC_VER >= MC_1_17_1
|
||||
@Override
|
||||
public int getHeight()
|
||||
{
|
||||
throw new UnsupportedOperationException("ERROR: getHeight() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
||||
}
|
||||
@Override
|
||||
public int getMinBuildHeight()
|
||||
{
|
||||
throw new UnsupportedOperationException("ERROR: getMinBuildHeight() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
+71
-54
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
* 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
|
||||
@@ -16,14 +16,11 @@
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.common.wrappers.block;
|
||||
|
||||
import com.seibel.lod.common.LodCommonMain;
|
||||
package com.seibel.distanthorizons.common.wrappers.block;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Cursor3D;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.world.level.BlockAndTintGetter;
|
||||
import net.minecraft.world.level.ColorResolver;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
@@ -33,25 +30,33 @@ import net.minecraft.world.level.lighting.LevelLightEngine;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class TintWithoutLevelSmoothOverrider implements BlockAndTintGetter {
|
||||
final BiomeWrapper biome;
|
||||
public int smoothingRange;
|
||||
#if MC_VER >= MC_1_18_2
|
||||
import net.minecraft.core.Holder;
|
||||
#endif
|
||||
|
||||
public TintWithoutLevelSmoothOverrider(BiomeWrapper biome, int smoothingRange) {
|
||||
this.biome = biome;
|
||||
this.smoothingRange = smoothingRange;
|
||||
}
|
||||
@Override
|
||||
public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver) {
|
||||
return colorResolver.getColor(_unwrap(biome.biome), blockPos.getX(), blockPos.getZ());
|
||||
}
|
||||
private Biome _unwrap(#if POST_MC_1_18_2 Holder<Biome> #else Biome #endif biome) {
|
||||
#if POST_MC_1_18_2
|
||||
return biome.value();
|
||||
public class TintWithoutLevelSmoothOverrider implements BlockAndTintGetter
|
||||
{
|
||||
final BiomeWrapper biome;
|
||||
public int smoothingRange;
|
||||
|
||||
public TintWithoutLevelSmoothOverrider(BiomeWrapper biome, int smoothingRange)
|
||||
{
|
||||
this.biome = biome;
|
||||
this.smoothingRange = smoothingRange;
|
||||
}
|
||||
@Override
|
||||
public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver)
|
||||
{
|
||||
return colorResolver.getColor(_unwrap(biome.biome), blockPos.getX(), blockPos.getZ());
|
||||
}
|
||||
private Biome _unwrap(#if MC_VER >= MC_1_18_2 Holder<Biome> #else Biome #endif biome)
|
||||
{
|
||||
#if MC_VER >= MC_1_18_2
|
||||
return biome.value();
|
||||
#else
|
||||
return biome;
|
||||
return biome;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
//
|
||||
// public int calculateBlockTint(BlockPos blockPos, ColorResolver colorResolver)
|
||||
// {
|
||||
@@ -81,35 +86,47 @@ public class TintWithoutLevelSmoothOverrider implements BlockAndTintGetter {
|
||||
// }
|
||||
// return (k / j & 0xFF) << 16 | (l / j & 0xFF) << 8 | m / j & 0xFF;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public float getShade(Direction direction, boolean shade) {
|
||||
throw new UnsupportedOperationException("ERROR: getShade() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
||||
}
|
||||
@Override
|
||||
public LevelLightEngine getLightEngine() {
|
||||
throw new UnsupportedOperationException("ERROR: getLightEngine() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
||||
}
|
||||
@Nullable
|
||||
@Override
|
||||
public BlockEntity getBlockEntity(BlockPos pos) {
|
||||
throw new UnsupportedOperationException("ERROR: getBlockEntity() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlockState(BlockPos pos) {
|
||||
throw new UnsupportedOperationException("ERROR: getBlockState() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
||||
}
|
||||
@Override
|
||||
public FluidState getFluidState(BlockPos pos) {
|
||||
throw new UnsupportedOperationException("ERROR: getFluidState() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
||||
}
|
||||
@Override
|
||||
public int getHeight() {
|
||||
throw new UnsupportedOperationException("ERROR: getHeight() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
||||
}
|
||||
@Override
|
||||
public int getMinBuildHeight() {
|
||||
throw new UnsupportedOperationException("ERROR: getMinBuildHeight() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getShade(Direction direction, boolean shade)
|
||||
{
|
||||
throw new UnsupportedOperationException("ERROR: getShade() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
||||
}
|
||||
@Override
|
||||
public LevelLightEngine getLightEngine()
|
||||
{
|
||||
throw new UnsupportedOperationException("ERROR: getLightEngine() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
||||
}
|
||||
@Nullable
|
||||
@Override
|
||||
public BlockEntity getBlockEntity(BlockPos pos)
|
||||
{
|
||||
throw new UnsupportedOperationException("ERROR: getBlockEntity() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlockState(BlockPos pos)
|
||||
{
|
||||
throw new UnsupportedOperationException("ERROR: getBlockState() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
||||
}
|
||||
@Override
|
||||
public FluidState getFluidState(BlockPos pos)
|
||||
{
|
||||
throw new UnsupportedOperationException("ERROR: getFluidState() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
||||
}
|
||||
|
||||
|
||||
#if MC_VER >= MC_1_17_1
|
||||
@Override
|
||||
public int getHeight()
|
||||
{
|
||||
throw new UnsupportedOperationException("ERROR: getHeight() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
||||
}
|
||||
@Override
|
||||
public int getMinBuildHeight()
|
||||
{
|
||||
throw new UnsupportedOperationException("ERROR: getMinBuildHeight() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2023 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers.block.cache;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
|
||||
import com.seibel.distanthorizons.core.pos.DhBlockPos;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class ClientBlockDetailMap
|
||||
{
|
||||
private final ConcurrentHashMap<BlockState, ClientBlockStateCache> blockCache = new ConcurrentHashMap<>();
|
||||
//private final ConcurrentHashMap<#if MC_VER < MC_1_18_2 Biome #else Holder<Biome> #endif, Biome> biomeMap = new ConcurrentHashMap<>();
|
||||
private final ClientLevelWrapper level;
|
||||
public ClientBlockDetailMap(ClientLevelWrapper level) { this.level = level; }
|
||||
|
||||
public ClientBlockStateCache getBlockStateData(BlockState state, DhBlockPos pos)
|
||||
{ //TODO: Allow a per pos unique setting
|
||||
return blockCache.computeIfAbsent(state, (s) -> new ClientBlockStateCache(s, level, pos));
|
||||
}
|
||||
|
||||
public void clear() { blockCache.clear(); }
|
||||
|
||||
public int getColor(BlockState state, BiomeWrapper biome, DhBlockPos pos)
|
||||
{
|
||||
return getBlockStateData(state, pos).getAndResolveFaceColor(biome, pos);
|
||||
}
|
||||
|
||||
}
|
||||
+412
@@ -0,0 +1,412 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2023 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers.block.cache;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.block.TextureAtlasSpriteWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.block.TintWithoutLevelOverrider;
|
||||
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
|
||||
import com.seibel.distanthorizons.common.wrappers.block.*;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.pos.DhBlockPos;
|
||||
import com.seibel.distanthorizons.core.util.ColorUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.level.LevelReader;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.FlowerBlock;
|
||||
import net.minecraft.world.level.block.LeavesBlock;
|
||||
import net.minecraft.world.level.block.RotatedPillarBlock;
|
||||
#if MC_VER >= MC_1_19_2
|
||||
import net.minecraft.util.RandomSource;
|
||||
#else
|
||||
import java.util.Random;
|
||||
#endif
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @version 2022-9-16
|
||||
*/
|
||||
public class ClientBlockStateCache
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
|
||||
private static final HashSet<BlockState> BLOCK_STATES_THAT_NEED_LEVEL = new HashSet<>();
|
||||
private static final HashSet<BlockState> BROKEN_BLOCK_STATES = new HashSet<>();
|
||||
|
||||
#if MC_VER < MC_1_19_2
|
||||
public static final Random random = new Random(0);
|
||||
#else
|
||||
public static final RandomSource random = RandomSource.create();
|
||||
#endif
|
||||
|
||||
public final IClientLevelWrapper levelWrapper;
|
||||
public final BlockState blockState;
|
||||
public final LevelReader level;
|
||||
public final BlockPos pos;
|
||||
|
||||
|
||||
|
||||
public ClientBlockStateCache(BlockState blockState, IClientLevelWrapper samplingLevel, DhBlockPos samplingPos)
|
||||
{
|
||||
this.blockState = blockState;
|
||||
this.levelWrapper = samplingLevel;
|
||||
this.level = (LevelReader) samplingLevel.getWrappedMcObject();
|
||||
this.pos = McObjectConverter.Convert(samplingPos);
|
||||
this.resolveColors();
|
||||
//LOGGER.info("ClientBlocKCache created for {}", blockState);
|
||||
}
|
||||
|
||||
boolean isColorResolved = false;
|
||||
int baseColor = 0; //TODO: Impl per-face color
|
||||
boolean needShade = true;
|
||||
boolean needPostTinting = false;
|
||||
int tintIndex = 0;
|
||||
|
||||
|
||||
public static final int FLOWER_COLOR_SCALE = 5;
|
||||
|
||||
enum ColorMode
|
||||
{
|
||||
Default,
|
||||
Flower,
|
||||
Leaves,
|
||||
Chisel,
|
||||
Glass;
|
||||
static ColorMode getColorMode(Block b)
|
||||
{
|
||||
if (b instanceof LeavesBlock) return Leaves;
|
||||
if (b instanceof FlowerBlock) return Flower;
|
||||
if (b.toString().contains("glass")) return Glass;
|
||||
if (b.toString().equals("Block{chiselsandbits:chiseled}")) return Chisel;
|
||||
return Default;
|
||||
}
|
||||
}
|
||||
|
||||
//Way to efficiently do this was suggested by IMS from sodium. This is where those numbers and support code was lifted from.
|
||||
private static final int MIN_BITS = 0x39000000; // 2^(-13)
|
||||
private static final int MAX_BITS = 0x3f7fffff; // 1.0 - f32::EPSILON
|
||||
private static final float MIN_BOUND = Float.intBitsToFloat(MIN_BITS);
|
||||
private static final float MAX_BOUND = Float.intBitsToFloat(MAX_BITS);
|
||||
|
||||
private static final int[] linearToSrgbTable = new int[] {
|
||||
0x0073000d, 0x007a000d, 0x0080000d, 0x0087000d, 0x008d000d, 0x0094000d, 0x009a000d, 0x00a1000d,
|
||||
0x00a7001a, 0x00b4001a, 0x00c1001a, 0x00ce001a, 0x00da001a, 0x00e7001a, 0x00f4001a, 0x0101001a,
|
||||
0x010e0033, 0x01280033, 0x01410033, 0x015b0033, 0x01750033, 0x018f0033, 0x01a80033, 0x01c20033,
|
||||
0x01dc0067, 0x020f0067, 0x02430067, 0x02760067, 0x02aa0067, 0x02dd0067, 0x03110067, 0x03440067,
|
||||
0x037800ce, 0x03df00ce, 0x044600ce, 0x04ad00ce, 0x051400ce, 0x057b00c5, 0x05dd00bc, 0x063b00b5,
|
||||
0x06970158, 0x07420142, 0x07e30130, 0x087b0120, 0x090b0112, 0x09940106, 0x0a1700fc, 0x0a9500f2,
|
||||
0x0b0f01cb, 0x0bf401ae, 0x0ccb0195, 0x0d950180, 0x0e56016e, 0x0f0d015e, 0x0fbc0150, 0x10630143,
|
||||
0x11070264, 0x1238023e, 0x1357021d, 0x14660201, 0x156601e9, 0x165a01d3, 0x174401c0, 0x182401af,
|
||||
0x18fe0331, 0x1a9602fe, 0x1c1502d2, 0x1d7e02ad, 0x1ed4028d, 0x201a0270, 0x21520256, 0x227d0240,
|
||||
0x239f0443, 0x25c003fe, 0x27bf03c4, 0x29a10392, 0x2b6a0367, 0x2d1d0341, 0x2ebe031f, 0x304d0300,
|
||||
0x31d105b0, 0x34a80555, 0x37520507, 0x39d504c5, 0x3c37048b, 0x3e7c0458, 0x40a8042a, 0x42bd0401,
|
||||
0x44c20798, 0x488e071e, 0x4c1c06b6, 0x4f76065d, 0x52a50610, 0x55ac05cc, 0x5892058f, 0x5b590559,
|
||||
0x5e0c0a23, 0x631c0980, 0x67db08f6, 0x6c55087f, 0x70940818, 0x74a007bd, 0x787d076c, 0x7c330723,
|
||||
};
|
||||
|
||||
private static final float[] srgbToLinearTable = new float[] {
|
||||
0.0f, 0.000303527f, 0.000607054f, 0.00091058103f, 0.001214108f, 0.001517635f, 0.0018211621f, 0.002124689f,
|
||||
0.002428216f, 0.002731743f, 0.00303527f, 0.0033465356f, 0.003676507f, 0.004024717f, 0.004391442f,
|
||||
0.0047769533f, 0.005181517f, 0.0056053917f, 0.0060488326f, 0.006512091f, 0.00699541f, 0.0074990317f,
|
||||
0.008023192f, 0.008568125f, 0.009134057f, 0.009721218f, 0.010329823f, 0.010960094f, 0.011612245f,
|
||||
0.012286487f, 0.012983031f, 0.013702081f, 0.014443844f, 0.015208514f, 0.015996292f, 0.016807375f,
|
||||
0.017641952f, 0.018500218f, 0.019382361f, 0.020288562f, 0.02121901f, 0.022173883f, 0.023153365f,
|
||||
0.02415763f, 0.025186857f, 0.026241222f, 0.027320892f, 0.028426038f, 0.029556843f, 0.03071345f, 0.03189604f,
|
||||
0.033104774f, 0.03433981f, 0.035601325f, 0.036889452f, 0.038204376f, 0.039546248f, 0.04091521f, 0.042311423f,
|
||||
0.043735042f, 0.045186214f, 0.046665095f, 0.048171833f, 0.049706575f, 0.051269468f, 0.052860655f, 0.05448028f,
|
||||
0.056128494f, 0.057805434f, 0.05951124f, 0.06124607f, 0.06301003f, 0.06480328f, 0.06662595f, 0.06847818f,
|
||||
0.07036011f, 0.07227186f, 0.07421358f, 0.07618539f, 0.07818743f, 0.08021983f, 0.082282715f, 0.084376216f,
|
||||
0.086500466f, 0.088655606f, 0.09084173f, 0.09305898f, 0.095307484f, 0.09758736f, 0.09989874f, 0.10224175f,
|
||||
0.10461649f, 0.10702311f, 0.10946172f, 0.111932434f, 0.11443538f, 0.116970696f, 0.11953845f, 0.12213881f,
|
||||
0.12477186f, 0.12743773f, 0.13013652f, 0.13286836f, 0.13563336f, 0.13843165f, 0.14126332f, 0.1441285f,
|
||||
0.1470273f, 0.14995982f, 0.15292618f, 0.1559265f, 0.15896086f, 0.16202943f, 0.16513224f, 0.16826946f,
|
||||
0.17144115f, 0.17464745f, 0.17788847f, 0.1811643f, 0.18447503f, 0.1878208f, 0.19120172f, 0.19461787f,
|
||||
0.19806935f, 0.2015563f, 0.20507877f, 0.2086369f, 0.21223079f, 0.21586053f, 0.21952623f, 0.22322798f,
|
||||
0.22696589f, 0.23074007f, 0.23455065f, 0.23839766f, 0.2422812f, 0.2462014f, 0.25015837f, 0.25415218f,
|
||||
0.2581829f, 0.26225072f, 0.26635566f, 0.27049786f, 0.27467737f, 0.27889434f, 0.2831488f, 0.2874409f,
|
||||
0.2917707f, 0.29613832f, 0.30054384f, 0.30498737f, 0.30946895f, 0.31398875f, 0.31854683f, 0.32314324f,
|
||||
0.32777813f, 0.33245158f, 0.33716366f, 0.34191445f, 0.3467041f, 0.3515327f, 0.35640025f, 0.36130688f,
|
||||
0.3662527f, 0.37123778f, 0.37626222f, 0.3813261f, 0.38642952f, 0.39157256f, 0.3967553f, 0.40197787f,
|
||||
0.4072403f, 0.4125427f, 0.41788515f, 0.42326775f, 0.42869055f, 0.4341537f, 0.43965724f, 0.44520125f,
|
||||
0.45078585f, 0.45641106f, 0.46207705f, 0.46778384f, 0.47353154f, 0.47932023f, 0.48514998f, 0.4910209f,
|
||||
0.49693304f, 0.5028866f, 0.50888145f, 0.5149178f, 0.5209957f, 0.52711535f, 0.5332766f, 0.5394797f,
|
||||
0.5457247f, 0.5520116f, 0.5583406f, 0.5647117f, 0.57112503f, 0.57758063f, 0.5840786f, 0.590619f, 0.597202f,
|
||||
0.60382754f, 0.61049575f, 0.61720675f, 0.62396055f, 0.63075733f, 0.637597f, 0.6444799f, 0.6514058f,
|
||||
0.65837497f, 0.66538745f, 0.67244333f, 0.6795426f, 0.68668544f, 0.69387203f, 0.70110214f, 0.70837605f,
|
||||
0.7156938f, 0.72305536f, 0.730461f, 0.7379107f, 0.7454045f, 0.75294244f, 0.76052475f, 0.7681514f, 0.77582246f,
|
||||
0.78353804f, 0.79129815f, 0.79910296f, 0.8069525f, 0.8148468f, 0.822786f, 0.8307701f, 0.83879924f, 0.84687346f,
|
||||
0.8549928f, 0.8631574f, 0.87136734f, 0.8796226f, 0.8879232f, 0.89626956f, 0.90466136f, 0.913099f, 0.92158204f,
|
||||
0.93011117f, 0.9386859f, 0.9473069f, 0.9559735f, 0.9646866f, 0.9734455f, 0.98225087f, 0.9911022f, 1.0f
|
||||
};
|
||||
|
||||
private static int linearToSrgb(float c) {
|
||||
if (!(c > MIN_BOUND)) {
|
||||
c = MIN_BOUND;
|
||||
}
|
||||
|
||||
if (c > MAX_BOUND) {
|
||||
c = MAX_BOUND;
|
||||
}
|
||||
int inputBits = Float.floatToRawIntBits(c);
|
||||
int entry = linearToSrgbTable[((inputBits - MIN_BITS) >> 20)];
|
||||
|
||||
int bias = (entry >>> 16) << 9;
|
||||
int scale = entry & 0xffff;
|
||||
int t = (inputBits >>> 12) & 0xff;
|
||||
|
||||
return (bias + (scale * t)) >>> 16;
|
||||
}
|
||||
//////////////
|
||||
|
||||
private static int getWidth(TextureAtlasSprite texture)
|
||||
{
|
||||
#if MC_VER < MC_1_19_4
|
||||
return texture.getWidth();
|
||||
#else
|
||||
return texture.contents().width();
|
||||
#endif
|
||||
}
|
||||
|
||||
private static int getHeight(TextureAtlasSprite texture)
|
||||
{
|
||||
#if MC_VER < MC_1_19_4
|
||||
return texture.getHeight();
|
||||
#else
|
||||
return texture.contents().height();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//TODO: Perhaps make this not just use the first frame?
|
||||
private static int calculateColorFromTexture(TextureAtlasSprite texture, ColorMode colorMode)
|
||||
{
|
||||
int count = 0;
|
||||
int alpha = 0;
|
||||
double red = 0;
|
||||
double green = 0;
|
||||
double blue = 0;
|
||||
int tempColor;
|
||||
//make Chiseled block not render. Since ColorMode is set per block, you only need to check it once
|
||||
if (colorMode != ColorMode.Chisel)
|
||||
{
|
||||
// textures normally use u and v instead of x and y
|
||||
for (int v = 0; v < getHeight(texture); v++)
|
||||
{
|
||||
for (int u = 0; u < getWidth(texture); u++)
|
||||
{
|
||||
//note: Minecraft color format is: 0xAA BB GG RR
|
||||
//________ DH mod color format is: 0xAA RR GG BB
|
||||
//OpenGL RGBA format native order: 0xRR GG BB AA
|
||||
//_ OpenGL RGBA format Java Order: 0xAA BB GG RR
|
||||
tempColor = TextureAtlasSpriteWrapper.getPixelRGBA(texture, 0, u, v);
|
||||
|
||||
int r = (tempColor & 0x000000FF);
|
||||
int g = (tempColor & 0x0000FF00) >>> 8;
|
||||
int b = (tempColor & 0x00FF0000) >>> 16;
|
||||
int a = (tempColor & 0xFF000000) >>> 24;
|
||||
int scale = 1;
|
||||
if (colorMode == ColorMode.Leaves)
|
||||
{
|
||||
//switch (//FIXME add config option)
|
||||
// case BLACK:
|
||||
// a = 255; //simulate black background of fast leaves
|
||||
// break;
|
||||
// case IGNORE:
|
||||
if (a == 0) {
|
||||
continue; //same long grass
|
||||
}
|
||||
else
|
||||
{
|
||||
a = 255; //just in case there are semi transparent pixels
|
||||
}
|
||||
// break;
|
||||
// case TRANSPARENT:
|
||||
// break; //do nothing, let it count towards transparency
|
||||
|
||||
}
|
||||
else if (a == 0 && colorMode != ColorMode.Glass)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (colorMode == ColorMode.Flower && (g + 25 < b || g + 25 < r))
|
||||
{
|
||||
scale = FLOWER_COLOR_SCALE;
|
||||
}
|
||||
count += scale;
|
||||
//apparently alpha is linear
|
||||
alpha += a * scale;
|
||||
//gamma correction is complicated
|
||||
red += srgbToLinearTable[r] * a * scale;
|
||||
green += srgbToLinearTable[g] * a * scale;
|
||||
blue += srgbToLinearTable[b] * a * scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
// this block is entirely transparent
|
||||
tempColor = ColorUtil.rgbToInt(0, 255, 255, 255);
|
||||
else
|
||||
{
|
||||
// determine the average color
|
||||
tempColor = ColorUtil.rgbToInt(
|
||||
alpha / count,
|
||||
linearToSrgb((float) (red / (double) alpha)),
|
||||
linearToSrgb((float) (green / (double) alpha)),
|
||||
linearToSrgb((float) (blue / (double) alpha)));
|
||||
}
|
||||
//check if not missing texture
|
||||
if (tempColor == ColorUtil.rgbToInt(255, 182, 0, 182))
|
||||
{
|
||||
//make it not render at all
|
||||
tempColor = ColorUtil.rgbToInt(0, 255, 255, 255);
|
||||
}
|
||||
return tempColor;
|
||||
}
|
||||
private static final Direction[] DIRECTION_ORDER = {Direction.UP, Direction.NORTH, Direction.EAST, Direction.WEST, Direction.SOUTH, Direction.DOWN};
|
||||
|
||||
private void resolveColors()
|
||||
{
|
||||
if (isColorResolved) return;
|
||||
if (blockState.getFluidState().isEmpty())
|
||||
{
|
||||
List<BakedQuad> quads = null;
|
||||
for (Direction direction : DIRECTION_ORDER)
|
||||
{
|
||||
quads = Minecraft.getInstance().getModelManager().getBlockModelShaper().
|
||||
getBlockModel(blockState).getQuads(blockState, direction, random); // TODO getQuads sometimes throws a "makeThreadingException", is there anything we can do about that? Note: this isn't a critical issue, it just prints an ugly error and the render data will need to be regenered.
|
||||
if (quads != null && !quads.isEmpty() &&
|
||||
!(blockState.getBlock() instanceof RotatedPillarBlock && direction == Direction.UP))
|
||||
break;
|
||||
} ;
|
||||
if (quads == null || quads.isEmpty())
|
||||
{
|
||||
quads = Minecraft.getInstance().getModelManager().getBlockModelShaper().
|
||||
getBlockModel(blockState).getQuads(blockState, null, random);
|
||||
}
|
||||
if (quads != null && !quads.isEmpty())
|
||||
{
|
||||
needPostTinting = quads.get(0).isTinted();
|
||||
needShade = quads.get(0).isShade();
|
||||
tintIndex = quads.get(0).getTintIndex();
|
||||
baseColor = calculateColorFromTexture(
|
||||
#if MC_VER < MC_1_17_1 quads.get(0).sprite,
|
||||
#else quads.get(0).getSprite(), #endif
|
||||
ColorMode.getColorMode(blockState.getBlock()));
|
||||
}
|
||||
else
|
||||
{ // Backup method.
|
||||
needPostTinting = false;
|
||||
needShade = false;
|
||||
tintIndex = 0;
|
||||
baseColor = calculateColorFromTexture(Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(blockState),
|
||||
ColorMode.getColorMode(blockState.getBlock()));
|
||||
}
|
||||
}
|
||||
else
|
||||
{ // Liquid Block
|
||||
needPostTinting = true;
|
||||
needShade = false;
|
||||
tintIndex = 0;
|
||||
baseColor = calculateColorFromTexture(Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(blockState),
|
||||
ColorMode.getColorMode(blockState.getBlock()));
|
||||
}
|
||||
isColorResolved = true;
|
||||
}
|
||||
|
||||
public int getAndResolveFaceColor(BiomeWrapper biome, DhBlockPos pos)
|
||||
{
|
||||
// FIXME: impl per-face colors
|
||||
|
||||
// only get the tint if the block needs to be tinted
|
||||
if (!this.needPostTinting)
|
||||
{
|
||||
return this.baseColor;
|
||||
}
|
||||
|
||||
// don't try tinting blocks that don't support our method of tint getting
|
||||
if (BROKEN_BLOCK_STATES.contains(this.blockState))
|
||||
{
|
||||
return this.baseColor;
|
||||
}
|
||||
|
||||
|
||||
// attempt to get the tint
|
||||
int tintColor = -1;
|
||||
try
|
||||
{
|
||||
// try to use the fast tint getter logic first
|
||||
if (!BLOCK_STATES_THAT_NEED_LEVEL.contains(this.blockState))
|
||||
{
|
||||
try
|
||||
{
|
||||
tintColor = Minecraft.getInstance().getBlockColors()
|
||||
.getColor(this.blockState, new TintWithoutLevelOverrider(biome, this.levelWrapper), McObjectConverter.Convert(pos), this.tintIndex);
|
||||
}
|
||||
catch (UnsupportedOperationException e)
|
||||
{
|
||||
// this exception generally occurs if the tint requires other blocks besides itself
|
||||
LOGGER.debug("Unable to use ["+TintWithoutLevelOverrider.class.getSimpleName()+"] to get the block tint for block: [" + this.blockState + "] and biome: [" + biome + "] at pos: " + pos + ". Error: [" + e.getMessage() + "]. Attempting to use backup method...", e);
|
||||
BLOCK_STATES_THAT_NEED_LEVEL.add(this.blockState);
|
||||
}
|
||||
}
|
||||
|
||||
// use the level logic only if requested
|
||||
if (BLOCK_STATES_THAT_NEED_LEVEL.contains(this.blockState))
|
||||
{
|
||||
// this logic can't be used all the time due to it breaking some blocks tinting
|
||||
// specifically oceans don't render correctly
|
||||
tintColor = Minecraft.getInstance().getBlockColors()
|
||||
.getColor(this.blockState, new TintGetterOverrideFast(this.level), McObjectConverter.Convert(pos), this.tintIndex);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// only display the error once per block/biome type to reduce log spam
|
||||
if (!BROKEN_BLOCK_STATES.contains(this.blockState))
|
||||
{
|
||||
LOGGER.warn("Failed to get block color for block: [" + this.blockState + "] and biome: [" + biome + "] at pos: " + pos + ". Error: ["+e.getMessage() + "]. Note: future errors for this block/biome will be ignored.", e);
|
||||
BROKEN_BLOCK_STATES.add(this.blockState);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (tintColor != -1)
|
||||
{
|
||||
return ColorUtil.multiplyARGBwithRGB(this.baseColor, tintColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
// unable to get the tinted color, use the base color instead
|
||||
return this.baseColor;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+13
-11
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
* 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
|
||||
@@ -16,26 +16,28 @@
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.common.wrappers.block.cache;
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers.block.cache;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.seibel.lod.common.wrappers.world.ServerLevelWrapper;
|
||||
import com.seibel.lod.core.pos.DhBlockPos;
|
||||
import 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 PRE_MC_1_18_2 Biome #else Holder<Biome> #endif, Biome> biomeMap = 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 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
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+603
@@ -0,0 +1,603 @@
|
||||
/*
|
||||
* 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.common.wrappers.block.BiomeWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.pos.DhBlockPos;
|
||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||
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.world.IBiomeWrapper;
|
||||
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import net.minecraft.client.multiplayer.ClientChunkCache;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.world.level.LevelReader;
|
||||
import net.minecraft.world.level.LightLayer;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
#if MC_VER >= MC_1_17_1
|
||||
import net.minecraft.core.QuartPos;
|
||||
#endif
|
||||
|
||||
#if MC_VER == MC_1_16_5
|
||||
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||
#endif
|
||||
|
||||
#if MC_VER == MC_1_17_1
|
||||
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||
#endif
|
||||
|
||||
#if MC_VER == MC_1_18_2
|
||||
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||
#endif
|
||||
|
||||
#if MC_VER == MC_1_19_2 || MC_VER == MC_1_19_4
|
||||
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||
#endif
|
||||
|
||||
#if MC_VER >= MC_1_20_1
|
||||
import net.minecraft.world.level.chunk.LevelChunkSection;
|
||||
import net.minecraft.world.level.lighting.LevelLightEngine;
|
||||
import net.minecraft.core.SectionPos;
|
||||
#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
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
|
||||
/** 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 final ChunkAccess chunk;
|
||||
private final DhChunkPos chunkPos;
|
||||
private final LevelReader lightSource;
|
||||
private final ILevelWrapper wrappedLevel;
|
||||
|
||||
private boolean isDhLightCorrect = false;
|
||||
/** only used when connected to a dedicated server */
|
||||
private boolean isMcClientLightingCorrect = false;
|
||||
|
||||
private ChunkLightStorage blockLightStorage;
|
||||
private ChunkLightStorage skyLightStorage;
|
||||
|
||||
private ArrayList<DhBlockPos> blockLightPosList = null;
|
||||
|
||||
private boolean useDhLighting;
|
||||
|
||||
private int minNonEmptyHeight = Integer.MIN_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'
|
||||
* before the light engine has ticked, (right after all light changes is marked by the engine to be processed).
|
||||
* To fix this, on client-only mode, we mixin-redirect the `isClientLightReady()` so that after the call, it will
|
||||
* trigger a synchronous update of this flag here on all chunks that are wrapped. <br><br>
|
||||
*
|
||||
* Note: Using a static weak hash map to store the chunks that need to be updated, as instance of chunk wrapper
|
||||
* can be duplicated, with same chunk instance. And the data stored here are all temporary, and thus will not be
|
||||
* visible when a chunk is re-wrapped later. <br>
|
||||
* (Also, thread safety done via a reader writer lock)
|
||||
*/
|
||||
private static final ConcurrentLinkedQueue<ChunkWrapper> chunksNeedingClientLightUpdating = new ConcurrentLinkedQueue<>();
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
public ChunkWrapper(ChunkAccess chunk, LevelReader lightSource, ILevelWrapper wrappedLevel)
|
||||
{
|
||||
this.chunk = chunk;
|
||||
this.lightSource = lightSource;
|
||||
this.wrappedLevel = wrappedLevel;
|
||||
this.chunkPos = new DhChunkPos(chunk.getPos().x, chunk.getPos().z);
|
||||
|
||||
// TODO is this the best way to differentiate between when we are generating chunks and when MC gave us a chunk?
|
||||
boolean isDhGeneratedChunk = (this.lightSource.getClass() == DhLitWorldGenRegion.class);
|
||||
// MC loaded chunks should get their lighting from MC, DH generated chunks should get their lighting from DH
|
||||
this.useDhLighting = isDhGeneratedChunk;
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// getters //
|
||||
//=========//
|
||||
|
||||
@Override
|
||||
public int getHeight() { return getHeight(this.chunk); }
|
||||
public static int getHeight(ChunkAccess chunk)
|
||||
{
|
||||
#if MC_VER < MC_1_17_1
|
||||
return 255;
|
||||
#else
|
||||
return chunk.getHeight();
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinBuildHeight() { return getMinBuildHeight(this.chunk); }
|
||||
public static int getMinBuildHeight(ChunkAccess chunk)
|
||||
{
|
||||
#if MC_VER < MC_1_17_1
|
||||
return 0;
|
||||
#else
|
||||
return chunk.getMinBuildHeight();
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxBuildHeight() { return getMaxBuildHeight(this.chunk); }
|
||||
public static int getMaxBuildHeight(ChunkAccess chunk) { return chunk.getMaxBuildHeight(); }
|
||||
|
||||
@Override
|
||||
public int getMinNonEmptyHeight()
|
||||
{
|
||||
if (this.minNonEmptyHeight != Integer.MIN_VALUE)
|
||||
{
|
||||
return this.minNonEmptyHeight;
|
||||
}
|
||||
|
||||
|
||||
// default if every section is empty or missing
|
||||
this.minNonEmptyHeight = this.getMinBuildHeight();
|
||||
|
||||
// determine the lowest empty section (bottom up)
|
||||
LevelChunkSection[] sections = this.chunk.getSections();
|
||||
for (int index = 0; index < sections.length; index++)
|
||||
{
|
||||
if (sections[index] == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isChunkSectionEmpty(sections[index]))
|
||||
{
|
||||
this.minNonEmptyHeight = this.getChunkSectionMinHeight(index);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return this.minNonEmptyHeight;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getMaxNonEmptyHeight()
|
||||
{
|
||||
if (this.maxNonEmptyHeight != Integer.MAX_VALUE)
|
||||
{
|
||||
return this.maxNonEmptyHeight;
|
||||
}
|
||||
|
||||
|
||||
// default if every section is empty or missing
|
||||
this.maxNonEmptyHeight = this.getMaxBuildHeight();
|
||||
|
||||
// determine the highest empty section (top down)
|
||||
LevelChunkSection[] sections = this.chunk.getSections();
|
||||
for (int index = sections.length-1; index >= 0; index--)
|
||||
{
|
||||
if (sections[index] == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isChunkSectionEmpty(sections[index]))
|
||||
{
|
||||
this.maxNonEmptyHeight = this.getChunkSectionMinHeight(index) + 16;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return this.maxNonEmptyHeight;
|
||||
}
|
||||
private static boolean isChunkSectionEmpty(LevelChunkSection section)
|
||||
{
|
||||
#if MC_VER == MC_1_16_5
|
||||
return section.isEmpty();
|
||||
#elif MC_VER == MC_1_17_1
|
||||
return section.isEmpty();
|
||||
#else
|
||||
return section.hasOnlyAir();
|
||||
#endif
|
||||
}
|
||||
private int getChunkSectionMinHeight(int index)
|
||||
{
|
||||
// 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
|
||||
public int getSolidHeightMapValue(int xRel, int zRel) { return this.chunk.getOrCreateHeightmapUnprimed(Heightmap.Types.WORLD_SURFACE).getFirstAvailable(xRel, zRel); }
|
||||
|
||||
@Override
|
||||
public int getLightBlockingHeightMapValue(int xRel, int zRel) { return this.chunk.getOrCreateHeightmapUnprimed(Heightmap.Types.MOTION_BLOCKING).getFirstAvailable(xRel, zRel); }
|
||||
|
||||
|
||||
@Override
|
||||
public IBiomeWrapper getBiome(int relX, int relY, int relZ)
|
||||
{
|
||||
#if MC_VER < MC_1_17_1
|
||||
return BiomeWrapper.getBiomeWrapper(this.chunk.getBiomes().getNoiseBiome(
|
||||
relX >> 2, relY >> 2, relZ >> 2),
|
||||
this.wrappedLevel);
|
||||
#elif MC_VER < MC_1_18_2
|
||||
return BiomeWrapper.getBiomeWrapper(this.chunk.getBiomes().getNoiseBiome(
|
||||
QuartPos.fromBlock(relX), QuartPos.fromBlock(relY), QuartPos.fromBlock(relZ)),
|
||||
this.wrappedLevel);
|
||||
#elif MC_VER < MC_1_18_2
|
||||
return BiomeWrapper.getBiomeWrapper(this.chunk.getNoiseBiome(
|
||||
QuartPos.fromBlock(relX), QuartPos.fromBlock(relY), QuartPos.fromBlock(relZ)),
|
||||
this.wrappedLevel);
|
||||
#else
|
||||
//Now returns a Holder<Biome> instead of Biome
|
||||
return BiomeWrapper.getBiomeWrapper(this.chunk.getNoiseBiome(
|
||||
QuartPos.fromBlock(relX), QuartPos.fromBlock(relY), QuartPos.fromBlock(relZ)),
|
||||
this.wrappedLevel);
|
||||
#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
|
||||
public DhChunkPos getChunkPos() { return this.chunkPos; }
|
||||
|
||||
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
|
||||
return chunk.getStatus();
|
||||
#else
|
||||
return chunk.getPersistedStatus();
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxBlockX() { return this.chunk.getPos().getMaxBlockX(); }
|
||||
@Override
|
||||
public int getMaxBlockZ() { return this.chunk.getPos().getMaxBlockZ(); }
|
||||
@Override
|
||||
public int getMinBlockX() { return this.chunk.getPos().getMinBlockX(); }
|
||||
@Override
|
||||
public int getMinBlockZ() { return this.chunk.getPos().getMinBlockZ(); }
|
||||
|
||||
|
||||
|
||||
//==========//
|
||||
// lighting //
|
||||
//==========//
|
||||
|
||||
@Override
|
||||
public void setIsDhLightCorrect(boolean isDhLightCorrect) { this.isDhLightCorrect = isDhLightCorrect; }
|
||||
|
||||
@Override
|
||||
public void setUseDhLighting(boolean useDhLighting) { this.useDhLighting = useDhLighting; }
|
||||
|
||||
@Override
|
||||
public boolean isLightCorrect()
|
||||
{
|
||||
if (this.useDhLighting)
|
||||
{
|
||||
return this.isDhLightCorrect;
|
||||
}
|
||||
|
||||
|
||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||
return false; // MC's lighting engine doesn't work consistently enough to trust for 1.16 or 1.17
|
||||
#else
|
||||
if (this.chunk instanceof LevelChunk)
|
||||
{
|
||||
LevelChunk levelChunk = (LevelChunk) this.chunk;
|
||||
if (levelChunk.getLevel() instanceof ClientLevel)
|
||||
{
|
||||
// connected to a server
|
||||
return this.isMcClientLightingCorrect;
|
||||
}
|
||||
else
|
||||
{
|
||||
// in a single player world
|
||||
return this.chunk.isLightCorrect() && levelChunk.loaded;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// called when in a single player world and the chunk is a proto chunk (in world gen, and not active)
|
||||
return this.chunk.isLightCorrect();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getDhBlockLight(int relX, int y, int relZ)
|
||||
{
|
||||
this.throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, y, relZ);
|
||||
return this.getBlockLightStorage().get(relX, y, relZ);
|
||||
}
|
||||
@Override
|
||||
public void setDhBlockLight(int relX, int y, int relZ, int lightValue)
|
||||
{
|
||||
this.throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, y, relZ);
|
||||
this.getBlockLightStorage().set(relX, y, relZ, lightValue);
|
||||
}
|
||||
|
||||
private ChunkLightStorage getBlockLightStorage()
|
||||
{
|
||||
if (this.blockLightStorage == null)
|
||||
{
|
||||
this.blockLightStorage = ChunkLightStorage.createBlockLightStorage(this);
|
||||
}
|
||||
return this.blockLightStorage;
|
||||
}
|
||||
public void setBlockLightStorage(ChunkLightStorage lightStorage) { this.blockLightStorage = lightStorage; }
|
||||
|
||||
|
||||
@Override
|
||||
public int getDhSkyLight(int relX, int y, int relZ)
|
||||
{
|
||||
this.throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, y, relZ);
|
||||
return this.getSkyLightStorage().get(relX, y, relZ);
|
||||
}
|
||||
@Override
|
||||
public void setDhSkyLight(int relX, int y, int relZ, int lightValue)
|
||||
{
|
||||
this.throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, y, relZ);
|
||||
this.getSkyLightStorage().set(relX, y, relZ, lightValue);
|
||||
}
|
||||
|
||||
private ChunkLightStorage getSkyLightStorage()
|
||||
{
|
||||
if (this.skyLightStorage == null)
|
||||
{
|
||||
this.skyLightStorage = ChunkLightStorage.createSkyLightStorage(this);
|
||||
}
|
||||
return this.skyLightStorage;
|
||||
}
|
||||
public void setSkyLightStorage(ChunkLightStorage lightStorage) { this.skyLightStorage = lightStorage; }
|
||||
|
||||
|
||||
@Override
|
||||
public int getBlockLight(int relX, int y, int relZ)
|
||||
{
|
||||
this.throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, y, relZ);
|
||||
|
||||
// use the full lighting engine when the chunks are within render distance or the config requests it
|
||||
if (this.useDhLighting)
|
||||
{
|
||||
// DH lighting method
|
||||
return this.getBlockLightStorage().get(relX, y, relZ);
|
||||
}
|
||||
else
|
||||
{
|
||||
// note: this returns 0 if the chunk is unload
|
||||
|
||||
// MC lighting method
|
||||
return this.lightSource.getBrightness(LightLayer.BLOCK, new BlockPos(relX + this.getMinBlockX(), y, relZ + this.getMinBlockZ()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSkyLight(int relX, int y, int relZ)
|
||||
{
|
||||
this.throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, y, relZ);
|
||||
|
||||
// use the full lighting engine when the chunks are within render distance or the config requests it
|
||||
if (this.useDhLighting)
|
||||
{
|
||||
// DH lighting method
|
||||
return this.getSkyLightStorage().get(relX, y, relZ);
|
||||
}
|
||||
else
|
||||
{
|
||||
// MC lighting method
|
||||
return this.lightSource.getBrightness(LightLayer.SKY, new BlockPos(relX + this.getMinBlockX(), y, relZ + this.getMinBlockZ()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* FIXME synchronized is necessary for a rare issue where this method is called from two separate threads at the same time
|
||||
* before the list has finished populating.
|
||||
*/
|
||||
@Override
|
||||
public synchronized ArrayList<DhBlockPos> getBlockLightPosList()
|
||||
{
|
||||
// only populate the list once
|
||||
if (this.blockLightPosList == null)
|
||||
{
|
||||
this.blockLightPosList = new ArrayList<>();
|
||||
|
||||
|
||||
#if MC_VER < MC_1_20_1
|
||||
this.chunk.getLights().forEach((blockPos) ->
|
||||
{
|
||||
this.blockLightPosList.add(new DhBlockPos(blockPos.getX(), blockPos.getY(), blockPos.getZ()));
|
||||
});
|
||||
#else
|
||||
this.chunk.findBlockLightSources((blockPos, blockState) ->
|
||||
{
|
||||
this.blockLightPosList.add(new DhBlockPos(blockPos.getX(), blockPos.getY(), blockPos.getZ()));
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
return this.blockLightPosList;
|
||||
}
|
||||
|
||||
public static void syncedUpdateClientLightStatus()
|
||||
{
|
||||
#if MC_VER < MC_1_18_2
|
||||
// TODO: Check what to do in 1.18.1 and older
|
||||
|
||||
// since we don't currently handle this list,
|
||||
// clear it to prevent memory leaks
|
||||
chunksNeedingClientLightUpdating.clear();
|
||||
|
||||
#else
|
||||
|
||||
// update the chunks client lighting
|
||||
ChunkWrapper chunkWrapper = chunksNeedingClientLightUpdating.poll();
|
||||
while (chunkWrapper != null)
|
||||
{
|
||||
chunkWrapper.updateIsClientLightingCorrect();
|
||||
chunkWrapper = chunksNeedingClientLightUpdating.poll();
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
/** Should be called after client light updates are triggered. */
|
||||
private void updateIsClientLightingCorrect()
|
||||
{
|
||||
if (this.chunk instanceof LevelChunk && ((LevelChunk) this.chunk).getLevel() instanceof ClientLevel)
|
||||
{
|
||||
LevelChunk levelChunk = (LevelChunk) this.chunk;
|
||||
ClientChunkCache clientChunkCache = ((ClientLevel) levelChunk.getLevel()).getChunkSource();
|
||||
this.isMcClientLightingCorrect = clientChunkCache.getChunkForLighting(this.chunk.getPos().x, this.chunk.getPos().z) != null &&
|
||||
#if MC_VER <= MC_1_17_1
|
||||
levelChunk.isLightCorrect();
|
||||
#elif MC_VER < MC_1_20_1
|
||||
levelChunk.isClientLightReady();
|
||||
#else
|
||||
checkLightSectionsOnChunk(levelChunk, levelChunk.getLevel().getLightEngine());
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#if MC_VER >= MC_1_20_1
|
||||
private static boolean checkLightSectionsOnChunk(LevelChunk chunk, LevelLightEngine engine)
|
||||
{
|
||||
LevelChunkSection[] sections = chunk.getSections();
|
||||
int minY = chunk.getMinSection();
|
||||
int maxY = chunk.getMaxSection();
|
||||
for (int y = minY; y < maxY; ++y)
|
||||
{
|
||||
LevelChunkSection section = sections[chunk.getSectionIndexFromSectionY(y)];
|
||||
if (section.hasOnlyAir()) continue;
|
||||
if (!engine.lightOnInSection(SectionPos.of(chunk.getPos(), y)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//===============//
|
||||
// other methods //
|
||||
//===============//
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
@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;
|
||||
//}
|
||||
|
||||
}
|
||||
+694
@@ -0,0 +1,694 @@
|
||||
package com.seibel.distanthorizons.common.wrappers.gui;
|
||||
|
||||
import java.util.AbstractMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
// Logger (for debug stuff)
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.config.DisallowSelectingViaConfigGui;
|
||||
import com.seibel.distanthorizons.api.enums.config.EDhApiUpdateBranch;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.config.ConfigBase;
|
||||
import com.seibel.distanthorizons.core.config.types.*;
|
||||
import com.seibel.distanthorizons.common.wrappers.gui.updater.ChangelogScreen;
|
||||
|
||||
// Uses https://github.com/TheElectronWill/night-config for toml (only for Fabric since Forge already includes this)
|
||||
|
||||
// Gets info from our own mod
|
||||
|
||||
// Minecraft imports
|
||||
|
||||
import com.seibel.distanthorizons.core.jar.updater.SelfUpdater;
|
||||
import com.seibel.distanthorizons.core.util.AnnotationUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.config.IConfigGui;
|
||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.Font;
|
||||
#if MC_VER < MC_1_20_1
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.gui.GuiComponent;
|
||||
#else
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
#endif
|
||||
import net.minecraft.client.gui.components.AbstractWidget;
|
||||
import net.minecraft.client.gui.components.Button;
|
||||
import net.minecraft.client.gui.components.ContainerObjectSelectionList;
|
||||
import net.minecraft.client.gui.components.EditBox;
|
||||
import net.minecraft.client.gui.components.events.GuiEventListener;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.client.resources.language.I18n; // translation
|
||||
#if MC_VER >= MC_1_17_1
|
||||
import net.minecraft.client.gui.narration.NarratableEntry;
|
||||
#endif
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import static com.seibel.distanthorizons.common.wrappers.gui.GuiHelper.*;
|
||||
|
||||
|
||||
/**
|
||||
* Based upon TinyConfig but is highly modified
|
||||
* https://github.com/Minenash/TinyConfig
|
||||
*
|
||||
* Credits to Motschen
|
||||
*
|
||||
* @author coolGi
|
||||
* @version 5-21-2022
|
||||
*/
|
||||
// FLOATS DONT WORK WITH THIS
|
||||
|
||||
/** This file is going to be removed sometime soon, please dont hook onto anything within this file until the new UI is compleated */
|
||||
@SuppressWarnings("unchecked")
|
||||
public class ClassicConfigGUI
|
||||
{
|
||||
/*
|
||||
This would be removed later on as it is going to be re-written in java swing
|
||||
*/
|
||||
|
||||
private static final Logger LOGGER = LogManager.getLogger();
|
||||
|
||||
public static final ConfigCoreInterface CONFIG_CORE_INTERFACE = new ConfigCoreInterface();
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// Initializers //
|
||||
//==============//
|
||||
|
||||
// Some regexes to check if an input is valid
|
||||
private static final Pattern INTEGER_ONLY_REGEX = Pattern.compile("(-?[0-9]*)");
|
||||
private static final Pattern DECIMAL_ONLY_REGEX = Pattern.compile("-?([\\d]+\\.?[\\d]*|[\\d]*\\.?[\\d]+|\\.)");
|
||||
|
||||
private static class ConfigScreenConfigs
|
||||
{
|
||||
// This contains all the configs for the configs
|
||||
public static final int SpaceFromRightScreen = 10;
|
||||
public static final int ButtonWidthSpacing = 5;
|
||||
public static final int ResetButtonWidth = 40;
|
||||
public static final int ResetButtonHeight = 20;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* The terribly coded old stuff
|
||||
*/
|
||||
public static class EntryInfo
|
||||
{
|
||||
Object widget;
|
||||
Map.Entry<EditBox, Component> error;
|
||||
String tempValue;
|
||||
int index;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* creates a text field
|
||||
*/
|
||||
private static void textField(AbstractConfigType info, Function<String, Number> func, Pattern pattern, boolean cast)
|
||||
{
|
||||
boolean isNumber = pattern != null;
|
||||
((EntryInfo) info.guiValue).widget = (BiFunction<EditBox, Button, Predicate<String>>) (editBox, button) -> stringValue ->
|
||||
{
|
||||
stringValue = stringValue.trim();
|
||||
if (!(stringValue.isEmpty() || !isNumber || pattern.matcher(stringValue).matches()))
|
||||
return false;
|
||||
|
||||
Number value = 0;
|
||||
((EntryInfo) info.guiValue).error = null;
|
||||
if (isNumber && !stringValue.isEmpty() && !stringValue.equals("-") && !stringValue.equals("."))
|
||||
{
|
||||
try
|
||||
{
|
||||
value = func.apply(stringValue);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
value = null;
|
||||
}
|
||||
|
||||
byte isValid = ((ConfigEntry) info).isValid(value);
|
||||
switch (isValid)
|
||||
{
|
||||
case 0:
|
||||
((EntryInfo) info.guiValue).error = null; break;
|
||||
case -1:
|
||||
((EntryInfo) info.guiValue).error = new AbstractMap.SimpleEntry<>(editBox, TextOrTranslatable("§cMinimum length is " + ((ConfigEntry) info).getMin())); break;
|
||||
case 1:
|
||||
((EntryInfo) info.guiValue).error = new AbstractMap.SimpleEntry<>(editBox, TextOrTranslatable("§cMaximum length is " + ((ConfigEntry) info).getMax())); break;
|
||||
case 2:
|
||||
((EntryInfo) info.guiValue).error = new AbstractMap.SimpleEntry<>(editBox, TextOrTranslatable("§cValue is invalid")); break;
|
||||
}
|
||||
}
|
||||
|
||||
((EntryInfo) info.guiValue).tempValue = stringValue;
|
||||
editBox.setTextColor(((ConfigEntry) info).isValid(value) == 0 ? 0xFFFFFFFF : 0xFFFF7777);
|
||||
// button.active = entries.stream().allMatch(e -> e.inLimits);
|
||||
|
||||
|
||||
if (((ConfigEntry) info).isValid(value) == 0 && info.getType() != List.class)
|
||||
{
|
||||
if (!cast)
|
||||
((ConfigEntry) info).uiSetWithoutSaving(value);
|
||||
else
|
||||
((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;
|
||||
};
|
||||
}
|
||||
|
||||
//==============//
|
||||
// GUI handling //
|
||||
//==============//
|
||||
|
||||
/**
|
||||
* if you want to get this config gui's screen call this
|
||||
*/
|
||||
public static Screen getScreen(ConfigBase configBase, Screen parent, String category)
|
||||
{
|
||||
return new ConfigScreen(configBase, parent, category);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pain
|
||||
*/
|
||||
private static class ConfigScreen extends DhScreen
|
||||
{
|
||||
protected ConfigScreen(ConfigBase configBase, Screen parent, String category)
|
||||
{
|
||||
super(Translatable(
|
||||
I18n.exists(configBase.modID + ".config" + (category.isEmpty() ? "." + category : "") + ".title") ?
|
||||
configBase.modID + ".config.title" :
|
||||
configBase.modID + ".config" + (category.isEmpty() ? "" : "." + category) + ".title")
|
||||
);
|
||||
this.configBase = configBase;
|
||||
this.parent = parent;
|
||||
this.category = category;
|
||||
this.translationPrefix = configBase.modID + ".config.";
|
||||
}
|
||||
private final ConfigBase configBase;
|
||||
|
||||
private final String translationPrefix;
|
||||
private final Screen parent;
|
||||
private final String category;
|
||||
private ConfigListWidget list;
|
||||
private boolean reload = false;
|
||||
|
||||
private Button doneButton;
|
||||
|
||||
// Real Time config update //
|
||||
@Override
|
||||
public void tick()
|
||||
{
|
||||
super.tick();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* When you close it, it goes to the previous screen and saves
|
||||
*/
|
||||
@Override
|
||||
public void onClose()
|
||||
{
|
||||
ConfigBase.INSTANCE.configFileINSTANCE.saveToFile();
|
||||
Objects.requireNonNull(this.minecraft).setScreen(this.parent);
|
||||
|
||||
CONFIG_CORE_INTERFACE.onScreenChangeListenerList.forEach((listener) -> listener.run());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init()
|
||||
{
|
||||
super.init();
|
||||
if (!reload)
|
||||
{
|
||||
ConfigBase.INSTANCE.configFileINSTANCE.loadFromFile();
|
||||
}
|
||||
|
||||
// Changelog button
|
||||
if (Config.Client.Advanced.AutoUpdater.enableAutoUpdater.get() && !ModInfo.IS_DEV_BUILD) // we only have changelogs for stable builds
|
||||
{
|
||||
this.addBtn(new TexturedButtonWidget(
|
||||
// Where the button is on the screen
|
||||
this.width - 28, this.height - 28,
|
||||
// Width and height of the button
|
||||
20, 20,
|
||||
// texture UV Offset
|
||||
0, 0,
|
||||
// Some textuary stuff
|
||||
0,
|
||||
#if MC_VER < MC_1_21
|
||||
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
|
||||
(buttonWidget) -> {
|
||||
ChangelogScreen changelogScreen = new ChangelogScreen(this);
|
||||
if (changelogScreen.usable)
|
||||
Objects.requireNonNull(minecraft).setScreen(changelogScreen);
|
||||
else
|
||||
LOGGER.warn("Changelog was not able to open");
|
||||
},
|
||||
// Add a title to the button
|
||||
Translatable(ModInfo.ID + ".updater.title")
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
addBtn(MakeBtn(Translatable("distanthorizons.general.cancel"),
|
||||
this.width / 2 - 154, this.height - 28,
|
||||
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) -> {
|
||||
ConfigBase.INSTANCE.configFileINSTANCE.saveToFile();
|
||||
Objects.requireNonNull(minecraft).setScreen(parent);
|
||||
}));
|
||||
|
||||
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)
|
||||
this.list.setRenderBackground(false);
|
||||
#endif
|
||||
|
||||
this.addWidget(this.list);
|
||||
|
||||
for (AbstractConfigType info : ConfigBase.INSTANCE.entries)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (info.getCategory().matches(category) && info.getAppearance().showInGui)
|
||||
addMenuItem(info);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
System.out.println("ERROR: Failed to show [" + info.getNameWCategory() + "]");
|
||||
if (info.get() != null)
|
||||
System.out.print(" with the value [" + info.get() + "] with type [" + info.getType() + "]");
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
CONFIG_CORE_INTERFACE.onScreenChangeListenerList.forEach((listener) -> listener.run());
|
||||
|
||||
}
|
||||
|
||||
private void addMenuItem(AbstractConfigType info)
|
||||
{
|
||||
initEntry(info, this.translationPrefix);
|
||||
Component name = Translatable(translationPrefix + info.getNameWCategory());
|
||||
|
||||
|
||||
if (ConfigEntry.class.isAssignableFrom(info.getClass()))
|
||||
{
|
||||
Button.OnPress btnAction = button -> {
|
||||
((ConfigEntry) info).uiSetWithoutSaving(((ConfigEntry) info).getDefaultValue());
|
||||
((EntryInfo) info.guiValue).index = 0;
|
||||
this.reload = true;
|
||||
Objects.requireNonNull(minecraft).setScreen(this);
|
||||
};
|
||||
int posX = this.width - ConfigScreenConfigs.SpaceFromRightScreen - 150 - ConfigScreenConfigs.ButtonWidthSpacing - ConfigScreenConfigs.ResetButtonWidth;
|
||||
int posZ = 0;
|
||||
|
||||
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)
|
||||
{
|
||||
Map.Entry<Button.OnPress, Function<Object, Component>> widget = (Map.Entry<Button.OnPress, Function<Object, Component>>) ((EntryInfo) info.guiValue).widget;
|
||||
if (info.getType().isEnum())
|
||||
{
|
||||
widget.setValue(value -> Translatable(translationPrefix + "enum." + info.getType().getSimpleName() + "." + info.get().toString()));
|
||||
}
|
||||
this.list.addButton(MakeBtn(widget.getValue().apply(info.get()), this.width - 150 - ConfigScreenConfigs.SpaceFromRightScreen, 0, 150, 20, widget.getKey()), resetButton, null, name);
|
||||
return;
|
||||
}
|
||||
else if (((EntryInfo) info.guiValue).widget != null)
|
||||
{
|
||||
EditBox widget = new EditBox(font, this.width - 150 - ConfigScreenConfigs.SpaceFromRightScreen + 2, 0, 150 - 4, 20, null);
|
||||
widget.setMaxLength(150);
|
||||
widget.insertText(String.valueOf(info.get()));
|
||||
Predicate<String> processor = ((BiFunction<EditBox, Button, Predicate<String>>) ((EntryInfo) info.guiValue).widget).apply(widget, doneButton);
|
||||
widget.setFilter(processor);
|
||||
this.list.addButton(widget, resetButton, null, name);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (ConfigCategory.class.isAssignableFrom(info.getClass()))
|
||||
{
|
||||
Button widget = MakeBtn(name, this.width / 2 - 100, this.height - 28, 100 * 2, 20, (button -> {
|
||||
ConfigBase.INSTANCE.configFileINSTANCE.saveToFile();
|
||||
Objects.requireNonNull(minecraft).setScreen(ClassicConfigGUI.getScreen(this.configBase, this, ((ConfigCategory) info).getDestination()));
|
||||
}));
|
||||
this.list.addButton(widget, null, null, null);
|
||||
return;
|
||||
}
|
||||
if (ConfigUIButton.class.isAssignableFrom(info.getClass()))
|
||||
{
|
||||
Button widget = MakeBtn(name, this.width / 2 - 100, this.height - 28, 100 * 2, 20, (button -> {
|
||||
((ConfigUIButton) info).runAction();
|
||||
}));
|
||||
this.list.addButton(widget, null, null, null);
|
||||
return;
|
||||
}
|
||||
if (ConfigUIComment.class.isAssignableFrom(info.getClass()))
|
||||
{
|
||||
this.list.addButton(null, null, null, name);
|
||||
return;
|
||||
}
|
||||
if (ConfigLinkedEntry.class.isAssignableFrom(info.getClass()))
|
||||
{
|
||||
this.addMenuItem(((ConfigLinkedEntry) info).get());
|
||||
return;
|
||||
}
|
||||
|
||||
LOGGER.warn("Config [" + info.getNameWCategory() + "] failed to show. Please try something like changing its type.");
|
||||
}
|
||||
|
||||
@Override
|
||||
#if MC_VER < MC_1_20_1
|
||||
public void render(PoseStack matrices, int mouseX, int mouseY, float delta)
|
||||
#else
|
||||
public void render(GuiGraphics matrices, int mouseX, int mouseY, float delta)
|
||||
#endif
|
||||
{
|
||||
#if MC_VER < MC_1_20_2 // 1.20.2 now enables this by default in the `this.list.render` function
|
||||
this.renderBackground(matrices); // Renders background
|
||||
#else
|
||||
super.render(matrices, mouseX, mouseY, delta);
|
||||
#endif
|
||||
this.list.render(matrices, mouseX, mouseY, delta); // Render buttons
|
||||
|
||||
DhDrawCenteredString(matrices, font, title, width / 2, 15, 0xFFFFFF); // Render title
|
||||
|
||||
if (this.configBase.modID.equals("distanthorizons"))
|
||||
{
|
||||
// Display version
|
||||
DhDrawString(matrices, font, TextOrLiteral(ModInfo.VERSION), 2, height - 10, 0xAAAAAA);
|
||||
|
||||
// If the update is pending, display this message to inform the user that it will apply when the game restarts
|
||||
if (SelfUpdater.deleteOldJarOnJvmShutdown)
|
||||
DhDrawString(matrices, font, Translatable(configBase.modID + ".updater.waitingForClose"), 4, height - 38, 0xFFFFFF);
|
||||
}
|
||||
|
||||
|
||||
// Render the tooltip only if it can find a tooltip in the language file
|
||||
for (AbstractConfigType info : ConfigBase.INSTANCE.entries)
|
||||
{
|
||||
if (info.getCategory().matches(category) && info.getAppearance().showInGui)
|
||||
{
|
||||
if (list.getHoveredButton(mouseX, mouseY).isPresent())
|
||||
{
|
||||
AbstractWidget buttonWidget = list.getHoveredButton(mouseX, mouseY).get();
|
||||
Component text = ButtonEntry.buttonsWithText.get(buttonWidget);
|
||||
if (text == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// A quick fix for tooltips on linked entries
|
||||
AbstractConfigType newInfo = ConfigLinkedEntry.class.isAssignableFrom(info.getClass()) ?
|
||||
((ConfigLinkedEntry) info).get() :
|
||||
info;
|
||||
|
||||
Component name = Translatable(this.translationPrefix + (info.category.isEmpty() ? "" : info.category + ".") + info.getName());
|
||||
String key = translationPrefix + (newInfo.category.isEmpty() ? "" : newInfo.category + ".") + newInfo.getName() + ".@tooltip";
|
||||
|
||||
if (((EntryInfo) newInfo.guiValue).error != null && text.equals(name))
|
||||
DhRenderTooltip(matrices, font, ((EntryInfo) newInfo.guiValue).error.getValue(), mouseX, mouseY);
|
||||
else if (I18n.exists(key) && (text != null && text.equals(name)))
|
||||
{
|
||||
List<Component> list = new ArrayList<>();
|
||||
for (String str : I18n.get(key).split("\n"))
|
||||
{
|
||||
list.add(TextOrTranslatable(str));
|
||||
}
|
||||
DhRenderComponentTooltip(matrices, font, list, mouseX, mouseY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#if MC_VER < MC_1_20_2
|
||||
super.render(matrices, mouseX, mouseY, delta);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private static void initEntry(AbstractConfigType info, String translationPrefix)
|
||||
{
|
||||
info.guiValue = new EntryInfo();
|
||||
Class<?> fieldClass = info.getType();
|
||||
|
||||
if (ConfigEntry.class.isAssignableFrom(info.getClass()))
|
||||
{
|
||||
if (fieldClass == Integer.class)
|
||||
{
|
||||
// For int
|
||||
textField(info, Integer::parseInt, INTEGER_ONLY_REGEX, true);
|
||||
}
|
||||
else if (fieldClass == Double.class)
|
||||
{
|
||||
// For double
|
||||
textField(info, Double::parseDouble, DECIMAL_ONLY_REGEX, false);
|
||||
}
|
||||
else if (fieldClass == String.class || fieldClass == List.class)
|
||||
{
|
||||
// For string or list
|
||||
textField(info, String::length, null, true);
|
||||
}
|
||||
else if (fieldClass == Boolean.class)
|
||||
{
|
||||
// For boolean
|
||||
Function<Object, Component> func = value -> Translatable("distanthorizons.general."+((Boolean) value ? "true" : "false")).withStyle((Boolean) value ? ChatFormatting.GREEN : ChatFormatting.RED);
|
||||
|
||||
((EntryInfo) info.guiValue).widget = new AbstractMap.SimpleEntry<Button.OnPress, Function<Object, Component>>(button -> {
|
||||
((ConfigEntry) info).uiSetWithoutSaving(!(Boolean) info.get());
|
||||
button.setMessage(func.apply(info.get()));
|
||||
}, func);
|
||||
}
|
||||
else if (fieldClass.isEnum())
|
||||
{
|
||||
// For enum
|
||||
List<?> values = Arrays.asList(info.getType().getEnumConstants());
|
||||
Function<Object, Component> func = value -> Translatable(translationPrefix + "enum." + fieldClass.getSimpleName() + "." + info.get().toString());
|
||||
((EntryInfo) info.guiValue).widget = new AbstractMap.SimpleEntry<Button.OnPress, Function<Object, Component>>(button -> {
|
||||
|
||||
// get the currently selected enum and enum index
|
||||
int startingIndex = values.indexOf(info.get());
|
||||
Enum<?> enumValue = (Enum<?>) values.get(startingIndex);
|
||||
|
||||
// search for the next enum that is selectable
|
||||
int index = startingIndex + 1;
|
||||
index = (index >= values.size()) ? 0 : index;
|
||||
while (index != startingIndex)
|
||||
{
|
||||
enumValue = (Enum<?>) values.get(index);
|
||||
if (!AnnotationUtil.doesEnumHaveAnnotation(enumValue, DisallowSelectingViaConfigGui.class))
|
||||
{
|
||||
// this enum shouldn't be selectable via the UI,
|
||||
// skip it
|
||||
break;
|
||||
}
|
||||
|
||||
index++;
|
||||
index = (index >= values.size()) ? 0 : index;
|
||||
}
|
||||
|
||||
if (index == startingIndex)
|
||||
{
|
||||
// none of the enums should be selectable, this is a programmer error
|
||||
enumValue = (Enum<?>) values.get(startingIndex);
|
||||
LOGGER.warn("Enum [" + enumValue.getClass() + "] doesn't contain any values that should be selectable via the UI, sticking to the currently selected value [" + enumValue + "].");
|
||||
}
|
||||
|
||||
|
||||
((ConfigEntry<Enum<?>>) info).uiSetWithoutSaving(enumValue);
|
||||
button.setMessage(func.apply(info.get()));
|
||||
}, func);
|
||||
}
|
||||
}
|
||||
else if (ConfigCategory.class.isAssignableFrom(info.getClass()))
|
||||
{
|
||||
// if (!info.info.getName().equals(""))
|
||||
// info.name = new TranslatableComponent(info.info.getName());
|
||||
}
|
||||
// return info;
|
||||
}
|
||||
|
||||
public static class ConfigListWidget extends ContainerObjectSelectionList<ButtonEntry>
|
||||
{
|
||||
Font textRenderer;
|
||||
|
||||
public ConfigListWidget(Minecraft minecraftClient, int canvasWidth, int canvasHeight, int topMargin, int botMargin, int itemSpacing)
|
||||
{
|
||||
#if MC_VER < MC_1_20_4
|
||||
super(minecraftClient, canvasWidth, canvasHeight, topMargin, canvasHeight - botMargin, itemSpacing);
|
||||
#else
|
||||
super(minecraftClient, canvasWidth, canvasHeight - (topMargin + botMargin), topMargin, itemSpacing);
|
||||
#endif
|
||||
this.centerListVertically = false;
|
||||
textRenderer = minecraftClient.font;
|
||||
}
|
||||
|
||||
public void addButton(AbstractWidget button, AbstractWidget resetButton, AbstractWidget indexButton, Component text)
|
||||
{
|
||||
this.addEntry(ButtonEntry.create(button, text, resetButton, indexButton));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRowWidth()
|
||||
{
|
||||
return 10000;
|
||||
}
|
||||
|
||||
public Optional<AbstractWidget> getHoveredButton(double mouseX, double mouseY)
|
||||
{
|
||||
for (ButtonEntry buttonEntry : this.children())
|
||||
{
|
||||
if (buttonEntry.button != null && buttonEntry.button.isMouseOver(mouseX, mouseY))
|
||||
{
|
||||
return Optional.of(buttonEntry.button);
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static class ButtonEntry extends ContainerObjectSelectionList.Entry<ButtonEntry>
|
||||
{
|
||||
private static final Font textRenderer = Minecraft.getInstance().font;
|
||||
public final AbstractWidget button;
|
||||
private final AbstractWidget resetButton;
|
||||
private final AbstractWidget indexButton;
|
||||
private final Component text;
|
||||
private final List<AbstractWidget> children = new ArrayList<>();
|
||||
public static final Map<AbstractWidget, Component> buttonsWithText = new HashMap<>();
|
||||
|
||||
private ButtonEntry(AbstractWidget button, Component text, AbstractWidget resetButton, AbstractWidget indexButton)
|
||||
{
|
||||
buttonsWithText.put(button, text);
|
||||
this.button = button;
|
||||
this.resetButton = resetButton;
|
||||
this.text = text;
|
||||
this.indexButton = indexButton;
|
||||
if (button != null)
|
||||
children.add(button);
|
||||
if (resetButton != null)
|
||||
children.add(resetButton);
|
||||
if (indexButton != null)
|
||||
children.add(indexButton);
|
||||
}
|
||||
|
||||
public static ButtonEntry create(AbstractWidget button, Component text, AbstractWidget resetButton, AbstractWidget indexButton)
|
||||
{
|
||||
return new ButtonEntry(button, text, resetButton, indexButton);
|
||||
}
|
||||
|
||||
@Override
|
||||
#if MC_VER < MC_1_20_1
|
||||
public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta)
|
||||
#else
|
||||
public void render(GuiGraphics matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta)
|
||||
#endif
|
||||
{
|
||||
if (button != null)
|
||||
{
|
||||
SetY(button, y);
|
||||
button.render(matrices, mouseX, mouseY, tickDelta);
|
||||
}
|
||||
if (resetButton != null)
|
||||
{
|
||||
SetY(resetButton, y);
|
||||
resetButton.render(matrices, mouseX, mouseY, tickDelta);
|
||||
}
|
||||
if (indexButton != null)
|
||||
{
|
||||
SetY(indexButton, y);
|
||||
indexButton.render(matrices, mouseX, mouseY, tickDelta);
|
||||
}
|
||||
if (text != null && (!text.getString().contains("spacer") || button != null))
|
||||
#if MC_VER < MC_1_20_1
|
||||
GuiComponent.drawString(matrices, textRenderer, text, 12, y + 5, 0xFFFFFF);
|
||||
#else
|
||||
matrices.drawString(textRenderer, text, 12, y + 5, 0xFFFFFF);
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends GuiEventListener> children()
|
||||
{
|
||||
return children;
|
||||
}
|
||||
|
||||
// Only for 1.17 and over
|
||||
// Remove in 1.16 and below
|
||||
#if MC_VER >= MC_1_17_1
|
||||
@Override
|
||||
public List<? extends NarratableEntry> narratables()
|
||||
{
|
||||
return children;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// event handling //
|
||||
//================//
|
||||
|
||||
private static class ConfigCoreInterface implements IConfigGui
|
||||
{
|
||||
/**
|
||||
* in the future it would be good to pass in the current page and other variables,
|
||||
* but for now just knowing when the page is closed is good enough
|
||||
*/
|
||||
public final ArrayList<Runnable> onScreenChangeListenerList = new ArrayList<>();
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void addOnScreenChangeListener(Runnable newListener) { this.onScreenChangeListenerList.add(newListener); }
|
||||
@Override
|
||||
public void removeOnScreenChangeListener(Runnable oldListener) { this.onScreenChangeListenerList.remove(oldListener); }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package com.seibel.distanthorizons.common.wrappers.gui;
|
||||
|
||||
import net.minecraft.client.gui.Font;
|
||||
#if MC_VER < MC_1_20_1
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
#else
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
#endif
|
||||
import net.minecraft.client.gui.components.Button;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import net.minecraft.network.chat.Component;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class DhScreen extends Screen
|
||||
{
|
||||
|
||||
protected DhScreen(Component $$0)
|
||||
{
|
||||
super($$0);
|
||||
}
|
||||
|
||||
// addRenderableWidget in 1.17 and over
|
||||
// addButton in 1.16 and below
|
||||
protected Button addBtn(Button button)
|
||||
{
|
||||
#if MC_VER < MC_1_17_1
|
||||
return this.addButton(button);
|
||||
#else
|
||||
return this.addRenderableWidget(button);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if MC_VER < MC_1_20_1
|
||||
protected void DhDrawCenteredString(PoseStack guiStack, Font font, Component text, int x, int y, int color)
|
||||
{
|
||||
drawCenteredString(guiStack, font, text, x, y, color);
|
||||
}
|
||||
protected void DhDrawString(PoseStack guiStack, Font font, Component text, int x, int y, int color)
|
||||
{
|
||||
drawString(guiStack, font, text, x, y, color);
|
||||
}
|
||||
protected void DhRenderTooltip(PoseStack guiStack, Font font, List<? extends net.minecraft.util.FormattedCharSequence> text, int x, int y)
|
||||
{
|
||||
renderTooltip(guiStack, text, x, y);
|
||||
}
|
||||
protected void DhRenderComponentTooltip(PoseStack guiStack, Font font, List<Component> comp, int x, int y)
|
||||
{
|
||||
renderComponentTooltip(guiStack, comp, x, y);
|
||||
}
|
||||
protected void DhRenderTooltip(PoseStack guiStack, Font font, Component comp, int x, int y)
|
||||
{
|
||||
renderTooltip(guiStack, comp, x, y);
|
||||
}
|
||||
#else
|
||||
protected void DhDrawCenteredString(GuiGraphics guiStack, Font font, Component text, int x, int y, int color)
|
||||
{
|
||||
guiStack.drawCenteredString(font, text, x, y, color);
|
||||
}
|
||||
protected void DhDrawString(GuiGraphics guiStack, Font font, Component text, int x, int y, int color)
|
||||
{
|
||||
guiStack.drawString(font, text, x, y, color);
|
||||
}
|
||||
protected void DhRenderTooltip(GuiGraphics guiStack, Font font, List<? extends net.minecraft.util.FormattedCharSequence> text, int x, int y)
|
||||
{
|
||||
guiStack.renderTooltip(font, text, x, y);
|
||||
}
|
||||
protected void DhRenderComponentTooltip(GuiGraphics guiStack, Font font, List<Component> comp, int x, int y)
|
||||
{
|
||||
guiStack.renderComponentTooltip(font, comp, x, y);
|
||||
}
|
||||
protected void DhRenderTooltip(GuiGraphics guiStack, Font font, Component text, int x, int y)
|
||||
{
|
||||
guiStack.renderTooltip(font, text, x, y);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
package com.seibel.distanthorizons.common.wrappers.gui;
|
||||
|
||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||
import com.seibel.distanthorizons.core.config.ConfigBase;
|
||||
import com.seibel.distanthorizons.core.config.gui.ConfigScreen;
|
||||
import com.seibel.distanthorizons.core.config.gui.JavaScreenHandlerScreen;
|
||||
import com.seibel.distanthorizons.core.config.gui.OpenGLConfigScreen;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
|
||||
public class GetConfigScreen
|
||||
{
|
||||
public static type useScreen = type.Classic;
|
||||
|
||||
public enum type
|
||||
{
|
||||
Classic,
|
||||
@Deprecated
|
||||
OpenGL, // This was just an attempt, it didn't work out, and we are going to change to javafx soon (as soon as that works)
|
||||
JavaFX;
|
||||
}
|
||||
|
||||
public static Screen getScreen(Screen parent)
|
||||
{
|
||||
// Generate the language
|
||||
// This shouldn't be here, but I need a way to test it after Minecraft inits its assets
|
||||
//System.out.println(ConfigBase.INSTANCE.generateLang(false, true));
|
||||
|
||||
switch (useScreen)
|
||||
{
|
||||
case Classic:
|
||||
return ClassicConfigGUI.getScreen(ConfigBase.INSTANCE, parent, "client");
|
||||
case OpenGL:
|
||||
MinecraftScreen.getScreen(parent, new OpenGLConfigScreen(), ModInfo.ID + ".title");
|
||||
return null;
|
||||
// case JavaFX -> MinecraftScreen.getScreen(parent, new JavaScreenHandlerScreen(new JavaScreenHandlerScreen.ExampleScreen()), ModInfo.ID + ".title");
|
||||
case JavaFX:
|
||||
return MinecraftScreen.getScreen(parent, new JavaScreenHandlerScreen(new ConfigScreen()), ModInfo.ID + ".title");
|
||||
default:
|
||||
throw new IllegalArgumentException("No config screen implementation defined for ["+useScreen+"].");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.seibel.distanthorizons.common.wrappers.gui;
|
||||
|
||||
import net.minecraft.client.gui.components.AbstractWidget;
|
||||
import net.minecraft.client.gui.components.Button;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
|
||||
#if MC_VER < MC_1_19_2
|
||||
import net.minecraft.network.chat.TextComponent;
|
||||
import net.minecraft.network.chat.TranslatableComponent;
|
||||
#endif
|
||||
|
||||
public class GuiHelper
|
||||
{
|
||||
/**
|
||||
* Helper static methods for versional compat
|
||||
*/
|
||||
public static Button MakeBtn(Component base, int posX, int posZ, int width, int height, Button.OnPress action)
|
||||
{
|
||||
#if MC_VER < MC_1_19_4
|
||||
return new Button(posX, posZ, width, height, base, action);
|
||||
#else
|
||||
return Button.builder(base, action).bounds(posX, posZ, width, height).build();
|
||||
#endif
|
||||
}
|
||||
|
||||
public static MutableComponent TextOrLiteral(String text)
|
||||
{
|
||||
#if MC_VER < MC_1_19_2
|
||||
return new TextComponent(text);
|
||||
#else
|
||||
return Component.literal(text);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static MutableComponent TextOrTranslatable(String text)
|
||||
{
|
||||
#if MC_VER < MC_1_19_2
|
||||
return new TextComponent(text);
|
||||
#else
|
||||
return Component.translatable(text);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static MutableComponent Translatable(String text, Object... args)
|
||||
{
|
||||
#if MC_VER < MC_1_19_2
|
||||
return new TranslatableComponent(text, args);
|
||||
#else
|
||||
return Component.translatable(text, args);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void SetX(AbstractWidget w, int x)
|
||||
{
|
||||
#if MC_VER < MC_1_19_4
|
||||
w.x = x;
|
||||
#else
|
||||
w.setX(x);
|
||||
#endif
|
||||
}
|
||||
|
||||
public static void SetY(AbstractWidget w, int y)
|
||||
{
|
||||
#if MC_VER < MC_1_19_4
|
||||
w.y = y;
|
||||
#else
|
||||
w.setY(y);
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.seibel.distanthorizons.common.wrappers.gui;
|
||||
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.config.ILangWrapper;
|
||||
import net.minecraft.client.resources.language.I18n;
|
||||
|
||||
public class LangWrapper implements ILangWrapper
|
||||
{
|
||||
public static final LangWrapper INSTANCE = new LangWrapper();
|
||||
@Override
|
||||
public boolean langExists(String str)
|
||||
{
|
||||
return I18n.exists(str);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLang(String str)
|
||||
{
|
||||
return I18n.get(str);
|
||||
}
|
||||
|
||||
}
|
||||
+150
@@ -0,0 +1,150 @@
|
||||
package com.seibel.distanthorizons.common.wrappers.gui;
|
||||
|
||||
import com.mojang.blaze3d.platform.Window;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.seibel.distanthorizons.core.config.gui.AbstractScreen;
|
||||
import net.minecraft.client.Minecraft;
|
||||
#if MC_VER >= MC_1_20_1
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
#endif
|
||||
import net.minecraft.client.gui.components.ContainerObjectSelectionList;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
public class MinecraftScreen
|
||||
{
|
||||
public static Screen getScreen(Screen parent, AbstractScreen screen, String translationName)
|
||||
{
|
||||
return new ConfigScreenRenderer(parent, screen, translationName);
|
||||
}
|
||||
|
||||
private static class ConfigScreenRenderer extends DhScreen
|
||||
{
|
||||
private final Screen parent;
|
||||
private ConfigListWidget list;
|
||||
private AbstractScreen screen;
|
||||
|
||||
|
||||
#if MC_VER < MC_1_19_2
|
||||
public static net.minecraft.network.chat.TranslatableComponent translate(String str, Object... args)
|
||||
{
|
||||
return new net.minecraft.network.chat.TranslatableComponent(str, args);
|
||||
}
|
||||
#else
|
||||
public static net.minecraft.network.chat.MutableComponent translate(String str, Object... args)
|
||||
{
|
||||
return net.minecraft.network.chat.Component.translatable(str, args);
|
||||
}
|
||||
#endif
|
||||
|
||||
protected ConfigScreenRenderer(Screen parent, AbstractScreen screen, String translationName)
|
||||
{
|
||||
super(translate(translationName));
|
||||
screen.minecraftWindow = Minecraft.getInstance().getWindow().getWindow();
|
||||
this.parent = parent;
|
||||
this.screen = screen;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init()
|
||||
{
|
||||
super.init(); // Init Minecraft's screen
|
||||
Window mcWindow = this.minecraft.getWindow();
|
||||
screen.width = mcWindow.getWidth();
|
||||
screen.height = mcWindow.getHeight();
|
||||
screen.scaledWidth = this.width;
|
||||
screen.scaledHeight = this.height;
|
||||
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
|
||||
|
||||
#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
|
||||
this.list.setRenderBackground(false); // Disable from rendering
|
||||
#endif
|
||||
|
||||
this.addWidget(this.list); // Add the tint to the things to be rendered
|
||||
}
|
||||
|
||||
@Override
|
||||
#if MC_VER < MC_1_20_1
|
||||
public void render(PoseStack matrices, int mouseX, int mouseY, float delta)
|
||||
#else
|
||||
public void render(GuiGraphics matrices, int mouseX, int mouseY, float delta)
|
||||
#endif
|
||||
{
|
||||
#if MC_VER < MC_1_20_2
|
||||
this.renderBackground(matrices); // Render background
|
||||
#else
|
||||
this.renderBackground(matrices, mouseX, mouseY, delta); // Render background
|
||||
#endif
|
||||
this.list.render(matrices, mouseX, mouseY, delta); // Renders the items in the render list (currently only used to tint background darker)
|
||||
|
||||
screen.mouseX = mouseX;
|
||||
screen.mouseY = mouseY;
|
||||
screen.render(delta); // Render everything on the main screen
|
||||
|
||||
super.render(matrices, mouseX, mouseY, delta); // Render the vanilla stuff (currently only used for the background and tint)
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resize(Minecraft mc, int width, int height)
|
||||
{
|
||||
super.resize(mc, width, height); // Resize Minecraft's screen
|
||||
Window mcWindow = this.minecraft.getWindow();
|
||||
screen.width = mcWindow.getWidth();
|
||||
screen.height = mcWindow.getHeight();
|
||||
screen.scaledWidth = this.width;
|
||||
screen.scaledHeight = this.height;
|
||||
screen.onResize(); // Resize our screen
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick()
|
||||
{
|
||||
super.tick(); // Tick Minecraft's screen
|
||||
screen.tick(); // Tick our screen
|
||||
if (screen.close) // If we decide to close the screen, then actually close the screen
|
||||
onClose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose()
|
||||
{
|
||||
screen.onClose(); // Close our screen
|
||||
Objects.requireNonNull(minecraft).setScreen(this.parent); // Goto the parent screen
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFilesDrop(@NotNull List<Path> files)
|
||||
{
|
||||
screen.onFilesDrop(files);
|
||||
}
|
||||
|
||||
// For checking if it should close when you press the escape key
|
||||
@Override
|
||||
public boolean shouldCloseOnEsc()
|
||||
{
|
||||
return screen.shouldCloseOnEsc;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class ConfigListWidget extends ContainerObjectSelectionList
|
||||
{
|
||||
public ConfigListWidget(Minecraft minecraftClient, int canvasWidth, int canvasHeight, int topMargin, int botMargin, int itemSpacing)
|
||||
{
|
||||
#if MC_VER < MC_1_20_4
|
||||
super(minecraftClient, canvasWidth, canvasHeight, topMargin, canvasHeight - botMargin, itemSpacing);
|
||||
#else
|
||||
super(minecraftClient, canvasWidth, canvasHeight - (topMargin + botMargin), topMargin, itemSpacing);
|
||||
#endif
|
||||
this.centerListVertically = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
/*
|
||||
* 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.gui;
|
||||
|
||||
/**
|
||||
* Creates a button with a texture on it (and a background) that works with all mc versions
|
||||
*
|
||||
* @author coolGi
|
||||
* @version 2023-10-03
|
||||
*/
|
||||
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import net.minecraft.client.gui.components.AbstractButton;
|
||||
import net.minecraft.client.gui.components.Button;
|
||||
import net.minecraft.client.gui.components.ImageButton;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
#if MC_VER >= MC_1_17_1
|
||||
import net.minecraft.client.renderer.GameRenderer;
|
||||
#endif
|
||||
#if MC_VER < MC_1_20_1
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.Minecraft;
|
||||
#else
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
#endif
|
||||
|
||||
#if MC_VER < MC_1_20_2
|
||||
public class TexturedButtonWidget extends ImageButton
|
||||
#else
|
||||
public class TexturedButtonWidget extends Button
|
||||
#endif
|
||||
{
|
||||
public final boolean renderBackground;
|
||||
|
||||
#if MC_VER >= MC_1_20_2
|
||||
private final int u;
|
||||
private final int v;
|
||||
private final int hoveredVOffset;
|
||||
|
||||
private final ResourceLocation texture;
|
||||
|
||||
private final int textureWidth;
|
||||
private final int textureHeight;
|
||||
#endif
|
||||
|
||||
|
||||
public TexturedButtonWidget(int x, int y, int width, int height, int u, int v, int hoveredVOffset, ResourceLocation texture, int textureWidth, int textureHeight, OnPress pressAction, Component text) {
|
||||
this(x, y, width, height, u, v, hoveredVOffset, texture, textureWidth, textureHeight, pressAction, text, true);
|
||||
}
|
||||
public TexturedButtonWidget(int x, int y, int width, int height, int u, int v, int hoveredVOffset, ResourceLocation texture, int textureWidth, int textureHeight, OnPress pressAction, Component text, boolean renderBackground)
|
||||
{
|
||||
#if MC_VER < MC_1_20_2
|
||||
super(x, y, width, height, u, v, hoveredVOffset, texture, textureWidth, textureHeight, pressAction, text);
|
||||
#else
|
||||
// We don't pass on the text option as otherwise it will render (we normally pass it for narration)
|
||||
// TODO: Find a fix for it
|
||||
super(x, y, width, height, Component.empty(), pressAction, DEFAULT_NARRATION);
|
||||
|
||||
this.u = u;
|
||||
this.v = v;
|
||||
this.hoveredVOffset = hoveredVOffset;
|
||||
|
||||
this.texture = texture;
|
||||
|
||||
this.textureWidth = textureWidth;
|
||||
this.textureHeight = textureHeight;
|
||||
#endif
|
||||
|
||||
this.renderBackground = renderBackground;
|
||||
}
|
||||
|
||||
#if MC_VER < MC_1_20_2
|
||||
#if MC_VER < MC_1_19_4
|
||||
@Override
|
||||
public void renderButton(PoseStack matrices, int mouseX, int mouseY, float delta) {
|
||||
if (this.renderBackground) // Renders the background of the button
|
||||
{
|
||||
#if MC_VER < MC_1_17_1
|
||||
Minecraft.getInstance().getTextureManager().bind(WIDGETS_LOCATION);
|
||||
RenderSystem.color4f(1.0F, 1.0F, 1.0F, this.alpha);
|
||||
#else
|
||||
RenderSystem.setShader(GameRenderer::getPositionTexShader);
|
||||
RenderSystem.setShaderTexture(0, WIDGETS_LOCATION);
|
||||
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, this.alpha);
|
||||
#endif
|
||||
|
||||
int i = this.getYImage(this.isHovered);
|
||||
RenderSystem.enableBlend();
|
||||
RenderSystem.defaultBlendFunc();
|
||||
RenderSystem.enableDepthTest();
|
||||
#if MC_VER < MC_1_19_4
|
||||
this.blit(matrices, this.x, this.y, 0, 46 + i * 20, this.width / 2, this.height);
|
||||
this.blit(matrices, this.x + this.width / 2, this.y, 200 - this.width / 2, 46 + i * 20, this.width / 2, this.height);
|
||||
#else
|
||||
this.blit(matrices, this.getX(), this.getY(), 0, 46 + i * 20, this.getWidth() / 2, this.getHeight());
|
||||
this.blit(matrices, this.getX() + this.getWidth() / 2, this.getY(), 200 - this.width / 2, 46 + i * 20, this.getWidth() / 2, this.getHeight());
|
||||
#endif
|
||||
}
|
||||
|
||||
super.renderButton(matrices, mouseX, mouseY, delta);
|
||||
}
|
||||
#else
|
||||
#if MC_VER < MC_1_20_1
|
||||
@Override
|
||||
public void renderWidget(PoseStack matrices, int mouseX, int mouseY, float delta)
|
||||
{
|
||||
RenderSystem.setShader(GameRenderer::getPositionTexShader);
|
||||
RenderSystem.setShaderTexture(0, WIDGETS_LOCATION);
|
||||
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, this.alpha);
|
||||
#else
|
||||
@Override
|
||||
public void renderWidget(GuiGraphics matrices, int mouseX, int mouseY, float delta)
|
||||
{
|
||||
#endif
|
||||
if (this.renderBackground) // Renders the background of the button
|
||||
{
|
||||
int i = 1;
|
||||
if (!this.active) i = 0;
|
||||
else if (this.isHovered) i = 2;
|
||||
|
||||
#if MC_VER < MC_1_20_1
|
||||
RenderSystem.enableBlend();
|
||||
RenderSystem.defaultBlendFunc();
|
||||
RenderSystem.enableDepthTest();
|
||||
|
||||
this.blit(matrices, this.getX(), this.getY(), 0, 46 + i * 20, this.getWidth() / 2, this.getHeight());
|
||||
this.blit(matrices, this.getX() + this.getWidth() / 2, this.getY(), 200 - this.width / 2, 46 + i * 20, this.getWidth() / 2, this.getHeight());
|
||||
#else
|
||||
matrices.blit(WIDGETS_LOCATION, this.getX(), this.getY(), 0, 46 + i * 20, this.getWidth() / 2, this.getHeight());
|
||||
matrices.blit(WIDGETS_LOCATION, this.getX() + this.getWidth() / 2, this.getY(), 200 - this.width / 2, 46 + i * 20, this.getWidth() / 2, this.getHeight());
|
||||
#endif
|
||||
}
|
||||
|
||||
super.renderWidget(matrices, mouseX, mouseY, delta);
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
@Override
|
||||
public void renderWidget(GuiGraphics matrices, int mouseX, int mouseY, float delta)
|
||||
{
|
||||
if (this.renderBackground)
|
||||
{
|
||||
//RenderSystem.enableBlend();
|
||||
//RenderSystem.enableDepthTest();
|
||||
matrices.blitSprite(SPRITES.get(this.active, this.isHoveredOrFocused()), this.getX(), this.getY(), this.getWidth(), this.getHeight());
|
||||
}
|
||||
|
||||
|
||||
// Renders the sprite
|
||||
int i = 0;
|
||||
if (!this.active) i = 2;
|
||||
else if (this.isHovered) i = 1;
|
||||
|
||||
matrices.blit(this.texture, this.getX(), this.getY(), this.u, this.v + (this.hoveredVOffset * i), this.width, this.height, this.textureWidth, this.textureHeight);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
+255
@@ -0,0 +1,255 @@
|
||||
package com.seibel.distanthorizons.common.wrappers.gui.updater;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.seibel.distanthorizons.common.wrappers.gui.DhScreen;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
|
||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||
import com.seibel.distanthorizons.core.jar.installer.MarkdownFormatter;
|
||||
import com.seibel.distanthorizons.core.jar.installer.ModrinthGetter;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.Font;
|
||||
import net.minecraft.client.gui.components.AbstractWidget;
|
||||
import net.minecraft.client.gui.components.ContainerObjectSelectionList;
|
||||
import net.minecraft.client.gui.components.events.GuiEventListener;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import net.minecraft.network.chat.Component;
|
||||
|
||||
#if MC_VER >= MC_1_17_1
|
||||
import net.minecraft.client.gui.narration.NarratableEntry;
|
||||
#endif
|
||||
|
||||
#if MC_VER < MC_1_20_1
|
||||
import net.minecraft.client.gui.GuiComponent;
|
||||
#else
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
#endif
|
||||
|
||||
|
||||
import static com.seibel.distanthorizons.common.wrappers.gui.GuiHelper.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* The screen that pops up if the mod has an update.
|
||||
*
|
||||
* @author coolGi
|
||||
*/
|
||||
// TODO: After finishing the config, rewrite this in openGL as well
|
||||
// TODO: Make this
|
||||
public class ChangelogScreen extends DhScreen
|
||||
{
|
||||
private Screen parent;
|
||||
private String versionID;
|
||||
private List<String> changelog;
|
||||
private TextArea changelogArea;
|
||||
|
||||
public boolean usable = false;
|
||||
|
||||
public ChangelogScreen(Screen parent)
|
||||
{
|
||||
this(parent, null);
|
||||
|
||||
if (!ModrinthGetter.initted) // Make sure the modrinth stuff is initted
|
||||
ModrinthGetter.init();
|
||||
if (!ModrinthGetter.initted) // If its not initted, then this isnt usable
|
||||
return;
|
||||
|
||||
if (!ModrinthGetter.mcVersions.contains(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion()))
|
||||
return;
|
||||
|
||||
String versionID = ModrinthGetter.getLatestIDForVersion(SingletonInjector.INSTANCE.get(IVersionConstants.class).getMinecraftVersion());
|
||||
if (versionID == null)
|
||||
return;
|
||||
try
|
||||
{
|
||||
setupChangelog(versionID);
|
||||
usable = true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public ChangelogScreen(Screen parent, String versionID)
|
||||
{
|
||||
super(Translatable(ModInfo.ID + ".updater.title"));
|
||||
this.parent = parent;
|
||||
this.versionID = versionID;
|
||||
|
||||
|
||||
if (versionID == null)
|
||||
return;
|
||||
try
|
||||
{
|
||||
setupChangelog(versionID);
|
||||
usable = true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void setupChangelog(String versionID)
|
||||
{
|
||||
this.changelog = new ArrayList<>();
|
||||
|
||||
// Put the new version name at the very top of the change log
|
||||
this.changelog.add("§lChangelog for " + ModrinthGetter.releaseNames.get(versionID) + "§r");
|
||||
this.changelog.add("");
|
||||
this.changelog.add("");
|
||||
|
||||
// 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+
|
||||
new MarkdownFormatter.MinecraftFormat().convertTo( // This formats markdown to minecraft's "§" characters
|
||||
ModrinthGetter.changeLogs.get(versionID)
|
||||
).split("\\n");
|
||||
// Makes the words wrap around to not go off the screen
|
||||
for (String str : unwrappedChangelog)
|
||||
{
|
||||
this.changelog.addAll(
|
||||
MarkdownFormatter.splitString(str, 75)
|
||||
);
|
||||
}
|
||||
// Debugging
|
||||
// System.out.println(this.changelog);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
protected void init()
|
||||
{
|
||||
super.init();
|
||||
if (!usable)
|
||||
return;
|
||||
|
||||
|
||||
this.addBtn( // Close
|
||||
MakeBtn(Translatable(ModInfo.ID + ".general.back"), 5, this.height - 25, 100, 20, (btn) -> {
|
||||
this.onClose();
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
this.changelogArea = new TextArea(this.minecraft, this.width * 2, this.height, 32, 32, 10);
|
||||
for (int i = 0; i < changelog.size(); i++)
|
||||
{
|
||||
this.changelogArea.addButton(TextOrLiteral(changelog.get(i)));
|
||||
// drawString(matrices, this.font, changelog.get(i), this.width / 2 - 175, this.height / 2 - 100 + i*10, 0xFFFFFF);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
#if MC_VER < MC_1_20_1
|
||||
public void render(PoseStack matrices, int mouseX, int mouseY, float delta)
|
||||
#else
|
||||
public void render(GuiGraphics matrices, int mouseX, int mouseY, float delta)
|
||||
#endif
|
||||
{
|
||||
#if MC_VER < MC_1_20_2
|
||||
this.renderBackground(matrices); // Render background
|
||||
#else
|
||||
this.renderBackground(matrices, mouseX, mouseY, delta); // Render background
|
||||
#endif
|
||||
if (!usable)
|
||||
return;
|
||||
|
||||
// Set the scroll position to the mouse height relative to the screen
|
||||
// This is a bit of a hack as we cannot scroll on this area
|
||||
double scrollAmount = ((double) mouseY) / ((double) this.height) * 1.1 * this.changelogArea.getMaxScroll();
|
||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||
this.changelogArea.setScrollAmount(scrollAmount);
|
||||
#else
|
||||
this.changelogArea.scrollAmount = scrollAmount;
|
||||
#endif
|
||||
|
||||
|
||||
// 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
|
||||
this.changelogArea.render(matrices, mouseX, mouseY, delta); // Render the changelog
|
||||
DhDrawCenteredString(matrices, font, title, width / 2, 15, 0xFFFFFF); // Render title
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose()
|
||||
{
|
||||
Objects.requireNonNull(minecraft).setScreen(this.parent); // Goto the parent screen
|
||||
}
|
||||
|
||||
public static class TextArea extends ContainerObjectSelectionList<ButtonEntry>
|
||||
{
|
||||
Font textRenderer;
|
||||
|
||||
public TextArea(Minecraft minecraftClient, int canvasWidth, int canvasHeight, int topMargin, int botMargin, int itemSpacing)
|
||||
{
|
||||
#if MC_VER < MC_1_20_4
|
||||
super(minecraftClient, canvasWidth, canvasHeight, topMargin, canvasHeight - botMargin, itemSpacing);
|
||||
#else
|
||||
super(minecraftClient, canvasWidth, canvasHeight - (topMargin + botMargin), topMargin, itemSpacing);
|
||||
#endif
|
||||
this.centerListVertically = false;
|
||||
textRenderer = minecraftClient.font;
|
||||
}
|
||||
|
||||
public void addButton(Component text)
|
||||
{
|
||||
this.addEntry(ButtonEntry.create(text));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRowWidth()
|
||||
{
|
||||
return 10000;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static class ButtonEntry extends ContainerObjectSelectionList.Entry<ButtonEntry>
|
||||
{
|
||||
private static final Font textRenderer = Minecraft.getInstance().font;
|
||||
private final Component text;
|
||||
private final List<AbstractWidget> children = new ArrayList<>();
|
||||
|
||||
private ButtonEntry(Component text)
|
||||
{
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public static ButtonEntry create(Component text)
|
||||
{
|
||||
return new ButtonEntry(text);
|
||||
}
|
||||
|
||||
#if MC_VER < MC_1_20_1
|
||||
@Override
|
||||
public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta)
|
||||
{
|
||||
GuiComponent.drawString(matrices, textRenderer, text, 12, y + 5, 0xFFFFFF);
|
||||
}
|
||||
#else
|
||||
@Override
|
||||
public void render(GuiGraphics matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta)
|
||||
{
|
||||
matrices.drawString(textRenderer, text, 12, y + 5, 0xFFFFFF);
|
||||
}
|
||||
#endif
|
||||
|
||||
@Override
|
||||
public List<? extends GuiEventListener> children()
|
||||
{
|
||||
return children;
|
||||
}
|
||||
#if MC_VER >= MC_1_17_1
|
||||
@Override
|
||||
public List<? extends NarratableEntry> narratables()
|
||||
{
|
||||
return children;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
+181
@@ -0,0 +1,181 @@
|
||||
package com.seibel.distanthorizons.common.wrappers.gui.updater;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.config.EDhApiUpdateBranch;
|
||||
import com.seibel.distanthorizons.common.wrappers.gui.DhScreen;
|
||||
import com.seibel.distanthorizons.common.wrappers.gui.TexturedButtonWidget;
|
||||
import com.seibel.distanthorizons.core.jar.ModJarInfo;
|
||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.jar.installer.ModrinthGetter;
|
||||
import com.seibel.distanthorizons.core.jar.updater.SelfUpdater;
|
||||
#if MC_VER >= MC_1_20_1
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
#else
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
#endif
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
import static com.seibel.distanthorizons.common.wrappers.gui.GuiHelper.*;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* The screen that pops up if the mod has an update.
|
||||
*
|
||||
* @author coolGi
|
||||
*/
|
||||
// TODO: After finishing the config, rewrite this in Java Swing as well
|
||||
// and also maybe add this suggestion https://discord.com/channels/881614130614767666/1035863487110467625/1035949054485594192
|
||||
public class UpdateModScreen extends DhScreen
|
||||
{
|
||||
private Screen parent;
|
||||
private String newVersionID;
|
||||
|
||||
private String currentVer;
|
||||
private String nextVer;
|
||||
|
||||
|
||||
public UpdateModScreen(Screen parent, String newVersionID)
|
||||
{
|
||||
super(Translatable(ModInfo.ID + ".updater.title"));
|
||||
this.parent = parent;
|
||||
this.newVersionID = newVersionID;
|
||||
|
||||
|
||||
EDhApiUpdateBranch updateBranch = EDhApiUpdateBranch.convertAutoToStableOrNightly(Config.Client.Advanced.AutoUpdater.updateBranch.get());
|
||||
if (updateBranch == EDhApiUpdateBranch.STABLE)
|
||||
{
|
||||
this.currentVer = ModInfo.VERSION;
|
||||
this.nextVer = ModrinthGetter.releaseNames.get(this.newVersionID);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.currentVer = ModJarInfo.Git_Commit.substring(0,7);
|
||||
this.nextVer = this.newVersionID.substring(0,7);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init()
|
||||
{
|
||||
super.init();
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
|
||||
// Logo image
|
||||
this.addBtn(new TexturedButtonWidget(
|
||||
// Where the button is on the screen
|
||||
this.width / 2 - 65, this.height / 2 - 110,
|
||||
// Width and height of the button
|
||||
130, 65,
|
||||
// Offset
|
||||
0, 0,
|
||||
// Some textuary stuff
|
||||
0,
|
||||
#if MC_VER < MC_1_21
|
||||
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
|
||||
// For now it goes to the client option by default
|
||||
(buttonWidget) -> System.out.println("Nice, you found an easter egg :)"), // TODO: Add a proper easter egg to pressing the logo (maybe with confetti)
|
||||
// Add a title to the button
|
||||
Translatable(ModInfo.ID + ".updater.title"),
|
||||
// Dont render the background of the button
|
||||
false
|
||||
));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
if (!ModInfo.IS_DEV_BUILD)
|
||||
{
|
||||
this.addBtn(new TexturedButtonWidget(
|
||||
// Where the button is on the screen
|
||||
this.width / 2 - 97, this.height / 2 + 8,
|
||||
// Width and height of the button
|
||||
20, 20,
|
||||
// Offset
|
||||
0, 0,
|
||||
// Some textuary stuff
|
||||
0,
|
||||
#if MC_VER < MC_1_21
|
||||
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
|
||||
(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
|
||||
Translatable(ModInfo.ID + ".updater.title")
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
this.addBtn( // Update
|
||||
MakeBtn(Translatable(ModInfo.ID + ".updater.update"), this.width / 2 - 75, this.height / 2 + 8, 150, 20, (btn) -> {
|
||||
SelfUpdater.updateMod();
|
||||
this.onClose();
|
||||
})
|
||||
);
|
||||
this.addBtn( // Silent update
|
||||
MakeBtn(Translatable(ModInfo.ID + ".updater.silent"), this.width / 2 - 75, this.height / 2 + 30, 150, 20, (btn) -> {
|
||||
Config.Client.Advanced.AutoUpdater.enableSilentUpdates.set(true);
|
||||
SelfUpdater.updateMod();
|
||||
this.onClose();
|
||||
})
|
||||
);
|
||||
this.addBtn( // Later (not now)
|
||||
MakeBtn(Translatable(ModInfo.ID + ".updater.later"), this.width / 2 + 2, this.height / 2 + 70, 100, 20, (btn) -> {
|
||||
this.onClose();
|
||||
})
|
||||
);
|
||||
this.addBtn( // Never
|
||||
MakeBtn(Translatable(ModInfo.ID + ".updater.never"), this.width / 2 - 102, this.height / 2 + 70, 100, 20, (btn) -> {
|
||||
Config.Client.Advanced.AutoUpdater.enableAutoUpdater.set(false);
|
||||
this.onClose();
|
||||
})
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
#if MC_VER < MC_1_20_1
|
||||
public void render(PoseStack matrices, int mouseX, int mouseY, float delta)
|
||||
#else
|
||||
public void render(GuiGraphics matrices, int mouseX, int mouseY, float delta)
|
||||
#endif
|
||||
{
|
||||
#if MC_VER < MC_1_20_2
|
||||
this.renderBackground(matrices); // Render background
|
||||
#else
|
||||
this.renderBackground(matrices, mouseX, mouseY, delta); // Render background
|
||||
#endif
|
||||
|
||||
// TODO: add the tooltips for the buttons
|
||||
super.render(matrices, mouseX, mouseY, delta); // Render the buttons
|
||||
// TODO: Add tooltips
|
||||
|
||||
// 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.text2", currentVer, nextVer),
|
||||
this.width / 2, this.height / 2 - 20, 0x52FD52);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose()
|
||||
{
|
||||
Objects.requireNonNull(minecraft).setScreen(this.parent); // Goto the parent screen
|
||||
}
|
||||
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
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.IKeyedClientLevelManager;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
public class KeyedClientLevelManager implements IKeyedClientLevelManager
|
||||
{
|
||||
public static final KeyedClientLevelManager INSTANCE = new KeyedClientLevelManager();
|
||||
|
||||
/** This is set and managed by the ClientApi for servers with support for DH. */
|
||||
private IServerKeyedClientLevel overrideWrapper = null;
|
||||
private boolean useOverrideWrapper = false;
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
private KeyedClientLevelManager() { }
|
||||
|
||||
|
||||
|
||||
//======================//
|
||||
// level override logic //
|
||||
//======================//
|
||||
|
||||
@Override
|
||||
public void setServerKeyedLevel(IServerKeyedClientLevel clientLevel) { this.overrideWrapper = clientLevel; }
|
||||
@Override
|
||||
public IServerKeyedClientLevel getOverrideWrapper() { return this.overrideWrapper; }
|
||||
|
||||
@Override
|
||||
public IServerKeyedClientLevel getServerKeyedLevel(ILevelWrapper level, String serverLevelKey)
|
||||
{
|
||||
Objects.requireNonNull(level);
|
||||
Objects.requireNonNull(serverLevelKey);
|
||||
return new ServerKeyedClientLevel((ClientLevel) level.getWrappedMcObject(), serverLevelKey);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setUseOverrideWrapper(boolean useOverrideWrapper) { this.useOverrideWrapper = useOverrideWrapper; }
|
||||
@Override
|
||||
public boolean getUseOverrideWrapper() { return this.useOverrideWrapper; }
|
||||
|
||||
|
||||
|
||||
}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
package com.seibel.distanthorizons.common.wrappers.level;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
|
||||
import com.seibel.distanthorizons.core.level.IServerKeyedClientLevel;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
|
||||
public class ServerKeyedClientLevel extends ClientLevelWrapper implements IServerKeyedClientLevel
|
||||
{
|
||||
/** A unique identifier (generally the level's name) for differentiating multiverse levels */
|
||||
private final String serverLevelKey;
|
||||
|
||||
public ServerKeyedClientLevel(ClientLevel level, String serverLevelKey)
|
||||
{
|
||||
super(level);
|
||||
this.serverLevelKey = serverLevelKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getServerLevelKey() { return this.serverLevelKey; }
|
||||
|
||||
}
|
||||
+313
@@ -0,0 +1,313 @@
|
||||
/*
|
||||
* 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.minecraft;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.ArrayList;
|
||||
import java.util.UUID;
|
||||
|
||||
import com.mojang.blaze3d.platform.NativeImage;
|
||||
import com.seibel.distanthorizons.api.enums.config.EDhApiLodShading;
|
||||
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
|
||||
import com.seibel.distanthorizons.common.wrappers.world.ClientLevelWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.enums.EDhDirection;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import com.seibel.distanthorizons.core.pos.DhBlockPos;
|
||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||
|
||||
import net.minecraft.CrashReport;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.client.resources.model.ModelManager;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
#if MC_VER < MC_1_19_2
|
||||
import net.minecraft.network.chat.TextComponent;
|
||||
#endif
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* A singleton that wraps the Minecraft object.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 3-5-2022
|
||||
*/
|
||||
//@Environment(EnvType.CLIENT)
|
||||
public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecraftSharedWrapper
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
|
||||
|
||||
public static final MinecraftClientWrapper INSTANCE = new MinecraftClientWrapper();
|
||||
|
||||
public final Minecraft mc = Minecraft.getInstance();
|
||||
|
||||
/**
|
||||
* The lightmap for the current:
|
||||
* Time, dimension, brightness setting, etc.
|
||||
*/
|
||||
private NativeImage lightMap = null;
|
||||
|
||||
private ProfilerWrapper profilerWrapper;
|
||||
|
||||
|
||||
private MinecraftClientWrapper()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// helper methods //
|
||||
//================//
|
||||
|
||||
/**
|
||||
* This should be called at the beginning of every frame to
|
||||
* clear any Minecraft data that becomes out of date after a frame. <br> <br>
|
||||
* <p>
|
||||
* LightMaps and other time sensitive objects fall in this category. <br> <br>
|
||||
* <p>
|
||||
* This doesn't affect OpenGL objects in any way.
|
||||
*/
|
||||
@Override
|
||||
public void clearFrameObjectCache()
|
||||
{
|
||||
lightMap = null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=================//
|
||||
// method wrappers //
|
||||
//=================//
|
||||
|
||||
@Override
|
||||
public float getShade(EDhDirection lodDirection)
|
||||
{
|
||||
EDhApiLodShading lodShading = Config.Client.Advanced.Graphics.AdvancedGraphics.lodShading.get();
|
||||
switch (lodShading)
|
||||
{
|
||||
default:
|
||||
case AUTO:
|
||||
if (this.mc.level != null)
|
||||
{
|
||||
Direction mcDir = McObjectConverter.Convert(lodDirection);
|
||||
return this.mc.level.getShade(mcDir, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
case ENABLED:
|
||||
switch (lodDirection)
|
||||
{
|
||||
case DOWN:
|
||||
return 0.5F;
|
||||
default:
|
||||
case UP:
|
||||
return 1.0F;
|
||||
case NORTH:
|
||||
case SOUTH:
|
||||
return 0.8F;
|
||||
case WEST:
|
||||
case EAST:
|
||||
return 0.6F;
|
||||
}
|
||||
|
||||
case DISABLED:
|
||||
return 1.0F;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSinglePlayerServer() { return mc.hasSingleplayerServer(); }
|
||||
@Override
|
||||
public boolean clientConnectedToDedicatedServer() { return mc.getCurrentServer() != null && !this.hasSinglePlayerServer(); }
|
||||
|
||||
@Override
|
||||
public String getCurrentServerName() { return mc.getCurrentServer().name; }
|
||||
|
||||
@Override
|
||||
public String getCurrentServerIp() { return mc.getCurrentServer().ip; }
|
||||
|
||||
@Override
|
||||
public String getCurrentServerVersion()
|
||||
{
|
||||
return mc.getCurrentServer().version.getString();
|
||||
}
|
||||
|
||||
//=============//
|
||||
// Simple gets //
|
||||
//=============//
|
||||
|
||||
public LocalPlayer getPlayer()
|
||||
{
|
||||
return mc.player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean playerExists()
|
||||
{
|
||||
return mc.player != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UUID getPlayerUUID()
|
||||
{
|
||||
return getPlayer().getUUID();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DhBlockPos getPlayerBlockPos()
|
||||
{
|
||||
BlockPos playerPos = getPlayer().blockPosition();
|
||||
return new DhBlockPos(playerPos.getX(), playerPos.getY(), playerPos.getZ());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DhChunkPos getPlayerChunkPos()
|
||||
{
|
||||
#if MC_VER < MC_1_17_1
|
||||
ChunkPos playerPos = new ChunkPos(getPlayer().blockPosition());
|
||||
#else
|
||||
ChunkPos playerPos = getPlayer().chunkPosition();
|
||||
#endif
|
||||
return new DhChunkPos(playerPos.x, playerPos.z);
|
||||
}
|
||||
|
||||
public ModelManager getModelManager()
|
||||
{
|
||||
return mc.getModelManager();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public IClientLevelWrapper getWrappedClientLevel()
|
||||
{
|
||||
if (this.mc.level == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return ClientLevelWrapper.getWrapperIgnoringOverride(this.mc.level);
|
||||
}
|
||||
|
||||
/** Please move over to getInstallationDirectory() */
|
||||
@Deprecated
|
||||
@Override
|
||||
public File getGameDirectory()
|
||||
{
|
||||
return getInstallationDirectory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IProfilerWrapper getProfiler()
|
||||
{
|
||||
if (profilerWrapper == null)
|
||||
profilerWrapper = new ProfilerWrapper(mc.getProfiler());
|
||||
else if (mc.getProfiler() != profilerWrapper.profiler)
|
||||
profilerWrapper.profiler = mc.getProfiler();
|
||||
return profilerWrapper;
|
||||
}
|
||||
|
||||
/** Returns all worlds available to the server */
|
||||
@Override
|
||||
public ArrayList<ILevelWrapper> getAllServerWorlds()
|
||||
{
|
||||
ArrayList<ILevelWrapper> worlds = new ArrayList<ILevelWrapper>();
|
||||
|
||||
Iterable<ServerLevel> serverWorlds = mc.getSingleplayerServer().getAllLevels();
|
||||
for (ServerLevel world : serverWorlds)
|
||||
{
|
||||
worlds.add(ServerLevelWrapper.getWrapper(world));
|
||||
}
|
||||
|
||||
return worlds;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void sendChatMessage(String string)
|
||||
{
|
||||
LocalPlayer p = getPlayer();
|
||||
if (p == null) return;
|
||||
#if MC_VER < MC_1_19_2
|
||||
p.sendMessage(new TextComponent(string), getPlayer().getUUID());
|
||||
#else
|
||||
p.sendSystemMessage(net.minecraft.network.chat.Component.translatable(string));
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Crashes Minecraft, displaying the given errorMessage <br> <br>
|
||||
* In the following format: <br>
|
||||
*
|
||||
* The game crashed whilst <strong>errorMessage</strong> <br>
|
||||
* Error: <strong>ExceptionClass: exceptionErrorMessage</strong> <br>
|
||||
* Exit Code: -1 <br>
|
||||
*/
|
||||
@Override
|
||||
public void crashMinecraft(String errorMessage, Throwable exception)
|
||||
{
|
||||
LOGGER.error(ModInfo.READABLE_NAME + " had the following error: [" + errorMessage + "]. Crashing Minecraft...", exception);
|
||||
CrashReport report = new CrashReport(errorMessage, exception);
|
||||
#if MC_VER < MC_1_20_4
|
||||
Minecraft.crash(report);
|
||||
#else
|
||||
Minecraft.getInstance().delayCrash(report);
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getOptionsObject()
|
||||
{
|
||||
return mc.options;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDedicatedServer()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getInstallationDirectory()
|
||||
{
|
||||
return mc.gameDirectory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void executeOnRenderThread(Runnable runnable) { this.mc.execute(runnable); }
|
||||
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
package com.seibel.distanthorizons.common.wrappers.minecraft;
|
||||
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
|
||||
import net.minecraft.server.dedicated.DedicatedServer;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
//@Environment(EnvType.SERVER)
|
||||
public class MinecraftDedicatedServerWrapper implements IMinecraftSharedWrapper
|
||||
{
|
||||
public static final MinecraftDedicatedServerWrapper INSTANCE = new MinecraftDedicatedServerWrapper();
|
||||
private MinecraftDedicatedServerWrapper() { }
|
||||
public DedicatedServer dedicatedServer = null;
|
||||
@Override
|
||||
public boolean isDedicatedServer() { return true; }
|
||||
@Override
|
||||
public File getInstallationDirectory()
|
||||
{
|
||||
if (this.dedicatedServer == null)
|
||||
{
|
||||
throw new IllegalStateException("Trying to get Installation Direction before Dedicated server complete initialization!");
|
||||
}
|
||||
|
||||
#if MC_VER < MC_1_21
|
||||
return this.dedicatedServer.getServerDirectory();
|
||||
#else
|
||||
return this.dedicatedServer.getServerDirectory().toFile();
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
+194
-105
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
* 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
|
||||
@@ -16,40 +16,53 @@
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.common.wrappers.minecraft;
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers.minecraft;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import com.mojang.blaze3d.pipeline.RenderTarget;
|
||||
import com.mojang.blaze3d.platform.NativeImage;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.seibel.lod.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.lod.core.pos.DhChunkPos;
|
||||
import com.seibel.lod.common.wrappers.misc.LightMapWrapper;
|
||||
import com.seibel.lod.core.dependencyInjection.ModAccessorInjector;
|
||||
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
|
||||
import com.seibel.distanthorizons.common.wrappers.WrapperFactory;
|
||||
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.lod.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.lod.core.render.glObject.GLProxy;
|
||||
import com.seibel.lod.core.wrapperInterfaces.misc.ILightMapWrapper;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.render.DhApiRenderProxy;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.ILightMapWrapper;
|
||||
|
||||
import com.mojang.math.Vector3f;
|
||||
import com.seibel.lod.core.util.math.Mat4f;
|
||||
import com.seibel.lod.core.util.math.Vec3d;
|
||||
import com.seibel.lod.core.util.math.Vec3f;
|
||||
import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory;
|
||||
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||
import com.seibel.lod.core.wrapperInterfaces.modAccessor.IBCLibAccessor;
|
||||
import com.seibel.lod.core.wrapperInterfaces.modAccessor.IModChecker;
|
||||
import com.seibel.lod.core.wrapperInterfaces.modAccessor.IOptifineAccessor;
|
||||
import com.seibel.lod.core.wrapperInterfaces.modAccessor.ISodiumAccessor;
|
||||
import com.seibel.lod.common.wrappers.McObjectConverter;
|
||||
import com.seibel.lod.common.wrappers.WrapperFactory;
|
||||
import com.seibel.lod.core.pos.DhBlockPos;
|
||||
#if MC_VER < MC_1_19_4
|
||||
import org.joml.Vector3f;
|
||||
#else
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Vector3f;
|
||||
#endif
|
||||
#if MC_VER >= MC_1_20_2
|
||||
import net.minecraft.client.renderer.chunk.SectionRenderDispatcher;
|
||||
#endif
|
||||
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.AbstractOptifineAccessor;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IDimensionTypeWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import com.seibel.distanthorizons.coreapi.util.math.Mat4f;
|
||||
import com.seibel.distanthorizons.coreapi.util.math.Vec3d;
|
||||
import com.seibel.distanthorizons.coreapi.util.math.Vec3f;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.IWrapperFactory;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||
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.Minecraft;
|
||||
@@ -57,10 +70,9 @@ 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.entity.Entity;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
#if PRE_MC_1_17_1
|
||||
#if MC_VER < MC_1_17_1
|
||||
import net.minecraft.tags.FluidTags;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import org.lwjgl.opengl.GL15;
|
||||
#else
|
||||
@@ -69,7 +81,7 @@ import net.minecraft.world.level.material.FogType;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
import org.joml.Matrix4f;
|
||||
|
||||
|
||||
/**
|
||||
@@ -87,19 +99,28 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
|
||||
private static final Minecraft MC = Minecraft.getInstance();
|
||||
private static final IWrapperFactory FACTORY = WrapperFactory.INSTANCE;
|
||||
|
||||
|
||||
private static final IOptifineAccessor OPTIFINE_ACCESSOR = ModAccessorInjector.INSTANCE.get(IOptifineAccessor.class);
|
||||
|
||||
public LightMapWrapper lightmap = null;
|
||||
|
||||
/**
|
||||
* In the case of immersive portals multiple levels may be active at once, causing conflicting lightmaps. <br>
|
||||
* Requiring the use of multiple {@link LightMapWrapper}.
|
||||
*/
|
||||
public ConcurrentHashMap<IDimensionTypeWrapper, LightMapWrapper> lightmapByDimensionType = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* Holds the render buffer that should be used when displaying levels to the screen.
|
||||
* This is used for Optifine shader support so we can render directly to Optifine's level frame buffer.
|
||||
*/
|
||||
public int finalLevelFrameBufferId = -1;
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public Vec3f getLookAtVector()
|
||||
{
|
||||
Camera camera = MC.gameRenderer.getMainCamera();
|
||||
Vector3f cameraDir = camera.getLookVector();
|
||||
return new Vec3f(cameraDir.x(), cameraDir.y(), cameraDir.z());
|
||||
return new Vec3f(camera.getLookVector().x(), camera.getLookVector().y(), camera.getLookVector().z());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -111,9 +132,14 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean playerHasBlindnessEffect()
|
||||
/** Unless you really need to know if the player is blind, use {@link MinecraftRenderWrapper#isFogStateSpecial()}/{@link IMinecraftRenderWrapper#isFogStateSpecial()} instead */
|
||||
public boolean playerHasBlindingEffect()
|
||||
{
|
||||
return MC.player.getActiveEffectsMap().get(MobEffects.BLINDNESS) != null;
|
||||
return MC.player.getActiveEffectsMap().get(MobEffects.BLINDNESS) != null
|
||||
#if MC_VER >= MC_1_19_2
|
||||
|| MC.player.getActiveEffectsMap().get(MobEffects.DARKNESS) != null // Deep dark effect
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -125,10 +151,27 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
|
||||
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 PRE_MC_1_17_1
|
||||
#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)));
|
||||
@@ -138,7 +181,7 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
|
||||
@Override
|
||||
public double getGamma()
|
||||
{
|
||||
#if PRE_MC_1_19
|
||||
#if MC_VER < MC_1_19_2
|
||||
return MC.options.gamma;
|
||||
#else
|
||||
return MC.options.gamma().get();
|
||||
@@ -146,32 +189,47 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getFogColor(float partialTicks) {
|
||||
if (SingletonInjector.INSTANCE.get(IModChecker.class).isModLoaded("bclib"))
|
||||
return ModAccessorInjector.INSTANCE.get(IBCLibAccessor.class).getFogColor(); // BCLib uses a different fog method so we need to use that instead if they are loaded
|
||||
|
||||
#if PRE_MC_1_17_1
|
||||
public Color getFogColor(float partialTicks)
|
||||
{
|
||||
#if MC_VER < MC_1_17_1
|
||||
float[] colorValues = new float[4];
|
||||
GL15.glGetFloatv(GL15.GL_FOG_COLOR, colorValues);
|
||||
#else
|
||||
FogRenderer.setupColor(MC.gameRenderer.getMainCamera(), partialTicks, MC.level, 1, MC.gameRenderer.getDarkenWorldAmount(partialTicks));
|
||||
float[] colorValues = RenderSystem.getShaderFogColor();
|
||||
#endif
|
||||
return new Color(colorValues[0], colorValues[1], colorValues[2], colorValues[3]);
|
||||
return new Color(
|
||||
Math.max(0f, Math.min(colorValues[0], 1f)),
|
||||
Math.max(0f, Math.min(colorValues[1], 1f)),
|
||||
Math.max(0f, Math.min(colorValues[2], 1f)),
|
||||
Math.max(0f, Math.min(colorValues[3], 1f))
|
||||
);
|
||||
}
|
||||
// getSpecialFogColor() is the same as getFogColor()
|
||||
|
||||
@Override
|
||||
public Color getSkyColor() {
|
||||
if (MC.level.dimensionType().hasSkyLight()) {
|
||||
#if PRE_MC_1_17_1
|
||||
Vec3 colorValues = MC.level.getSkyColor(MC.gameRenderer.getMainCamera().getBlockPosition(), MC.getFrameTime());
|
||||
public Color getSkyColor()
|
||||
{
|
||||
if (MC.level.dimensionType().hasSkyLight())
|
||||
{
|
||||
float frameTime;
|
||||
#if MC_VER < MC_1_21
|
||||
frameTime = MC.getFrameTime();
|
||||
#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
|
||||
return new Color((float) colorValues.x, (float) colorValues.y, (float) colorValues.z);
|
||||
} else
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Color(0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -184,7 +242,7 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
|
||||
@Override
|
||||
public int getRenderDistance()
|
||||
{
|
||||
#if PRE_MC_1_18_1
|
||||
#if MC_VER < MC_1_18_2
|
||||
//FIXME: How to resolve this?
|
||||
return MC.options.renderDistance;
|
||||
#else
|
||||
@@ -227,68 +285,101 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
|
||||
return height;
|
||||
}
|
||||
|
||||
private RenderTarget getRenderTarget() {
|
||||
RenderTarget r = null; //MC.levelRenderer.getCloudsTarget();
|
||||
return r!=null ? r : MC.getMainRenderTarget();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTargetFrameBuffer() {
|
||||
return getRenderTarget().frameBufferId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTargetFrameBufferViewportWidth() {
|
||||
return getRenderTarget().viewWidth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTargetFrameBufferViewportHeight() {
|
||||
return getRenderTarget().viewHeight;
|
||||
}
|
||||
|
||||
private RenderTarget getRenderTarget() { return MC.getMainRenderTarget(); }
|
||||
|
||||
@Override
|
||||
public int getTargetFrameBuffer()
|
||||
{
|
||||
// used so we can access the framebuffer shaders end up rendering to
|
||||
if (AbstractOptifineAccessor.optifinePresent())
|
||||
{
|
||||
return this.finalLevelFrameBufferId;
|
||||
}
|
||||
|
||||
return this.getRenderTarget().frameBufferId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearTargetFrameBuffer() { this.finalLevelFrameBufferId = -1; }
|
||||
|
||||
@Override
|
||||
public int getDepthTextureId() { return this.getRenderTarget().getDepthTextureId(); }
|
||||
|
||||
@Override
|
||||
public int getTargetFrameBufferViewportWidth()
|
||||
{
|
||||
return getRenderTarget().viewWidth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTargetFrameBufferViewportHeight()
|
||||
{
|
||||
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;
|
||||
public boolean usingBackupGetVanillaRenderedChunks = false;
|
||||
@Override
|
||||
public HashSet<DhChunkPos> getVanillaRenderedChunks() {
|
||||
public HashSet<DhChunkPos> getVanillaRenderedChunks()
|
||||
{
|
||||
ISodiumAccessor sodium = ModAccessorInjector.INSTANCE.get(ISodiumAccessor.class);
|
||||
if (sodium != null) {
|
||||
if (sodium != null)
|
||||
{
|
||||
return sodium.getNormalRenderedChunks();
|
||||
}
|
||||
IOptifineAccessor optifine = ModAccessorInjector.INSTANCE.get(IOptifineAccessor.class);
|
||||
if (optifine != null) {
|
||||
if (optifine != null)
|
||||
{
|
||||
HashSet<DhChunkPos> pos = optifine.getNormalRenderedChunks();
|
||||
if (pos == null)
|
||||
pos = getMaximumRenderedChunks();
|
||||
return pos;
|
||||
}
|
||||
if (!usingBackupGetVanillaRenderedChunks) {
|
||||
try {
|
||||
if (!usingBackupGetVanillaRenderedChunks)
|
||||
{
|
||||
try
|
||||
{
|
||||
#if MC_VER < MC_1_20_2
|
||||
LevelRenderer levelRenderer = MC.levelRenderer;
|
||||
Collection<LevelRenderer.RenderChunkInfo> chunks =
|
||||
#if PRE_MC_1_18_1 levelRenderer.renderChunks;
|
||||
#if MC_VER < MC_1_18_2 levelRenderer.renderChunks;
|
||||
#else levelRenderer.renderChunkStorage.get().renderChunks; #endif
|
||||
|
||||
|
||||
return (chunks.stream().map((chunk) -> {
|
||||
AABB chunkBoundingBox =
|
||||
#if PRE_MC_1_18_2 chunk.chunk.bb;
|
||||
#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)));
|
||||
} catch (LinkageError e) {
|
||||
try {
|
||||
#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) {
|
||||
}
|
||||
catch (Exception e2)
|
||||
{
|
||||
}
|
||||
LOGGER.error("getVanillaRenderedChunks Error: ", e);
|
||||
usingBackupGetVanillaRenderedChunks = true;
|
||||
@@ -296,38 +387,36 @@ public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
|
||||
}
|
||||
return getMaximumRenderedChunks();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ILightMapWrapper getLightmapWrapper() {
|
||||
return lightmap;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFogStateSpecial() {
|
||||
#if PRE_MC_1_17_1
|
||||
public ILightMapWrapper getLightmapWrapper(ILevelWrapper level) { return this.lightmapByDimensionType.get(level.getDimensionType()); }
|
||||
|
||||
@Override
|
||||
public boolean isFogStateSpecial()
|
||||
{
|
||||
#if MC_VER < MC_1_17_1
|
||||
Camera camera = Minecraft.getInstance().gameRenderer.getMainCamera();
|
||||
FluidState fluidState = camera.getFluidInCamera();
|
||||
Entity entity = camera.getEntity();
|
||||
boolean isUnderWater = (entity instanceof LivingEntity) && ((LivingEntity)entity).hasEffect(MobEffects.BLINDNESS);
|
||||
isUnderWater |= fluidState.is(FluidTags.WATER);
|
||||
isUnderWater |= fluidState.is(FluidTags.LAVA);
|
||||
return isUnderWater;
|
||||
boolean isBlind = this.playerHasBlindingEffect();
|
||||
isBlind |= fluidState.is(FluidTags.WATER);
|
||||
isBlind |= fluidState.is(FluidTags.LAVA);
|
||||
return isBlind;
|
||||
#else
|
||||
Entity entity = MC.gameRenderer.getMainCamera().getEntity();
|
||||
boolean isBlind = (entity instanceof LivingEntity) && ((LivingEntity)entity).hasEffect(MobEffects.BLINDNESS);
|
||||
boolean isBlind = this.playerHasBlindingEffect();
|
||||
return MC.gameRenderer.getMainCamera().getFluidInCamera() != FogType.NONE || isBlind;
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean tryDisableVanillaFog() {
|
||||
return true; // Handled via MixinFogRenderer in both forge and fabric
|
||||
public void updateLightmap(NativeImage lightPixels, IClientLevelWrapper level)
|
||||
{
|
||||
// Using ClientLevelWrapper as the key would be better, but we don't have a consistent way to create the same
|
||||
// object for the same MC level and/or the same hash,
|
||||
// so this will have to do for now
|
||||
IDimensionTypeWrapper dimensionType = level.getDimensionType();
|
||||
|
||||
LightMapWrapper wrapper = this.lightmapByDimensionType.compute(dimensionType, (dimType, oldWrapper) -> new LightMapWrapper());
|
||||
wrapper.uploadLightmap(lightPixels);
|
||||
}
|
||||
|
||||
public void updateLightmap(NativeImage lightPixels) {
|
||||
if (lightmap== null) {
|
||||
lightmap = new LightMapWrapper();
|
||||
}
|
||||
lightmap.uploadLightmap(lightPixels);
|
||||
}
|
||||
|
||||
}
|
||||
+34
-33
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
* 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
|
||||
@@ -16,10 +16,10 @@
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.common.wrappers.minecraft;
|
||||
|
||||
import com.seibel.lod.core.wrapperInterfaces.minecraft.IProfilerWrapper;
|
||||
package com.seibel.distanthorizons.common.wrappers.minecraft;
|
||||
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper;
|
||||
|
||||
import net.minecraft.util.profiling.ProfilerFiller;
|
||||
|
||||
@@ -29,32 +29,33 @@ import net.minecraft.util.profiling.ProfilerFiller;
|
||||
*/
|
||||
public class ProfilerWrapper implements IProfilerWrapper
|
||||
{
|
||||
public ProfilerFiller profiler;
|
||||
|
||||
public ProfilerWrapper(ProfilerFiller newProfiler)
|
||||
{
|
||||
profiler = newProfiler;
|
||||
}
|
||||
|
||||
|
||||
/** starts a new section inside the currently running section */
|
||||
@Override
|
||||
public void push(String newSection)
|
||||
{
|
||||
profiler.push(newSection);
|
||||
}
|
||||
|
||||
/** ends the currently running section and starts a new one */
|
||||
@Override
|
||||
public void popPush(String newSection)
|
||||
{
|
||||
profiler.popPush(newSection);
|
||||
}
|
||||
|
||||
/** ends the currently running section */
|
||||
@Override
|
||||
public void pop()
|
||||
{
|
||||
profiler.pop();
|
||||
}
|
||||
public ProfilerFiller profiler;
|
||||
|
||||
public ProfilerWrapper(ProfilerFiller newProfiler)
|
||||
{
|
||||
profiler = newProfiler;
|
||||
}
|
||||
|
||||
|
||||
/** starts a new section inside the currently running section */
|
||||
@Override
|
||||
public void push(String newSection)
|
||||
{
|
||||
profiler.push(newSection);
|
||||
}
|
||||
|
||||
/** ends the currently running section and starts a new one */
|
||||
@Override
|
||||
public void popPush(String newSection)
|
||||
{
|
||||
profiler.popPush(newSection);
|
||||
}
|
||||
|
||||
/** ends the currently running section */
|
||||
@Override
|
||||
public void pop()
|
||||
{
|
||||
profiler.pop();
|
||||
}
|
||||
|
||||
}
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* 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.misc;
|
||||
|
||||
import com.mojang.blaze3d.platform.NativeImage;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.ILightMapWrapper;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class LightMapWrapper implements ILightMapWrapper
|
||||
{
|
||||
private int textureId = 0;
|
||||
|
||||
|
||||
//==============//
|
||||
// constructors //
|
||||
//==============//
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// methods //
|
||||
//=========//
|
||||
|
||||
public void uploadLightmap(NativeImage image)
|
||||
{
|
||||
int currentBind = GL32.glGetInteger(GL32.GL_TEXTURE_BINDING_2D);
|
||||
GL32.glBindTexture(GL32.GL_TEXTURE_2D, this.textureId);
|
||||
if (this.textureId == 0)
|
||||
{
|
||||
this.createLightmap(image);
|
||||
}
|
||||
image.upload(0, 0, 0, false);
|
||||
GL32.glBindTexture(GL32.GL_TEXTURE_2D, currentBind);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bind()
|
||||
{
|
||||
GL32.glActiveTexture(GL32.GL_TEXTURE0);
|
||||
GL32.glBindTexture(GL32.GL_TEXTURE_2D, this.textureId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unbind() { GL32.glBindTexture(GL32.GL_TEXTURE_2D, 0); }
|
||||
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
package com.seibel.distanthorizons.common.wrappers.misc;
|
||||
|
||||
import com.google.common.collect.MapMaker;
|
||||
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
public class ServerPlayerWrapper implements IServerPlayerWrapper
|
||||
{
|
||||
private static final ConcurrentMap<ServerPlayer, ServerPlayerWrapper>
|
||||
serverPlayerWrapperMap = new MapMaker().weakKeys().makeMap();
|
||||
|
||||
private final ServerPlayer serverPlayer;
|
||||
|
||||
public static ServerPlayerWrapper getWrapper(ServerPlayer serverPlayer)
|
||||
{
|
||||
return serverPlayerWrapperMap.computeIfAbsent(serverPlayer, ServerPlayerWrapper::new);
|
||||
}
|
||||
|
||||
private ServerPlayerWrapper(ServerPlayer serverPlayer)
|
||||
{
|
||||
this.serverPlayer = serverPlayer;
|
||||
}
|
||||
|
||||
public UUID getUUID()
|
||||
{
|
||||
return serverPlayer.getUUID();
|
||||
}
|
||||
|
||||
public IServerLevelWrapper getLevel()
|
||||
{
|
||||
#if MC_VER < MC_1_20_1
|
||||
return ServerLevelWrapper.getWrapper(this.serverPlayer.getLevel());
|
||||
#else
|
||||
return ServerLevelWrapper.getWrapper(this.serverPlayer.serverLevel());
|
||||
#endif
|
||||
}
|
||||
|
||||
public Object getWrappedMcObject()
|
||||
{
|
||||
return serverPlayer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "Wrapped{" + serverPlayer.toString() + "}";
|
||||
}
|
||||
|
||||
}
|
||||
+245
@@ -0,0 +1,245 @@
|
||||
package com.seibel.distanthorizons.common.wrappers.world;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiLevelType;
|
||||
import com.seibel.distanthorizons.api.interfaces.world.IDhApiDimensionTypeWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
|
||||
import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.block.cache.ClientBlockDetailMap;
|
||||
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.level.IKeyedClientLevelManager;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.pos.DhBlockPos;
|
||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IDimensionTypeWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IServerLevelWrapper;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.LightLayer;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.ChunkSource;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
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
|
||||
{
|
||||
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 IKeyedClientLevelManager KEYED_CLIENT_LEVEL_MANAGER = SingletonInjector.INSTANCE.get(IKeyedClientLevelManager.class);
|
||||
|
||||
private final ClientLevel level;
|
||||
private final ClientBlockDetailMap blockMap = new ClientBlockDetailMap(this);
|
||||
|
||||
private BlockStateWrapper dirtBlockWrapper;
|
||||
private BiomeWrapper plainsBiomeWrapper;
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
protected ClientLevelWrapper(ClientLevel level) { this.level = level; }
|
||||
|
||||
|
||||
|
||||
//===============//
|
||||
// wrapper logic //
|
||||
//===============//
|
||||
|
||||
@Nullable
|
||||
public static IClientLevelWrapper getWrapper(@Nullable ClientLevel level)
|
||||
{
|
||||
if (level == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// used if the client is connected to a server that defines the currently loaded level
|
||||
if (KEYED_CLIENT_LEVEL_MANAGER.getUseOverrideWrapper())
|
||||
{
|
||||
return KEYED_CLIENT_LEVEL_MANAGER.getOverrideWrapper();
|
||||
}
|
||||
|
||||
return getWrapperIgnoringOverride(level);
|
||||
}
|
||||
public static IClientLevelWrapper getWrapperIgnoringOverride(@NotNull ClientLevel level) { return LEVEL_WRAPPER_BY_CLIENT_LEVEL.computeIfAbsent(level, ClientLevelWrapper::new); }
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public IServerLevelWrapper tryGetServerSideWrapper()
|
||||
{
|
||||
try
|
||||
{
|
||||
Iterable<ServerLevel> serverLevels = MinecraftClientWrapper.INSTANCE.mc.getSingleplayerServer().getAllLevels();
|
||||
|
||||
// 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
|
||||
ServerLevelWrapper foundLevelWrapper = null;
|
||||
|
||||
// TODO: Surely there is a more efficient way to write this code
|
||||
for (ServerLevel serverLevel : serverLevels)
|
||||
{
|
||||
if (serverLevel.dimension() == this.level.dimension())
|
||||
{
|
||||
foundLevelWrapper = ServerLevelWrapper.getWrapper(serverLevel);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return foundLevelWrapper;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.error("Failed to get server side wrapper for client level: " + level);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//====================//
|
||||
// base level methods //
|
||||
//====================//
|
||||
|
||||
@Override
|
||||
public int computeBaseColor(DhBlockPos pos, IBiomeWrapper biome, IBlockStateWrapper blockState)
|
||||
{
|
||||
return this.blockMap.getColor(((BlockStateWrapper) blockState).blockState, (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.blockMap.getColor(this.dirtBlockWrapper.blockState, BiomeWrapper.EMPTY_WRAPPER, DhBlockPos.ZERO);
|
||||
}
|
||||
|
||||
@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
|
||||
public IDimensionTypeWrapper getDimensionType() { return DimensionTypeWrapper.getDimensionTypeWrapper(this.level.dimensionType()); }
|
||||
|
||||
@Override
|
||||
public EDhApiLevelType getLevelType() { return EDhApiLevelType.CLIENT_LEVEL; }
|
||||
|
||||
public ClientLevel getLevel() { return this.level; }
|
||||
|
||||
@Override
|
||||
public boolean hasCeiling() { return this.level.dimensionType().hasCeiling(); }
|
||||
|
||||
@Override
|
||||
public boolean hasSkyLight() { return this.level.dimensionType().hasSkyLight(); }
|
||||
|
||||
@Override
|
||||
public int getHeight() { return this.level.getHeight(); }
|
||||
|
||||
@Override
|
||||
public int getMinHeight()
|
||||
{
|
||||
#if MC_VER < MC_1_17_1
|
||||
return 0;
|
||||
#else
|
||||
return this.level.getMinBuildHeight();
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkWrapper tryGetChunk(DhChunkPos pos)
|
||||
{
|
||||
if (!this.level.hasChunk(pos.x, pos.z))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
ChunkAccess chunk = this.level.getChunk(pos.x, pos.z, ChunkStatus.EMPTY, false);
|
||||
if (chunk == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ChunkWrapper(chunk, this.level, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasChunkLoaded(int chunkX, int chunkZ)
|
||||
{
|
||||
ChunkSource source = this.level.getChunkSource();
|
||||
return source.hasChunk(chunkX, chunkZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockStateWrapper getBlockState(DhBlockPos pos)
|
||||
{
|
||||
return BlockStateWrapper.fromBlockState(this.level.getBlockState(McObjectConverter.Convert(pos)), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBiomeWrapper getBiome(DhBlockPos pos) { return BiomeWrapper.getBiomeWrapper(this.level.getBiome(McObjectConverter.Convert(pos)), this); }
|
||||
|
||||
@Override
|
||||
public ClientLevel getWrappedMcObject() { return this.level; }
|
||||
|
||||
@Override
|
||||
public void onUnload() { LEVEL_WRAPPER_BY_CLIENT_LEVEL.remove(this.level); }
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
if (this.level == null)
|
||||
{
|
||||
return "Wrapped{null}";
|
||||
}
|
||||
|
||||
return "Wrapped{" + this.level.toString() + "@" + this.getDimensionType().getDimensionName() + "}";
|
||||
}
|
||||
|
||||
}
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
/*
|
||||
* 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.world;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IDimensionTypeWrapper;
|
||||
|
||||
import net.minecraft.world.level.dimension.DimensionType;
|
||||
|
||||
/**
|
||||
* @author James Seibel
|
||||
* @version 2022-9-16
|
||||
*/
|
||||
public class DimensionTypeWrapper implements IDimensionTypeWrapper
|
||||
{
|
||||
private static final ConcurrentMap<DimensionType, DimensionTypeWrapper> dimensionTypeWrapperMap = new ConcurrentHashMap<>();
|
||||
private final DimensionType dimensionType;
|
||||
|
||||
public DimensionTypeWrapper(DimensionType dimensionType)
|
||||
{
|
||||
this.dimensionType = dimensionType;
|
||||
}
|
||||
|
||||
public static DimensionTypeWrapper getDimensionTypeWrapper(DimensionType dimensionType)
|
||||
{
|
||||
//first we check if the biome has already been wrapped
|
||||
if (dimensionTypeWrapperMap.containsKey(dimensionType) && dimensionTypeWrapperMap.get(dimensionType) != null)
|
||||
return dimensionTypeWrapperMap.get(dimensionType);
|
||||
|
||||
|
||||
//if it hasn't been created yet, we create it and save it in the map
|
||||
DimensionTypeWrapper dimensionTypeWrapper = new DimensionTypeWrapper(dimensionType);
|
||||
dimensionTypeWrapperMap.put(dimensionType, dimensionTypeWrapper);
|
||||
|
||||
//we return the newly created wrapper
|
||||
return dimensionTypeWrapper;
|
||||
}
|
||||
|
||||
public static void clearMap()
|
||||
{
|
||||
dimensionTypeWrapperMap.clear();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getDimensionName()
|
||||
{
|
||||
return dimensionType.effectsLocation().getPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCeiling()
|
||||
{
|
||||
return dimensionType.hasCeiling();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSkyLight()
|
||||
{
|
||||
return dimensionType.hasSkyLight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getWrappedMcObject()
|
||||
{
|
||||
return this.dimensionType;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (obj.getClass() != DimensionTypeWrapper.class)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
DimensionTypeWrapper other = (DimensionTypeWrapper) obj;
|
||||
return other.getDimensionName().equals(this.getDimensionName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+188
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* 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.world;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiLevelType;
|
||||
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
|
||||
import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper;
|
||||
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.minecraft.MinecraftClientWrapper;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.pos.DhBlockPos;
|
||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.block.IBlockStateWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||
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.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.ChunkSource;
|
||||
|
||||
#if MC_VER <= MC_1_20_4
|
||||
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.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @version 2022-9-16
|
||||
*/
|
||||
public class ServerLevelWrapper implements IServerLevelWrapper
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
private static final ConcurrentHashMap<ServerLevel, ServerLevelWrapper> LEVEL_WRAPPER_BY_SERVER_LEVEL = new ConcurrentHashMap<>();
|
||||
|
||||
final ServerLevel level;
|
||||
ServerBlockDetailMap blockMap = new ServerBlockDetailMap(this);
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// constructors //
|
||||
//==============//
|
||||
|
||||
public static ServerLevelWrapper getWrapper(ServerLevel level) { return LEVEL_WRAPPER_BY_SERVER_LEVEL.computeIfAbsent(level, ServerLevelWrapper::new); }
|
||||
|
||||
public ServerLevelWrapper(ServerLevel level)
|
||||
{
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// methods //
|
||||
//=========//
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public IClientLevelWrapper tryGetClientLevelWrapper()
|
||||
{
|
||||
MinecraftClientWrapper client = MinecraftClientWrapper.INSTANCE;
|
||||
if (client.mc.level == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return ClientLevelWrapper.getWrapper(client.mc.level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getSaveFolder()
|
||||
{
|
||||
return level.getChunkSource().getDataStorage().dataFolder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DimensionTypeWrapper getDimensionType()
|
||||
{
|
||||
return DimensionTypeWrapper.getDimensionTypeWrapper(level.dimensionType());
|
||||
}
|
||||
|
||||
@Override
|
||||
public EDhApiLevelType getLevelType() { return EDhApiLevelType.SERVER_LEVEL; }
|
||||
|
||||
public ServerLevel getLevel()
|
||||
{
|
||||
return level;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCeiling()
|
||||
{
|
||||
return level.dimensionType().hasCeiling();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSkyLight()
|
||||
{
|
||||
return level.dimensionType().hasSkyLight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight()
|
||||
{
|
||||
return level.getHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinHeight()
|
||||
{
|
||||
#if MC_VER < MC_1_17_1
|
||||
return 0;
|
||||
#else
|
||||
return level.getMinBuildHeight();
|
||||
#endif
|
||||
}
|
||||
@Override
|
||||
public IChunkWrapper tryGetChunk(DhChunkPos pos)
|
||||
{
|
||||
if (!level.hasChunk(pos.x, pos.z)) return null;
|
||||
ChunkAccess chunk = level.getChunk(pos.x, pos.z, ChunkStatus.FULL, false);
|
||||
if (chunk == null) return null;
|
||||
return new ChunkWrapper(chunk, level, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasChunkLoaded(int chunkX, int chunkZ)
|
||||
{
|
||||
// world.hasChunk(chunkX, chunkZ); THIS DOES NOT WORK FOR CLIENT LEVEL CAUSE MOJANG ALWAYS RETURN TRUE FOR THAT!
|
||||
ChunkSource source = level.getChunkSource();
|
||||
return source.hasChunk(chunkX, chunkZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockStateWrapper getBlockState(DhBlockPos pos)
|
||||
{
|
||||
return BlockStateWrapper.fromBlockState(level.getBlockState(McObjectConverter.Convert(pos)), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBiomeWrapper getBiome(DhBlockPos pos)
|
||||
{
|
||||
return BiomeWrapper.getBiomeWrapper(level.getBiome(McObjectConverter.Convert(pos)), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ServerLevel getWrappedMcObject()
|
||||
{
|
||||
return level;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUnload() { LEVEL_WRAPPER_BY_SERVER_LEVEL.remove(this.level); }
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return "Wrapped{" + level.toString() + "@" + getDimensionType().getDimensionName() + "}";
|
||||
}
|
||||
|
||||
}
|
||||
+852
@@ -0,0 +1,852 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2021 Tom Lee (TomTheFurry)
|
||||
* 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.worldGeneration;
|
||||
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiDistantGeneratorMode;
|
||||
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiWorldGenerationStep;
|
||||
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.*;
|
||||
import com.seibel.distanthorizons.core.dataObjects.transformers.FullDataToRenderDataTransformer;
|
||||
import com.seibel.distanthorizons.core.generation.DhLightingEngine;
|
||||
import com.seibel.distanthorizons.core.level.IDhServerLevel;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
|
||||
import com.seibel.distanthorizons.core.logging.ConfigBasedSpamLogger;
|
||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||
import com.seibel.distanthorizons.core.util.objects.EventTimer;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
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.worldGeneration.AbstractBatchGenerationEnvironmentWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.DependencySetupDoneCheck;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.step.StepBiomes;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.step.StepFeatures;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.step.StepNoise;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.step.StepStructureReference;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.step.StepStructureStart;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.step.StepSurface;
|
||||
|
||||
#if MC_VER >= MC_1_19_4
|
||||
import net.minecraft.core.registries.Registries;
|
||||
#else
|
||||
import net.minecraft.core.Registry;
|
||||
#endif
|
||||
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||
import net.minecraft.world.level.chunk.UpgradeData;
|
||||
import net.minecraft.world.level.chunk.storage.IOWorker;
|
||||
import net.minecraft.world.level.chunk.storage.RegionFileStorage;
|
||||
import net.minecraft.world.level.levelgen.DebugLevelSource;
|
||||
import net.minecraft.world.level.levelgen.FlatLevelSource;
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
import net.minecraft.world.level.levelgen.NoiseBasedChunkGenerator;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
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
|
||||
=====================================
|
||||
Empty Chunks: 0.000558328s
|
||||
StructureStart Step: 0.025177207s
|
||||
StructureReference Step: 0.00189559s
|
||||
Biome Step: 0.13789155s
|
||||
Noise Step: 1.570347555s
|
||||
Surface Step: 0.741238194s
|
||||
Carver Step: 0.000009923s
|
||||
Feature Step: 0.389072425s
|
||||
Lod Generation: 0.269023348s
|
||||
*/
|
||||
public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnvironmentWrapper
|
||||
{
|
||||
public static final ConfigBasedSpamLogger PREF_LOGGER =
|
||||
new ConfigBasedSpamLogger(LogManager.getLogger("LodWorldGen"),
|
||||
() -> Config.Client.Advanced.Logging.logWorldGenPerformance.get(), 1);
|
||||
public static final ConfigBasedLogger EVENT_LOGGER =
|
||||
new ConfigBasedLogger(LogManager.getLogger("LodWorldGen"),
|
||||
() -> Config.Client.Advanced.Logging.logWorldGenEvent.get());
|
||||
public static final ConfigBasedLogger LOAD_LOGGER =
|
||||
new ConfigBasedLogger(LogManager.getLogger("LodWorldGen"),
|
||||
() -> Config.Client.Advanced.Logging.logWorldGenLoadEvent.get());
|
||||
|
||||
public static class PerfCalculator
|
||||
{
|
||||
private static final String[] TIME_NAMES = {
|
||||
"total",
|
||||
"setup",
|
||||
"structStart",
|
||||
"structRef",
|
||||
"biome",
|
||||
"noise",
|
||||
"surface",
|
||||
"carver",
|
||||
"feature",
|
||||
"light",
|
||||
"cleanup",
|
||||
//"lodCreation" (No longer used)
|
||||
};
|
||||
|
||||
public static final int SIZE = 50;
|
||||
ArrayList<Rolling> times = new ArrayList<>();
|
||||
|
||||
public PerfCalculator()
|
||||
{
|
||||
for (int i = 0; i < 11; i++)
|
||||
{
|
||||
times.add(new Rolling(SIZE));
|
||||
}
|
||||
}
|
||||
|
||||
public void recordEvent(EventTimer event)
|
||||
{
|
||||
for (EventTimer.Event e : event.events)
|
||||
{
|
||||
String name = e.name;
|
||||
int index = Arrays.asList(TIME_NAMES).indexOf(name);
|
||||
if (index == -1) continue;
|
||||
times.get(index).add(e.timeNs);
|
||||
}
|
||||
times.get(0).add(event.getTotalTimeNs());
|
||||
}
|
||||
|
||||
public String toString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (int i = 0; i < times.size(); i++)
|
||||
{
|
||||
if (times.get(i).getAverage() == 0) continue;
|
||||
sb.append(TIME_NAMES[i]).append(": ").append(times.get(i).getAverage()).append("\n");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private final IDhServerLevel serverlevel;
|
||||
|
||||
//=================Generation Step===================
|
||||
|
||||
public final LinkedBlockingQueue<GenerationEvent> generationEventList = new LinkedBlockingQueue<>();
|
||||
public final GlobalParameters params;
|
||||
public final StepStructureStart stepStructureStart = new StepStructureStart(this);
|
||||
public final StepStructureReference stepStructureReference = new StepStructureReference(this);
|
||||
public final StepBiomes stepBiomes = new StepBiomes(this);
|
||||
public final StepNoise stepNoise = new StepNoise(this);
|
||||
public final StepSurface stepSurface = new StepSurface(this);
|
||||
public final StepFeatures stepFeatures = new StepFeatures(this);
|
||||
public boolean unsafeThreadingRecorded = false;
|
||||
public static final long EXCEPTION_TIMER_RESET_TIME = TimeUnit.NANOSECONDS.convert(1, TimeUnit.SECONDS);
|
||||
public static final int EXCEPTION_COUNTER_TRIGGER = 20;
|
||||
public static final int RANGE_TO_RANGE_EMPTY_EXTENSION = 1;
|
||||
public int unknownExceptionCount = 0;
|
||||
public long lastExceptionTriggerTime = 0;
|
||||
|
||||
private AtomicReference<RegionFileStorageExternalCache> regionFileStorageCacheRef = new AtomicReference<>();
|
||||
|
||||
public RegionFileStorageExternalCache getOrCreateRegionFileCache(RegionFileStorage storage)
|
||||
{
|
||||
RegionFileStorageExternalCache cache = regionFileStorageCacheRef.get();
|
||||
if (cache == null)
|
||||
{
|
||||
cache = new RegionFileStorageExternalCache(storage);
|
||||
if (!regionFileStorageCacheRef.compareAndSet(null, cache))
|
||||
{
|
||||
cache = regionFileStorageCacheRef.get();
|
||||
}
|
||||
}
|
||||
return cache;
|
||||
}
|
||||
|
||||
public static ThreadLocal<Boolean> isDistantGeneratorThread = new ThreadLocal<>();
|
||||
public static ThreadLocal<Object> onDistantGenerationMixinData = new ThreadLocal<>();
|
||||
public static boolean isCurrentThreadDistantGeneratorThread() { return (isDistantGeneratorThread.get() != null); }
|
||||
public static void putDistantGenerationMixinData(Object data)
|
||||
{
|
||||
LodUtil.assertTrue(isCurrentThreadDistantGeneratorThread());
|
||||
onDistantGenerationMixinData.set(data);
|
||||
}
|
||||
public static Object getDistantGenerationMixinData()
|
||||
{
|
||||
LodUtil.assertTrue(isCurrentThreadDistantGeneratorThread());
|
||||
return onDistantGenerationMixinData.get();
|
||||
}
|
||||
|
||||
public static void clearDistantGenerationMixinData()
|
||||
{
|
||||
LodUtil.assertTrue(isCurrentThreadDistantGeneratorThread());
|
||||
onDistantGenerationMixinData.remove();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// constructors //
|
||||
//==============//
|
||||
|
||||
public static ImmutableMap<EDhApiWorldGenerationStep, Integer> BorderNeeded;
|
||||
public static int MaxBorderNeeded;
|
||||
|
||||
static
|
||||
{
|
||||
DependencySetupDoneCheck.getIsCurrentThreadDistantGeneratorThread = BatchGenerationEnvironment::isCurrentThreadDistantGeneratorThread;
|
||||
|
||||
boolean isTerraFirmaCraft = false;
|
||||
try
|
||||
{
|
||||
Class.forName("net.dries007.tfc.world.TFCChunkGenerator");
|
||||
isTerraFirmaCraft = true;
|
||||
}
|
||||
catch (ClassNotFoundException e)
|
||||
{
|
||||
//Ignore
|
||||
}
|
||||
EVENT_LOGGER.info("DH TerraFirmaCraft detection: " + isTerraFirmaCraft);
|
||||
ImmutableMap.Builder<EDhApiWorldGenerationStep, Integer> builder = ImmutableMap.builder();
|
||||
builder.put(EDhApiWorldGenerationStep.EMPTY, 1);
|
||||
builder.put(EDhApiWorldGenerationStep.STRUCTURE_START, 0);
|
||||
builder.put(EDhApiWorldGenerationStep.STRUCTURE_REFERENCE, 0);
|
||||
builder.put(EDhApiWorldGenerationStep.BIOMES, isTerraFirmaCraft ? 1 : 0);
|
||||
builder.put(EDhApiWorldGenerationStep.NOISE, isTerraFirmaCraft ? 1 : 0);
|
||||
builder.put(EDhApiWorldGenerationStep.SURFACE, 0);
|
||||
builder.put(EDhApiWorldGenerationStep.CARVERS, 0);
|
||||
builder.put(EDhApiWorldGenerationStep.LIQUID_CARVERS, 0);
|
||||
builder.put(EDhApiWorldGenerationStep.FEATURES, 0);
|
||||
builder.put(EDhApiWorldGenerationStep.LIGHT, 0);
|
||||
BorderNeeded = builder.build();
|
||||
MaxBorderNeeded = BorderNeeded.values().stream().mapToInt(Integer::intValue).max().getAsInt();
|
||||
}
|
||||
|
||||
public BatchGenerationEnvironment(IDhServerLevel serverlevel)
|
||||
{
|
||||
super(serverlevel);
|
||||
this.serverlevel = serverlevel;
|
||||
|
||||
EVENT_LOGGER.info("================WORLD_GEN_STEP_INITING=============");
|
||||
|
||||
serverlevel.getServerLevelWrapper().getDimensionType();
|
||||
|
||||
ChunkGenerator generator = ((ServerLevelWrapper) (serverlevel.getServerLevelWrapper())).getLevel().getChunkSource().getGenerator();
|
||||
if (!(generator instanceof NoiseBasedChunkGenerator ||
|
||||
generator instanceof DebugLevelSource ||
|
||||
generator instanceof FlatLevelSource))
|
||||
{
|
||||
if (generator.getClass().toString().equals("class com.terraforged.mod.chunk.TFChunkGenerator"))
|
||||
{
|
||||
EVENT_LOGGER.info("TerraForge Chunk Generator detected: [" + generator.getClass() + "], Distant Generation will try its best to support it.");
|
||||
EVENT_LOGGER.info("If it does crash, turn Distant Generation off or set it to to [" + EDhApiDistantGeneratorMode.PRE_EXISTING_ONLY + "].");
|
||||
}
|
||||
else if (generator.getClass().toString().equals("class net.dries007.tfc.world.TFCChunkGenerator"))
|
||||
{
|
||||
EVENT_LOGGER.info("TerraFirmaCraft Chunk Generator detected: [" + generator.getClass() + "], Distant Generation will try its best to support it.");
|
||||
EVENT_LOGGER.info("If it does crash, turn Distant Generation off or set it to to [" + EDhApiDistantGeneratorMode.PRE_EXISTING_ONLY + "].");
|
||||
}
|
||||
else
|
||||
{
|
||||
EVENT_LOGGER.warn("Unknown Chunk Generator detected: [" + generator.getClass() + "], Distant Generation May Fail!");
|
||||
EVENT_LOGGER.warn("If it does crash, disable Distant Generation or set the Generation Mode to [" + EDhApiDistantGeneratorMode.PRE_EXISTING_ONLY + "].");
|
||||
}
|
||||
}
|
||||
|
||||
this.params = new GlobalParameters(serverlevel);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=================//
|
||||
// synchronization //
|
||||
//=================//
|
||||
|
||||
public <T> T joinSync(CompletableFuture<T> future)
|
||||
{
|
||||
if (!unsafeThreadingRecorded && !future.isDone())
|
||||
{
|
||||
EVENT_LOGGER.error("Unsafe MultiThreading in Chunk Generator: ", new RuntimeException("Concurrent future"));
|
||||
EVENT_LOGGER.error("To increase stability, it is recommended to set world generation threads count to 1.");
|
||||
unsafeThreadingRecorded = true;
|
||||
}
|
||||
|
||||
return future.join();
|
||||
}
|
||||
|
||||
public void updateAllFutures()
|
||||
{
|
||||
if (this.unknownExceptionCount > 0)
|
||||
{
|
||||
if (System.nanoTime() - this.lastExceptionTriggerTime >= EXCEPTION_TIMER_RESET_TIME)
|
||||
{
|
||||
this.unknownExceptionCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Update all current out standing jobs
|
||||
Iterator<GenerationEvent> iter = this.generationEventList.iterator();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
GenerationEvent event = iter.next();
|
||||
if (event.future.isDone())
|
||||
{
|
||||
if (event.future.isCompletedExceptionally() && !event.future.isCancelled())
|
||||
{
|
||||
try
|
||||
{
|
||||
event.future.get(); // Should throw exception
|
||||
LodUtil.assertNotReach();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
this.unknownExceptionCount++;
|
||||
this.lastExceptionTriggerTime = System.nanoTime();
|
||||
EVENT_LOGGER.error("Batching World Generator event ["+event+"] threw an exception: "+e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
iter.remove();
|
||||
}
|
||||
else if (event.hasTimeout(Config.Client.Advanced.WorldGenerator.worldGenerationTimeoutLengthInSeconds.get(), TimeUnit.SECONDS))
|
||||
{
|
||||
EVENT_LOGGER.error("Batching World Generator: " + event + " timed out and terminated! Please lower your CPU load.");
|
||||
EVENT_LOGGER.info("Dump PrefEvent: " + event.timer);
|
||||
try
|
||||
{
|
||||
if (!event.terminate())
|
||||
{
|
||||
EVENT_LOGGER.error("Failed to terminate the stuck generation event!");
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (this.unknownExceptionCount > EXCEPTION_COUNTER_TRIGGER)
|
||||
{
|
||||
EVENT_LOGGER.error("Too many exceptions in Batching World Generator! Disabling the generator.");
|
||||
this.unknownExceptionCount = 0;
|
||||
Config.Client.Advanced.WorldGenerator.enableDistantGeneration.set(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==================//
|
||||
// world generation //
|
||||
//==================//
|
||||
|
||||
public void generateLodFromList(GenerationEvent genEvent) throws InterruptedException
|
||||
{
|
||||
EVENT_LOGGER.debug("Lod Generate Event: " + genEvent.minPos);
|
||||
|
||||
ArrayGridList<ChunkWrapper> chunkWrapperList;
|
||||
DhLitWorldGenRegion region;
|
||||
DummyLightEngine dummyLightEngine;
|
||||
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);
|
||||
dummyLightEngine = new DummyLightEngine(adaptor);
|
||||
|
||||
|
||||
|
||||
//=============================//
|
||||
// try getting existing chunks //
|
||||
//=============================//
|
||||
|
||||
HashMap<DhChunkPos, ChunkLightStorage> chunkSkyLightingByDhPos = new HashMap<>();
|
||||
HashMap<DhChunkPos, ChunkLightStorage> chunkBlockLightingByDhPos = new HashMap<>();
|
||||
IEmptyChunkGeneratorFunc emptyChunkGeneratorFunc = (int x, int z) ->
|
||||
{
|
||||
ChunkPos chunkPos = new ChunkPos(x, z);
|
||||
DhChunkPos dhChunkPos = new DhChunkPos(x, z);
|
||||
ChunkAccess newChunk = null;
|
||||
try
|
||||
{
|
||||
// get the chunk
|
||||
CompoundTag chunkData = this.getChunkNbtData(chunkPos);
|
||||
newChunk = this.loadOrMakeChunk(chunkPos, chunkData);
|
||||
|
||||
// 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
|
||||
);
|
||||
}
|
||||
return newChunk;
|
||||
};
|
||||
totalChunks = new ArrayGridList<>(refSize, (x, z) -> emptyChunkGeneratorFunc.generate(x + refPosX, z + refPosZ));
|
||||
|
||||
int radius = refSize / 2;
|
||||
int centerX = refPosX + radius;
|
||||
int centerZ = refPosZ + radius;
|
||||
|
||||
ChunkAccess centerChunk = totalChunks.stream().filter(chunk -> chunk.getPos().x == centerX && chunk.getPos().z == centerZ).findFirst().get();
|
||||
|
||||
genEvent.refreshTimeout();
|
||||
region = new DhLitWorldGenRegion(
|
||||
centerX, centerZ,
|
||||
centerChunk,
|
||||
this.params.level, dummyLightEngine, totalChunks,
|
||||
ChunkStatus.STRUCTURE_STARTS, radius, emptyChunkGeneratorFunc);
|
||||
adaptor.setRegion(region);
|
||||
genEvent.threadedParam.makeStructFeat(region, this.params);
|
||||
|
||||
|
||||
|
||||
//=======================//
|
||||
// create chunk wrappers //
|
||||
//=======================//
|
||||
|
||||
chunkWrapperList = new ArrayGridList<>(totalChunks.gridSize);
|
||||
totalChunks.forEachPos((x, z) ->
|
||||
{
|
||||
ChunkAccess chunk = totalChunks.get(x, z);
|
||||
if (chunk != null)
|
||||
{
|
||||
// wrap the chunk
|
||||
ChunkWrapper chunkWrapper = new ChunkWrapper(chunk, region, this.serverlevel.getLevelWrapper());
|
||||
chunkWrapperList.set(x, z, chunkWrapper);
|
||||
|
||||
// try getting the chunk lighting
|
||||
if (chunkBlockLightingByDhPos.containsKey(chunkWrapper.getChunkPos()))
|
||||
{
|
||||
chunkWrapper.setBlockLightStorage(chunkBlockLightingByDhPos.get(chunkWrapper.getChunkPos()));
|
||||
chunkWrapper.setSkyLightStorage(chunkSkyLightingByDhPos.get(chunkWrapper.getChunkPos()));
|
||||
chunkWrapper.setUseDhLighting(true);
|
||||
chunkWrapper.setIsDhLightCorrect(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
int k = 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
//=================//
|
||||
// generate chunks //
|
||||
//=================//
|
||||
|
||||
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 = ChunkWrapper.getStatus(target) == 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 (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.infoInc("{}", genEvent.timer);
|
||||
}
|
||||
}
|
||||
private CompoundTag getChunkNbtData(ChunkPos chunkPos)
|
||||
{
|
||||
ServerLevel level = this.params.level;
|
||||
|
||||
CompoundTag chunkData = null;
|
||||
try
|
||||
{
|
||||
IOWorker ioWorker = level.getChunkSource().chunkMap.worker;
|
||||
|
||||
#if MC_VER <= MC_1_18_2
|
||||
chunkData = ioWorker.load(chunkPos);
|
||||
#else
|
||||
|
||||
// timeout should prevent locking up the thread if the ioWorker dies or has issues
|
||||
int maxGetTimeInSec = Config.Client.Advanced.WorldGenerator.worldGenerationTimeoutLengthInSeconds.get();
|
||||
CompletableFuture<Optional<CompoundTag>> future = ioWorker.loadAsync(chunkPos);
|
||||
try
|
||||
{
|
||||
Optional<CompoundTag> data = future.get(maxGetTimeInSec, TimeUnit.SECONDS);
|
||||
if (data.isPresent())
|
||||
{
|
||||
chunkData = data.get();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOAD_LOGGER.warn("Unable to get chunk at pos ["+chunkPos+"] after ["+maxGetTimeInSec+"] milliseconds.", e);
|
||||
future.cancel(true);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
catch (Exception 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)
|
||||
{
|
||||
ServerLevel level = this.params.level;
|
||||
|
||||
if (chunkData == null)
|
||||
{
|
||||
return CreateEmptyChunk(level, chunkPos);
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
LOAD_LOGGER.info("DistantHorizons: Loading chunk [" + chunkPos + "] from disk.");
|
||||
return ChunkLoader.read(level, chunkPos, chunkData);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOAD_LOGGER.error(
|
||||
"DistantHorizons: couldn't load or make chunk at ["+chunkPos+"]." +
|
||||
"Please try optimizing your world to fix this issue. \n" +
|
||||
"World optimization can be done from the singleplayer world selection screen.\n" +
|
||||
"Error: ["+e.getMessage()+"]."
|
||||
, e);
|
||||
|
||||
return CreateEmptyChunk(level, chunkPos);
|
||||
}
|
||||
}
|
||||
}
|
||||
private static ProtoChunk CreateEmptyChunk(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 void generateDirect(
|
||||
GenerationEvent genEvent, ArrayGridList<ChunkWrapper> chunksToGenerate, int border,
|
||||
EDhApiWorldGenerationStep step, DhLitWorldGenRegion region) throws InterruptedException
|
||||
{
|
||||
if (Thread.interrupted())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
chunksToGenerate.forEach((chunkWrapper) ->
|
||||
{
|
||||
ChunkAccess chunk = chunkWrapper.getChunk();
|
||||
if (chunk instanceof ProtoChunk)
|
||||
{
|
||||
ProtoChunk protoChunk = ((ProtoChunk) chunk);
|
||||
|
||||
protoChunk.setLightEngine(region.getLightEngine());
|
||||
}
|
||||
});
|
||||
|
||||
if (step == EDhApiWorldGenerationStep.EMPTY)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
genEvent.timer.nextEvent("structStart");
|
||||
throwIfThreadInterrupted();
|
||||
this.stepStructureStart.generateGroup(genEvent.threadedParam, region, GetCutoutFrom(chunksToGenerate, EDhApiWorldGenerationStep.STRUCTURE_START));
|
||||
genEvent.refreshTimeout();
|
||||
if (step == EDhApiWorldGenerationStep.STRUCTURE_START)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
genEvent.timer.nextEvent("structRef");
|
||||
throwIfThreadInterrupted();
|
||||
this.stepStructureReference.generateGroup(genEvent.threadedParam, region, GetCutoutFrom(chunksToGenerate, EDhApiWorldGenerationStep.STRUCTURE_REFERENCE));
|
||||
genEvent.refreshTimeout();
|
||||
if (step == EDhApiWorldGenerationStep.STRUCTURE_REFERENCE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
genEvent.timer.nextEvent("biome");
|
||||
throwIfThreadInterrupted();
|
||||
this.stepBiomes.generateGroup(genEvent.threadedParam, region, GetCutoutFrom(chunksToGenerate, EDhApiWorldGenerationStep.BIOMES));
|
||||
genEvent.refreshTimeout();
|
||||
if (step == EDhApiWorldGenerationStep.BIOMES)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
genEvent.timer.nextEvent("noise");
|
||||
throwIfThreadInterrupted();
|
||||
this.stepNoise.generateGroup(genEvent.threadedParam, region, GetCutoutFrom(chunksToGenerate, EDhApiWorldGenerationStep.NOISE));
|
||||
genEvent.refreshTimeout();
|
||||
if (step == EDhApiWorldGenerationStep.NOISE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
genEvent.timer.nextEvent("surface");
|
||||
throwIfThreadInterrupted();
|
||||
this.stepSurface.generateGroup(genEvent.threadedParam, region, GetCutoutFrom(chunksToGenerate, EDhApiWorldGenerationStep.SURFACE));
|
||||
genEvent.refreshTimeout();
|
||||
if (step == EDhApiWorldGenerationStep.SURFACE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
genEvent.timer.nextEvent("carver");
|
||||
throwIfThreadInterrupted();
|
||||
// caves can generally be ignored since they aren't generally visible from far away
|
||||
if (step == EDhApiWorldGenerationStep.CARVERS)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
genEvent.timer.nextEvent("feature");
|
||||
throwIfThreadInterrupted();
|
||||
this.stepFeatures.generateGroup(genEvent.threadedParam, region, GetCutoutFrom(chunksToGenerate, EDhApiWorldGenerationStep.FEATURES));
|
||||
genEvent.refreshTimeout();
|
||||
}
|
||||
finally
|
||||
{
|
||||
genEvent.timer.nextEvent("light");
|
||||
|
||||
// generate lighting using DH's lighting engine
|
||||
|
||||
int maxSkyLight = this.serverlevel.getServerLevelWrapper().hasSkyLight() ? 15 : 0;
|
||||
|
||||
// only light generated chunks,
|
||||
// attempting to light un-generated chunks will cause lighting issues on bordering generated chunks
|
||||
ArrayList<IChunkWrapper> iChunkWrapperList = new ArrayList<>();
|
||||
for (int i = 0; i < chunksToGenerate.size(); i++) // regular for loop since enhanced for loops increase GC pressure slightly
|
||||
{
|
||||
ChunkWrapper chunkWrapper = chunksToGenerate.get(i);
|
||||
if (chunkWrapper.getStatus() != ChunkStatus.EMPTY)
|
||||
{
|
||||
iChunkWrapperList.add(chunkWrapper);
|
||||
}
|
||||
}
|
||||
|
||||
// light each chunk in the list
|
||||
for (int i = 0; i < iChunkWrapperList.size(); i++)
|
||||
{
|
||||
IChunkWrapper centerChunk = iChunkWrapperList.get(i);
|
||||
if (centerChunk == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
throwIfThreadInterrupted();
|
||||
|
||||
// make sure the height maps are all properly generated
|
||||
// if this isn't done everything else afterward may fail
|
||||
Heightmap.primeHeightmaps(((ChunkWrapper)centerChunk).getChunk(), ChunkStatus.FEATURES.heightmapsAfter());
|
||||
|
||||
// pre-generated chunks should have lighting but new ones won't
|
||||
if (!centerChunk.isLightCorrect())
|
||||
{
|
||||
DhLightingEngine.INSTANCE.lightChunk(centerChunk, iChunkWrapperList, maxSkyLight);
|
||||
}
|
||||
}
|
||||
|
||||
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 - BorderNeeded.get(step)); }
|
||||
|
||||
|
||||
@Override
|
||||
public int getEventCount() { return this.generationEventList.size(); }
|
||||
|
||||
@Override
|
||||
public void stop()
|
||||
{
|
||||
EVENT_LOGGER.info(BatchGenerationEnvironment.class.getSimpleName() + " shutting down...");
|
||||
|
||||
EVENT_LOGGER.info("Canceling in progress generation event futures...");
|
||||
Iterator<GenerationEvent> iter = this.generationEventList.iterator();
|
||||
while (iter.hasNext())
|
||||
{
|
||||
GenerationEvent event = iter.next();
|
||||
event.future.cancel(true);
|
||||
iter.remove();
|
||||
}
|
||||
|
||||
// clear the chunk cache
|
||||
RegionFileStorageExternalCache regionStorage = this.regionFileStorageCacheRef.get();
|
||||
if (regionStorage != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
regionStorage.close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
EVENT_LOGGER.error("Failed to close region file storage cache!", e);
|
||||
}
|
||||
}
|
||||
|
||||
EVENT_LOGGER.info(BatchGenerationEnvironment.class.getSimpleName() + " shutdown complete.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Void> generateChunks(
|
||||
int minX, int minZ, int genSize, EDhApiWorldGenerationStep targetStep,
|
||||
ExecutorService worldGeneratorThreadPool, Consumer<IChunkWrapper> resultConsumer)
|
||||
{
|
||||
//System.out.println("GenerationEvent: "+genSize+"@"+minX+","+minZ+" "+targetStep);
|
||||
|
||||
// TODO: Check event overlap via e.tooClose()
|
||||
GenerationEvent genEvent = GenerationEvent.startEvent(new DhChunkPos(minX, minZ), genSize, this, targetStep, resultConsumer, worldGeneratorThreadPool);
|
||||
this.generationEventList.add(genEvent);
|
||||
return genEvent.future;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// helper methods //
|
||||
//================//
|
||||
|
||||
/**
|
||||
* Called before code that may run for an extended period of time. <br>
|
||||
* This is necessary to allow canceling world gen since waiting
|
||||
* for some world gen requests to finish can take a while.
|
||||
*/
|
||||
public static void throwIfThreadInterrupted() throws InterruptedException
|
||||
{
|
||||
if (Thread.interrupted())
|
||||
{
|
||||
throw new InterruptedException(FullDataToRenderDataTransformer.class.getSimpleName() + " task interrupted.");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// helper classes //
|
||||
//================//
|
||||
|
||||
@FunctionalInterface
|
||||
public interface IEmptyChunkGeneratorFunc
|
||||
{
|
||||
ChunkAccess generate(int x, int z);
|
||||
}
|
||||
|
||||
}
|
||||
+37
-45
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
* 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
|
||||
@@ -17,21 +17,21 @@
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.common.wrappers.worldGeneration;
|
||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.seibel.lod.api.enums.worldGeneration.EDhApiWorldGenerationStep;
|
||||
import com.seibel.lod.core.util.objects.UncheckedInterruptedException;
|
||||
import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.api.enums.config.ELightGenerationMode;
|
||||
import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.lod.core.pos.DhChunkPos;
|
||||
import com.seibel.lod.core.util.objects.EventTimer;
|
||||
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiWorldGenerationStep;
|
||||
import com.seibel.distanthorizons.core.util.objects.UncheckedInterruptedException;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||
import com.seibel.distanthorizons.core.util.objects.EventTimer;
|
||||
import com.seibel.distanthorizons.core.util.threading.ThreadPoolUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
@@ -40,23 +40,22 @@ public final class GenerationEvent
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
|
||||
private static int generationFutureDebugIDs = 0;
|
||||
|
||||
final int id;
|
||||
final ThreadedParameters threadedParam;
|
||||
final DhChunkPos minPos;
|
||||
final int size;
|
||||
final EDhApiWorldGenerationStep targetGenerationStep;
|
||||
final ELightGenerationMode lightMode;
|
||||
final double runTimeRatio;
|
||||
EventTimer timer = null;
|
||||
long inQueueTime;
|
||||
long timeoutTime = -1;
|
||||
public final int id;
|
||||
public final ThreadedParameters threadedParam;
|
||||
public final DhChunkPos minPos;
|
||||
public final int size;
|
||||
public final EDhApiWorldGenerationStep targetGenerationStep;
|
||||
public EventTimer timer = null;
|
||||
public long inQueueTime;
|
||||
public long timeoutTime = -1;
|
||||
public CompletableFuture<Void> future = null;
|
||||
final Consumer<IChunkWrapper> resultConsumer;
|
||||
public final Consumer<IChunkWrapper> resultConsumer;
|
||||
|
||||
|
||||
|
||||
public GenerationEvent(DhChunkPos minPos, int size, BatchGenerationEnvironment generationGroup,
|
||||
EDhApiWorldGenerationStep targetGenerationStep, double runTimeRatio, Consumer<IChunkWrapper> resultConsumer)
|
||||
public GenerationEvent(
|
||||
DhChunkPos minPos, int size, BatchGenerationEnvironment generationGroup,
|
||||
EDhApiWorldGenerationStep targetGenerationStep, Consumer<IChunkWrapper> resultConsumer)
|
||||
{
|
||||
this.inQueueTime = System.nanoTime();
|
||||
this.id = generationFutureDebugIDs++;
|
||||
@@ -64,51 +63,44 @@ public final class GenerationEvent
|
||||
this.size = size;
|
||||
this.targetGenerationStep = targetGenerationStep;
|
||||
this.threadedParam = ThreadedParameters.getOrMake(generationGroup.params);
|
||||
this.lightMode = Config.Client.WorldGenerator.lightGenerationMode.get();
|
||||
this.runTimeRatio = runTimeRatio;
|
||||
this.resultConsumer = resultConsumer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static GenerationEvent startEvent(DhChunkPos minPos, int size, BatchGenerationEnvironment generationGroup,
|
||||
EDhApiWorldGenerationStep target, double runTimeRatio, Consumer<IChunkWrapper> resultConsumer)
|
||||
public static GenerationEvent startEvent(
|
||||
DhChunkPos minPos, int size, BatchGenerationEnvironment genEnvironment,
|
||||
EDhApiWorldGenerationStep target, Consumer<IChunkWrapper> resultConsumer,
|
||||
ExecutorService worldGeneratorThreadPool)
|
||||
{
|
||||
if (size % 2 == 0)
|
||||
{
|
||||
size += 1; // size must be odd for vanilla world gen regions to work
|
||||
}
|
||||
|
||||
GenerationEvent generationEvent = new GenerationEvent(minPos, size, generationGroup, target, runTimeRatio, resultConsumer);
|
||||
|
||||
GenerationEvent generationEvent = new GenerationEvent(minPos, size, genEnvironment, target, resultConsumer);
|
||||
generationEvent.future = CompletableFuture.runAsync(() ->
|
||||
{
|
||||
long runStartTime = System.nanoTime();
|
||||
generationEvent.timeoutTime = runStartTime;
|
||||
generationEvent.inQueueTime = runStartTime - generationEvent.inQueueTime;
|
||||
generationEvent.timer = new EventTimer("setup");
|
||||
|
||||
BatchGenerationEnvironment.isDistantGeneratorThread.set(true);
|
||||
try
|
||||
{
|
||||
//LOGGER.info("generating [{}]", event.minPos);
|
||||
generationGroup.generateLodFromList(generationEvent);
|
||||
genEnvironment.generateLodFromList(generationEvent);
|
||||
}
|
||||
catch (InterruptedException ignored)
|
||||
{
|
||||
}
|
||||
finally
|
||||
{
|
||||
BatchGenerationEnvironment.isDistantGeneratorThread.remove();
|
||||
if (!Thread.interrupted() && runTimeRatio < 1.0)
|
||||
{
|
||||
long endTime = System.nanoTime();
|
||||
try
|
||||
{
|
||||
long deltaMs = TimeUnit.NANOSECONDS.toMillis(endTime - runStartTime);
|
||||
Thread.sleep((long) (deltaMs / runTimeRatio - deltaMs));
|
||||
}
|
||||
catch (InterruptedException ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}, generationGroup.executors);
|
||||
}, worldGeneratorThreadPool);
|
||||
return generationEvent;
|
||||
}
|
||||
|
||||
@@ -129,7 +121,7 @@ public final class GenerationEvent
|
||||
public boolean terminate()
|
||||
{
|
||||
LOGGER.info("======================DUMPING ALL THREADS FOR WORLD GEN=======================");
|
||||
BatchGenerationEnvironment.threadFactory.dumpAllThreadStacks();
|
||||
ThreadPoolUtil.WORLD_GEN_THREAD_FACTORY.dumpAllThreadStacks();
|
||||
this.future.cancel(true);
|
||||
return this.future.isCancelled();
|
||||
}
|
||||
@@ -156,6 +148,6 @@ public final class GenerationEvent
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() { return this.id+":"+this.size+"@"+this.minPos+"("+this.targetGenerationStep +")"; }
|
||||
public String toString() { return this.id + ":" + this.size + "@" + this.minPos + "(" + this.targetGenerationStep + ")"; }
|
||||
|
||||
}
|
||||
+32
-18
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
* 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
|
||||
@@ -16,12 +16,12 @@
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.common.wrappers.worldGeneration;
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration;
|
||||
|
||||
import com.mojang.datafixers.DataFixer;
|
||||
import com.seibel.lod.common.wrappers.world.ServerLevelWrapper;
|
||||
import com.seibel.lod.core.level.IDhServerLevel;
|
||||
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
|
||||
import com.seibel.distanthorizons.core.level.IDhServerLevel;
|
||||
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
@@ -31,36 +31,43 @@ import net.minecraft.server.level.ThreadedLevelLightEngine;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.biome.BiomeManager;
|
||||
import net.minecraft.world.level.chunk.ChunkGenerator;
|
||||
#if POST_MC_1_18_1
|
||||
#if MC_VER >= MC_1_18_2
|
||||
import net.minecraft.world.level.chunk.storage.ChunkScanAccess;
|
||||
#endif
|
||||
import net.minecraft.world.level.levelgen.WorldGenSettings;
|
||||
#if PRE_MC_1_19
|
||||
#if MC_VER < MC_1_19_2
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager;
|
||||
#else
|
||||
import net.minecraft.world.level.levelgen.RandomState;
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureTemplateManager;
|
||||
import net.minecraft.world.level.levelgen.RandomState;
|
||||
#if MC_VER >= MC_1_19_4
|
||||
import net.minecraft.world.level.levelgen.WorldOptions;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
#endif
|
||||
#endif
|
||||
import net.minecraft.world.level.storage.WorldData;
|
||||
|
||||
public final class GlobalParameters
|
||||
{
|
||||
public final ChunkGenerator generator;
|
||||
#if PRE_MC_1_19
|
||||
#if MC_VER < MC_1_19_2
|
||||
public final StructureManager structures;
|
||||
#else
|
||||
public final StructureTemplateManager structures;
|
||||
public final RandomState randomState;
|
||||
#endif
|
||||
#if MC_VER < MC_1_19_4
|
||||
public final WorldGenSettings worldGenSettings;
|
||||
public final ThreadedLevelLightEngine lightEngine;
|
||||
#else
|
||||
public final WorldOptions worldOptions;
|
||||
#endif
|
||||
public final IDhServerLevel lodLevel;
|
||||
public final ServerLevel level;
|
||||
public final Registry<Biome> biomes;
|
||||
public final RegistryAccess registry;
|
||||
public final long worldSeed;
|
||||
public final DataFixer fixerUpper;
|
||||
#if POST_MC_1_18_1
|
||||
#if MC_VER >= MC_1_18_2
|
||||
public final BiomeManager biomeManager;
|
||||
public final ChunkScanAccess chunkScanner; // FIXME: Figure out if this is actually needed
|
||||
#endif
|
||||
@@ -68,24 +75,31 @@ public final class GlobalParameters
|
||||
public GlobalParameters(IDhServerLevel lodLevel)
|
||||
{
|
||||
this.lodLevel = lodLevel;
|
||||
|
||||
level = ((ServerLevelWrapper)lodLevel.getServerLevelWrapper()).getWrappedMcObject_UNSAFE();
|
||||
lightEngine = (ThreadedLevelLightEngine) level.getLightEngine();
|
||||
|
||||
level = ((ServerLevelWrapper) lodLevel.getServerLevelWrapper()).getWrappedMcObject();
|
||||
MinecraftServer server = level.getServer();
|
||||
WorldData worldData = server.getWorldData();
|
||||
worldGenSettings = worldData.worldGenSettings();
|
||||
registry = server.registryAccess();
|
||||
|
||||
#if MC_VER < MC_1_19_4
|
||||
worldGenSettings = worldData.worldGenSettings();
|
||||
biomes = registry.registryOrThrow(Registry.BIOME_REGISTRY);
|
||||
worldSeed = worldGenSettings.seed();
|
||||
#if POST_MC_1_18_1
|
||||
#else
|
||||
worldOptions = worldData.worldGenOptions();
|
||||
biomes = registry.registryOrThrow(Registries.BIOME);
|
||||
worldSeed = worldOptions.seed();
|
||||
#endif
|
||||
#if MC_VER >= MC_1_18_2
|
||||
biomeManager = new BiomeManager(level, BiomeManager.obfuscateSeed(worldSeed));
|
||||
chunkScanner = level.getChunkSource().chunkScanner();
|
||||
#endif
|
||||
structures = server.getStructureManager();
|
||||
generator = level.getChunkSource().getGenerator();
|
||||
fixerUpper = server.getFixerUpper();
|
||||
#if POST_MC_1_19
|
||||
#if MC_VER >= MC_1_19_2
|
||||
randomState = level.getChunkSource().randomState();
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
+8
-5
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
* 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
|
||||
@@ -16,9 +16,9 @@
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
package com.seibel.lod.common.wrappers.worldGeneration;
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration;
|
||||
|
||||
//FIXME: Move this outside the WorldGenerationStep thingy
|
||||
public class Rolling
|
||||
@@ -34,7 +34,9 @@ public class Rolling
|
||||
this.size = size;
|
||||
samples = new double[size];
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
samples[i] = 0d;
|
||||
}
|
||||
}
|
||||
|
||||
public void add(double x)
|
||||
@@ -48,6 +50,7 @@ public class Rolling
|
||||
|
||||
public double getAverage()
|
||||
{
|
||||
return size==0 ? 0 : total / size;
|
||||
return size == 0 ? 0 : total / size;
|
||||
}
|
||||
|
||||
}
|
||||
+16
-12
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
* 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
|
||||
@@ -16,16 +16,16 @@
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
package com.seibel.lod.common.wrappers.worldGeneration;
|
||||
|
||||
import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment.PerfCalculator;
|
||||
import com.seibel.lod.common.wrappers.worldGeneration.mimicObject.WorldGenStructFeatManager;
|
||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment.PerfCalculator;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.WorldGenStructFeatManager;
|
||||
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.WorldGenLevel;
|
||||
#if POST_MC_1_18_1
|
||||
#if MC_VER >= MC_1_18_2
|
||||
import net.minecraft.world.level.levelgen.structure.StructureCheck;
|
||||
#endif
|
||||
|
||||
@@ -35,7 +35,7 @@ public final class ThreadedParameters
|
||||
|
||||
final ServerLevel level;
|
||||
public WorldGenStructFeatManager structFeat = null;
|
||||
#if POST_MC_1_18_1
|
||||
#if MC_VER >= MC_1_18_2
|
||||
public StructureCheck structCheck;
|
||||
#endif
|
||||
boolean isValid = true;
|
||||
@@ -63,9 +63,9 @@ public final class ThreadedParameters
|
||||
previousGlobalParameters = param;
|
||||
|
||||
this.level = param.level;
|
||||
#if PRE_MC_1_18_1
|
||||
#if MC_VER < MC_1_18_2
|
||||
this.structFeat = new WorldGenStructFeatManager(param.worldGenSettings, level);
|
||||
#elif PRE_MC_1_19
|
||||
#elif MC_VER < MC_1_19_2
|
||||
this.structCheck = this.createStructureCheck(param);
|
||||
#else
|
||||
this.structCheck = new StructureCheck(param.chunkScanner, param.registry, param.structures,
|
||||
@@ -80,11 +80,15 @@ public final class ThreadedParameters
|
||||
|
||||
public void makeStructFeat(WorldGenLevel genLevel, GlobalParameters param)
|
||||
{
|
||||
structFeat = new WorldGenStructFeatManager(param.worldGenSettings, genLevel #if POST_MC_1_18_1, structCheck #endif);
|
||||
#if MC_VER < MC_1_19_4
|
||||
structFeat = new WorldGenStructFeatManager(param.worldGenSettings, genLevel #if MC_VER >= MC_1_18_2 , structCheck #endif );
|
||||
#else
|
||||
structFeat = new WorldGenStructFeatManager(param.worldOptions, genLevel, structCheck);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
#if PRE_MC_1_19
|
||||
#if MC_VER >= MC_1_18_2 && MC_VER < MC_1_19_2
|
||||
public void recreateStructureCheck()
|
||||
{
|
||||
if (previousGlobalParameters != null)
|
||||
+522
@@ -0,0 +1,522 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU GPL 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 General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.mojang.serialization.Codec;
|
||||
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.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.LongSet;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
|
||||
import net.minecraft.core.Registry;
|
||||
import net.minecraft.core.SectionPos;
|
||||
#if MC_VER >= MC_1_19_4
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
#endif
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.ListTag;
|
||||
import net.minecraft.nbt.NbtOps;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.level.*;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.biome.Biomes;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.chunk.*;
|
||||
import net.minecraft.world.level.chunk.storage.ChunkSerializer;
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
#if MC_VER >= MC_1_18_2
|
||||
import net.minecraft.world.level.levelgen.blending.BlendingData;
|
||||
#if MC_VER < MC_1_19_2
|
||||
import net.minecraft.world.level.levelgen.feature.StructureFeature;
|
||||
#endif
|
||||
import net.minecraft.world.level.levelgen.structure.StructureStart;
|
||||
import net.minecraft.world.level.levelgen.structure.pieces.StructurePieceSerializationContext;
|
||||
import net.minecraft.world.ticks.LevelChunkTicks;
|
||||
#endif
|
||||
#if MC_VER >= MC_1_18_2
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.RegistryAccess;
|
||||
#if MC_VER < MC_1_19_2
|
||||
import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||
import net.minecraft.world.level.material.Fluids;
|
||||
#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
|
||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||
import net.minecraft.world.level.chunk.status.ChunkType;
|
||||
#endif
|
||||
|
||||
import net.minecraft.world.level.material.Fluid;
|
||||
|
||||
|
||||
public class ChunkLoader
|
||||
{
|
||||
private static boolean zeroChunkPosErrorLogged = false;
|
||||
|
||||
#if MC_VER >= MC_1_19_2
|
||||
private static final Codec<PalettedContainer<BlockState>> BLOCK_STATE_CODEC = PalettedContainer.codecRW(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState());
|
||||
#elif MC_VER >= MC_1_18_2
|
||||
private static final Codec<PalettedContainer<BlockState>> BLOCK_STATE_CODEC = PalettedContainer.codec(Block.BLOCK_STATE_REGISTRY, BlockState.CODEC, PalettedContainer.Strategy.SECTION_STATES, Blocks.AIR.defaultBlockState());
|
||||
#endif
|
||||
private static final String TAG_UPGRADE_DATA = "UpgradeData";
|
||||
private static final String BLOCK_TICKS_TAG_18 = "block_ticks";
|
||||
private static final String FLUID_TICKS_TAG_18 = "fluid_ticks";
|
||||
private static final String BLOCK_TICKS_TAG_PRE18 = "TileTicks";
|
||||
private static final String FLUID_TICKS_TAG_PRE18 = "LiquidTicks";
|
||||
private static final ConfigBasedLogger LOGGER = BatchGenerationEnvironment.LOAD_LOGGER;
|
||||
|
||||
private static boolean lightingSectionErrorLogged = false;
|
||||
|
||||
|
||||
|
||||
//============//
|
||||
// read chunk //
|
||||
//============//
|
||||
|
||||
public static LevelChunk read(WorldGenLevel level, ChunkPos chunkPos, CompoundTag chunkData)
|
||||
{
|
||||
#if MC_VER < MC_1_18_2
|
||||
CompoundTag tagLevel = chunkData.getCompound("Level");
|
||||
#else
|
||||
CompoundTag tagLevel = chunkData;
|
||||
#endif
|
||||
|
||||
ChunkPos actualPos = new ChunkPos(tagLevel.getInt("xPos"), tagLevel.getInt("zPos"));
|
||||
if (!Objects.equals(chunkPos, actualPos))
|
||||
{
|
||||
#if MC_VER > MC_1_17_1
|
||||
if (actualPos.equals(ChunkPos.ZERO))
|
||||
#else
|
||||
if (actualPos.equals(ChunkPos.INVALID_CHUNK_POS))
|
||||
#endif
|
||||
{
|
||||
if (!zeroChunkPosErrorLogged)
|
||||
{
|
||||
zeroChunkPosErrorLogged = true;
|
||||
|
||||
// explicit chunkPos toString is necessary otherwise the JDK 17 compiler breaks
|
||||
LOGGER.warn("Chunk file at ["+chunkPos.toString()+"] doesn't have a chunk pos. \n" +
|
||||
"This might happen if the world was created using an external program. \n" +
|
||||
"DH will attempt to parse the chunk anyway and won't log this message again.\n" +
|
||||
"If issues arise please try optimizing your world to fix this issue. \n" +
|
||||
"World optimization can be done from the singleplayer world selection screen."+
|
||||
"");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// everything is on one line to fix a JDK 17 compiler issue
|
||||
// if the issue is ever resolved, feel free to make this multi-line for readability
|
||||
LOGGER.error("Chunk file at ["+chunkPos.toString()+"] is in the wrong location. \nPlease try optimizing your world to fix this issue. \nWorld optimization can be done from the singleplayer world selection screen. \n(Expected pos: ["+chunkPos.toString()+"], actual ["+actualPos.toString()+"])");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
#if MC_VER < MC_1_20_6
|
||||
ChunkStatus.ChunkType chunkType;
|
||||
#else
|
||||
ChunkType chunkType;
|
||||
#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
|
||||
|
||||
long inhabitedTime = tagLevel.getLong("InhabitedTime");
|
||||
|
||||
//================== Read params for making the LevelChunk ==================
|
||||
UpgradeData upgradeData = tagLevel.contains(TAG_UPGRADE_DATA, 10)
|
||||
? new UpgradeData(tagLevel.getCompound(TAG_UPGRADE_DATA)#if MC_VER >= MC_1_17_1 , level #endif )
|
||||
: UpgradeData.EMPTY;
|
||||
|
||||
boolean isLightOn = tagLevel.getBoolean("isLightOn");
|
||||
#if MC_VER < MC_1_18_2
|
||||
ChunkBiomeContainer chunkBiomeContainer = new ChunkBiomeContainer(
|
||||
level.getLevel().registryAccess().registryOrThrow(Registry.BIOME_REGISTRY)#if MC_VER >= MC_1_17_1 , level #endif ,
|
||||
chunkPos, level.getLevel().getChunkSource().getGenerator().getBiomeSource(),
|
||||
tagLevel.contains("Biomes", 11) ? tagLevel.getIntArray("Biomes") : null);
|
||||
|
||||
TickList<Block> blockTicks = tagLevel.contains(BLOCK_TICKS_TAG_PRE18, 9)
|
||||
? ChunkTickList.create(tagLevel.getList(BLOCK_TICKS_TAG_PRE18, 10), Registry.BLOCK::getKey, Registry.BLOCK::get)
|
||||
: new ProtoTickList<Block>(block -> (block == null || block.defaultBlockState().isAir()), chunkPos,
|
||||
tagLevel.getList("ToBeTicked", 9)#if MC_VER >= MC_1_17_1 , level #endif );
|
||||
|
||||
TickList<Fluid> fluidTicks = tagLevel.contains(FLUID_TICKS_TAG_PRE18, 9)
|
||||
? ChunkTickList.create(tagLevel.getList(FLUID_TICKS_TAG_PRE18, 10), Registry.FLUID::getKey, Registry.FLUID::get)
|
||||
: new ProtoTickList<Fluid>(fluid -> (fluid == null || fluid == Fluids.EMPTY), chunkPos,
|
||||
tagLevel.getList("LiquidsToBeTicked", 9)#if MC_VER >= MC_1_17_1 , level #endif );
|
||||
#else
|
||||
#if MC_VER < MC_1_19_4
|
||||
LevelChunkTicks<Block> blockTicks = LevelChunkTicks.load(tagLevel.getList(BLOCK_TICKS_TAG_18, 10),
|
||||
string -> Registry.BLOCK.getOptional(ResourceLocation.tryParse(string)), chunkPos);
|
||||
LevelChunkTicks<Fluid> fluidTicks = LevelChunkTicks.load(tagLevel.getList(FLUID_TICKS_TAG_18, 10),
|
||||
string -> Registry.FLUID.getOptional(ResourceLocation.tryParse(string)), chunkPos);
|
||||
#else
|
||||
LevelChunkTicks<Block> blockTicks = LevelChunkTicks.load(tagLevel.getList(BLOCK_TICKS_TAG_18, 10),
|
||||
(string -> BuiltInRegistries.BLOCK.getOptional(ResourceLocation.tryParse(string))), chunkPos);
|
||||
LevelChunkTicks<Fluid> fluidTicks = LevelChunkTicks.load(tagLevel.getList(FLUID_TICKS_TAG_18, 10),
|
||||
string -> BuiltInRegistries.FLUID.getOptional(ResourceLocation.tryParse(string)), chunkPos);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
LevelChunkSection[] levelChunkSections = readSections(level, chunkPos, tagLevel);
|
||||
|
||||
// ====================== Make the chunk =========================
|
||||
#if MC_VER < MC_1_18_2
|
||||
LevelChunk chunk = new LevelChunk((Level) level.getLevel(), chunkPos, chunkBiomeContainer, upgradeData, blockTicks,
|
||||
fluidTicks, inhabitedTime, levelChunkSections, null);
|
||||
#else
|
||||
|
||||
LevelChunk chunk = new LevelChunk((Level) level, chunkPos, upgradeData, blockTicks,
|
||||
fluidTicks, inhabitedTime, levelChunkSections, null, blendingData);
|
||||
#endif
|
||||
// Set some states after object creation
|
||||
chunk.setLightCorrect(isLightOn);
|
||||
readHeightmaps(chunk, chunkData);
|
||||
readPostPocessings(chunk, chunkData);
|
||||
return chunk;
|
||||
}
|
||||
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))
|
||||
#if MC_VER < MC_1_20_6
|
||||
.getOrThrow(false, LOGGER::error)
|
||||
#else
|
||||
.getOrThrow((message) -> (RuntimeException) LOGGER.errorAndThrow(message, null))
|
||||
#endif
|
||||
: new PalettedContainer<BlockState>(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES);
|
||||
|
||||
#if MC_VER < MC_1_18_2
|
||||
biomeContainer = tagSection.contains("biomes", 10)
|
||||
? biomeCodec.parse(NbtOps.INSTANCE, tagSection.getCompound("biomes")).promotePartial(string -> logErrors(chunkPos, sectionYPos, string)).getOrThrow(false, LOGGER::error)
|
||||
: new PalettedContainer<Biome>(biomes, biomes.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
|
||||
#else
|
||||
|
||||
biomeContainer = tagSection.contains("biomes", 10)
|
||||
? biomeCodec.parse(NbtOps.INSTANCE, tagSection.getCompound("biomes")).promotePartial(string -> logErrors(chunkPos, i, (String) string))
|
||||
#if MC_VER < MC_1_20_6
|
||||
.getOrThrow(false, LOGGER::error)
|
||||
#else
|
||||
.getOrThrow((message) -> (RuntimeException) LOGGER.errorAndThrow(message, null))
|
||||
#endif
|
||||
: new PalettedContainer<Holder<Biome>>(biomes.asHolderIdMap(), biomes.getHolderOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
|
||||
#endif
|
||||
|
||||
#if MC_VER < MC_1_20_1
|
||||
chunkSections[sectionId] = new LevelChunkSection(sectionYPos, blockStateContainer, biomeContainer);
|
||||
#else
|
||||
chunkSections[sectionId] = new LevelChunkSection(blockStateContainer, biomeContainer);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
return chunkSections;
|
||||
}
|
||||
private static
|
||||
#if MC_VER < MC_1_20_6 ChunkStatus.ChunkType
|
||||
#elif MC_VER < MC_1_21 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 logErrors(ChunkPos chunkPos, int i, String string)
|
||||
{
|
||||
LOGGER.error("Distant Horizons: Recoverable errors when loading section [" + chunkPos.x + ", " + i + ", " + chunkPos.z + "]: " + string);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// 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
|
||||
|
||||
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
|
||||
+422
@@ -0,0 +1,422 @@
|
||||
/*
|
||||
* 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.worldGeneration.mimicObject;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
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.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
import net.minecraft.world.level.block.EntityBlock;
|
||||
import net.minecraft.world.level.block.SpawnerBlock;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Cursor3D;
|
||||
import net.minecraft.core.SectionPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.WorldGenRegion;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.ColorResolver;
|
||||
#if MC_VER >= MC_1_17_1
|
||||
import net.minecraft.world.level.LevelHeightAccessor;
|
||||
#endif
|
||||
import net.minecraft.world.level.LightLayer;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.ImposterProtoChunk;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
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
|
||||
import net.minecraft.util.StaticCache2D;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import net.minecraft.server.level.GenerationChunkHolder;
|
||||
#endif
|
||||
|
||||
|
||||
public class DhLitWorldGenRegion extends WorldGenRegion
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
|
||||
|
||||
private static ChunkStatus debugTriggeredForStatus = null;
|
||||
|
||||
|
||||
public final DummyLightEngine lightEngine;
|
||||
public final BatchGenerationEnvironment.IEmptyChunkGeneratorFunc generator;
|
||||
public final int writeRadius;
|
||||
public final int size;
|
||||
|
||||
private final ChunkPos firstPos;
|
||||
private final List<ChunkAccess> cache;
|
||||
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,
|
||||
* specifically: "it.unimi.dsi.fastutil.longs.Long2ObjectLinkedOpenHashMap.getAndMoveToFirst()"
|
||||
*/
|
||||
private final ReentrantLock getChunkLock = new ReentrantLock();
|
||||
|
||||
#if MC_VER < MC_1_18_2
|
||||
private ChunkPos overrideCenterPos = null;
|
||||
|
||||
public void setOverrideCenter(ChunkPos pos) { overrideCenterPos = pos; }
|
||||
#if MC_VER < MC_1_17_1
|
||||
@Override
|
||||
public int getCenterX()
|
||||
{
|
||||
return overrideCenterPos==null ? super.getCenterX() : overrideCenterPos.x;
|
||||
}
|
||||
@Override
|
||||
public int getCenterZ()
|
||||
{
|
||||
return overrideCenterPos==null ? super.getCenterX() : overrideCenterPos.z;
|
||||
}
|
||||
#else
|
||||
@Override
|
||||
public ChunkPos getCenter()
|
||||
{
|
||||
return overrideCenterPos == null ? super.getCenter() : overrideCenterPos;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
public DhLitWorldGenRegion(
|
||||
int centerChunkX, int centerChunkZ,
|
||||
ChunkAccess centerChunk,
|
||||
ServerLevel serverLevel, DummyLightEngine lightEngine,
|
||||
List<ChunkAccess> chunkList, ChunkStatus chunkStatus, int writeRadius,
|
||||
BatchGenerationEnvironment.IEmptyChunkGeneratorFunc generator)
|
||||
{
|
||||
#if MC_VER == MC_1_16_5
|
||||
super(serverLevel, chunkList);
|
||||
#elif MC_VER < MC_1_21
|
||||
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.generator = generator;
|
||||
this.lightEngine = lightEngine;
|
||||
this.writeRadius = writeRadius;
|
||||
this.cache = chunkList;
|
||||
this.size = Mth.floor(Math.sqrt(chunkList.size()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if MC_VER >= MC_1_17_1
|
||||
// Bypass BCLib mixin overrides.
|
||||
@Override
|
||||
public boolean ensureCanWrite(BlockPos blockPos)
|
||||
{
|
||||
int i = SectionPos.blockToSectionCoord(blockPos.getX());
|
||||
int j = SectionPos.blockToSectionCoord(blockPos.getZ());
|
||||
ChunkPos chunkPos = this.getCenter();
|
||||
ChunkAccess center = this.getChunk(chunkPos.x, chunkPos.z);
|
||||
int k = Math.abs(chunkPos.x - i);
|
||||
int l = Math.abs(chunkPos.z - j);
|
||||
if (k > this.writeRadius || l > this.writeRadius)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#if MC_VER >= MC_1_18_2
|
||||
if (center.isUpgrading())
|
||||
{
|
||||
LevelHeightAccessor levelHeightAccessor = center.getHeightAccessorForGeneration();
|
||||
if (blockPos.getY() < levelHeightAccessor.getMinBuildHeight() || blockPos.getY() >= levelHeightAccessor.getMaxBuildHeight())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
// TODO Check this
|
||||
// @Override
|
||||
// public List<? extends StructureStart<?>> startsForFeature(SectionPos sectionPos,
|
||||
// StructureFeature<?> structureFeature) {
|
||||
// return structFeat.startsForFeature(sectionPos, structureFeature);
|
||||
// }
|
||||
|
||||
// Skip updating the related tile entities
|
||||
@Override
|
||||
public boolean setBlock(BlockPos blockPos, BlockState blockState, int i, int j)
|
||||
{
|
||||
ChunkAccess chunkAccess = this.getChunk(blockPos);
|
||||
if (chunkAccess instanceof LevelChunk)
|
||||
return true;
|
||||
chunkAccess.setBlockState(blockPos, blockState, false);
|
||||
// This is for post ticking for water on gen and stuff like that. Not enabled
|
||||
// for now.
|
||||
// if (blockState.hasPostProcess(this, blockPos))
|
||||
// this.getChunk(blockPos).markPosForPostprocessing(blockPos);
|
||||
return true;
|
||||
}
|
||||
|
||||
// Skip Dropping the item on destroy
|
||||
@Override
|
||||
public boolean destroyBlock(BlockPos blockPos, boolean bl, @Nullable Entity entity, int i)
|
||||
{
|
||||
BlockState blockState = this.getBlockState(blockPos);
|
||||
if (blockState.isAir())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return this.setBlock(blockPos, Blocks.AIR.defaultBlockState(), 3, i);
|
||||
}
|
||||
|
||||
// Skip BlockEntity stuff. It aren't really needed
|
||||
@Override
|
||||
public BlockEntity getBlockEntity(BlockPos blockPos)
|
||||
{
|
||||
BlockState blockState = this.getBlockState(blockPos);
|
||||
|
||||
// This is a bypass for the spawner block since MC complains about not having it
|
||||
#if MC_VER >= MC_1_17_1
|
||||
if (blockState.getBlock() instanceof SpawnerBlock)
|
||||
{
|
||||
return ((EntityBlock) blockState.getBlock()).newBlockEntity(blockPos, blockState);
|
||||
}
|
||||
else return null;
|
||||
#else
|
||||
if (blockState.getBlock() instanceof SpawnerBlock) {
|
||||
return ((EntityBlock) blockState.getBlock()).newBlockEntity(this);
|
||||
} else return null;
|
||||
#endif
|
||||
}
|
||||
|
||||
/** 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
|
||||
// @Override
|
||||
// public boolean hasChunk(int i, int j) {
|
||||
// return true;
|
||||
// }
|
||||
|
||||
// Override to ensure no other mod mixins cause skipping the overrided
|
||||
// getChunk(...)
|
||||
@Override
|
||||
public @NotNull ChunkAccess getChunk(int chunkX, int chunkZ)
|
||||
{
|
||||
try
|
||||
{
|
||||
// lock is to prevent issues with underlying MC code that doesn't support multithreading
|
||||
this.getChunkLock.lock();
|
||||
return this.getChunk(chunkX, chunkZ, ChunkStatus.EMPTY);
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.getChunkLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
// Override to ensure no other mod mixins cause skipping the overrided
|
||||
// getChunk(...)
|
||||
@Override
|
||||
public @NotNull ChunkAccess getChunk(int chunkX, int chunkZ, @NotNull ChunkStatus chunkStatus)
|
||||
{
|
||||
try
|
||||
{
|
||||
// lock is to prevent issues with underlying MC code that doesn't support multithreading
|
||||
this.getChunkLock.lock();
|
||||
|
||||
ChunkAccess chunk = this.getChunk(chunkX, chunkZ, chunkStatus, true);
|
||||
if (chunk == null)
|
||||
{
|
||||
LodUtil.assertNotReach("getChunk shouldn't return null values");
|
||||
}
|
||||
return chunk;
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.getChunkLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
/** Allows creating empty chunks even if they're outside the worldGenRegion */
|
||||
@Override
|
||||
@Nullable
|
||||
public ChunkAccess getChunk(int chunkX, int chunkZ, @NotNull ChunkStatus chunkStatus, boolean returnNonNull)
|
||||
{
|
||||
ChunkAccess chunk = this.getChunkAccess(chunkX, chunkZ, chunkStatus, returnNonNull);
|
||||
if (chunk instanceof LevelChunk)
|
||||
{
|
||||
chunk = new ImposterProtoChunk((LevelChunk) chunk #if MC_VER >= MC_1_18_2 , true #endif );
|
||||
}
|
||||
return chunk;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param returnNonNull if true this method will always return a non-null chunk,
|
||||
* 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 = this.superHasChunk(chunkX, chunkZ) ? this.superGetChunk(chunkX, chunkZ) : null;
|
||||
if (chunk != null && ChunkWrapper.getStatus(chunk).isOrAfter(chunkStatus))
|
||||
{
|
||||
return chunk;
|
||||
}
|
||||
else if (!returnNonNull)
|
||||
{
|
||||
// no chunk found with the necessary status and null return values are allowed
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
// we need a non-null chunk
|
||||
if (chunk == null)
|
||||
{
|
||||
// check memory
|
||||
chunk = this.chunkMap.get(ChunkPos.asLong(chunkX, chunkZ));
|
||||
if (chunk == null)
|
||||
{
|
||||
// chunk isn't in memory, generate a new one
|
||||
chunk = this.generator.generate(chunkX, chunkZ);
|
||||
if (chunk == null)
|
||||
{
|
||||
throw new NullPointerException("The provided generator should not return null!");
|
||||
}
|
||||
this.chunkMap.put(ChunkPos.asLong(chunkX, chunkZ), chunk);
|
||||
}
|
||||
}
|
||||
|
||||
if (chunkStatus != ChunkStatus.EMPTY && chunkStatus != debugTriggeredForStatus)
|
||||
{
|
||||
LOGGER.info("WorldGen requiring " + chunkStatus
|
||||
+ " outside expected range detected. Force passing EMPTY chunk and seeing if it works.");
|
||||
debugTriggeredForStatus = chunkStatus;
|
||||
}
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
||||
/** Use this instead of super.hasChunk() to bypass C2ME concurrency checks */
|
||||
public boolean superHasChunk(int x, int z)
|
||||
{
|
||||
int k = x - this.firstPos.x;
|
||||
int l = z - this.firstPos.z;
|
||||
return l >= 0 && l < this.size && k >= 0 && k < this.size;
|
||||
}
|
||||
|
||||
/** Use this instead of super.getChunk() to bypass C2ME concurrency checks */
|
||||
private ChunkAccess superGetChunk(int x, int z)
|
||||
{
|
||||
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)
|
||||
{
|
||||
#if MC_VER >= MC_1_18_2
|
||||
return this.getBiome(pos).value();
|
||||
#else
|
||||
return this.getBiome(pos);
|
||||
#endif
|
||||
}
|
||||
|
||||
public int calculateBlockTint(BlockPos blockPos, ColorResolver colorResolver)
|
||||
{
|
||||
#if MC_VER < MC_1_19_2
|
||||
int i = (Minecraft.getInstance()).options.biomeBlendRadius;
|
||||
#else
|
||||
int i = (Minecraft.getInstance()).options.biomeBlendRadius().get();
|
||||
#endif
|
||||
if (i == 0)
|
||||
return colorResolver.getColor((Biome) _getBiome(blockPos), blockPos.getX(), blockPos.getZ());
|
||||
int j = (i * 2 + 1) * (i * 2 + 1);
|
||||
int k = 0;
|
||||
int l = 0;
|
||||
int m = 0;
|
||||
Cursor3D cursor3D = new Cursor3D(blockPos.getX() - i, blockPos.getY(), blockPos.getZ() - i, blockPos.getX() + i, blockPos.getY(), blockPos.getZ() + i);
|
||||
BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
|
||||
while (cursor3D.advance())
|
||||
{
|
||||
mutableBlockPos.set(cursor3D.nextX(), cursor3D.nextY(), cursor3D.nextZ());
|
||||
int n = colorResolver.getColor((Biome) _getBiome((BlockPos) mutableBlockPos), mutableBlockPos.getX(), mutableBlockPos.getZ());
|
||||
k += (n & 0xFF0000) >> 16;
|
||||
l += (n & 0xFF00) >> 8;
|
||||
m += n & 0xFF;
|
||||
}
|
||||
return (k / j & 0xFF) << 16 | (l / j & 0xFF) << 8 | m / j & 0xFF;
|
||||
}
|
||||
|
||||
}
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* 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.worldGeneration.mimicObject;
|
||||
|
||||
import net.minecraft.world.level.lighting.*;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.SectionPos;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
|
||||
import net.minecraft.world.level.LightLayer;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.DataLayer;
|
||||
|
||||
public class DummyLightEngine extends LevelLightEngine
|
||||
{
|
||||
|
||||
public DummyLightEngine(LightGetterAdaptor genRegion)
|
||||
{
|
||||
super(genRegion, false, false);
|
||||
}
|
||||
|
||||
|
||||
#if MC_VER < MC_1_20_1
|
||||
@Override
|
||||
public void onBlockEmissionIncrease(BlockPos blockPos, int i) { }
|
||||
|
||||
@Override
|
||||
public int runUpdates(int i, boolean bl, boolean bl2) { return 0; }
|
||||
|
||||
@Override
|
||||
public void enableLightSources(ChunkPos chunkPos, boolean bl) { }
|
||||
|
||||
#else
|
||||
@Override
|
||||
public int runLightUpdates() { return 0; }
|
||||
|
||||
@Override
|
||||
public void setLightEnabled(ChunkPos $$0, boolean $$1) { }
|
||||
|
||||
@Override
|
||||
public void propagateLightSources(ChunkPos arg) { }
|
||||
|
||||
public boolean lightOnInSection(SectionPos $$0) { return false; }
|
||||
#endif
|
||||
|
||||
@Override
|
||||
public void queueSectionData(LightLayer lightLayer, SectionPos sectionPos, @Nullable DataLayer dataLayer #if MC_VER < MC_1_20_1 , boolean bl #endif ) { }
|
||||
|
||||
@Override
|
||||
public void checkBlock(BlockPos blockPos) { }
|
||||
|
||||
@Override
|
||||
public boolean hasLightWork() { return false; }
|
||||
|
||||
@Override
|
||||
public void updateSectionStatus(SectionPos sectionPos, boolean bl) { }
|
||||
|
||||
@Override
|
||||
public LayerLightEventListener getLayerListener(LightLayer lightLayer) { return LayerLightEventListener.DummyLightLayerEventListener.INSTANCE; }
|
||||
|
||||
@Override
|
||||
public int getRawBrightness(BlockPos blockPos, int i) { return 0; }
|
||||
|
||||
public void lightChunk(ChunkAccess chunkAccess, boolean needLightBlockUpdate) { }
|
||||
|
||||
@Override
|
||||
public String getDebugData(LightLayer lightLayer, SectionPos sectionPos) { throw new UnsupportedOperationException("This should never be used!"); }
|
||||
@Override
|
||||
public void retainData(ChunkPos chunkPos, boolean bl) { }
|
||||
|
||||
#if MC_VER >= MC_1_17_1
|
||||
@Override
|
||||
public int getLightSectionCount() { throw new UnsupportedOperationException("This should never be used!"); }
|
||||
@Override
|
||||
public int getMinLightSection() { throw new UnsupportedOperationException("This should never be used!"); }
|
||||
@Override
|
||||
public int getMaxLightSection() { throw new UnsupportedOperationException("This should never be used!"); }
|
||||
#endif
|
||||
|
||||
}
|
||||
+42
-24
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
* 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
|
||||
@@ -16,48 +16,66 @@
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.common.wrappers.worldGeneration.mimicObject;
|
||||
|
||||
import com.seibel.lod.core.dependencyInjection.ModAccessorInjector;
|
||||
import com.seibel.lod.core.wrapperInterfaces.modAccessor.IStarlightAccessor;
|
||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject;
|
||||
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.modAccessor.IStarlightAccessor;
|
||||
|
||||
import net.minecraft.world.level.BlockGetter;
|
||||
#if POST_MC_1_17_1
|
||||
import net.minecraft.world.level.LevelHeightAccessor;
|
||||
#endif
|
||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||
import net.minecraft.world.level.chunk.LightChunkGetter;
|
||||
|
||||
public class LightGetterAdaptor implements LightChunkGetter {
|
||||
private final BlockGetter heightGetter;
|
||||
public LightedWorldGenRegion genRegion = null;
|
||||
final boolean shouldReturnNull;
|
||||
#if MC_VER >= MC_1_17_1
|
||||
import net.minecraft.world.level.LevelHeightAccessor;
|
||||
#endif
|
||||
|
||||
public LightGetterAdaptor(BlockGetter heightAccessor) {
|
||||
#if MC_VER >= MC_1_20_1
|
||||
import net.minecraft.world.level.chunk.LightChunk;
|
||||
#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
|
||||
{
|
||||
private final BlockGetter heightGetter;
|
||||
public DhLitWorldGenRegion genRegion = null;
|
||||
final boolean shouldReturnNull;
|
||||
|
||||
public LightGetterAdaptor(BlockGetter heightAccessor)
|
||||
{
|
||||
this.heightGetter = heightAccessor;
|
||||
shouldReturnNull = ModAccessorInjector.INSTANCE.get(IStarlightAccessor.class) != null;
|
||||
}
|
||||
|
||||
public void setRegion(LightedWorldGenRegion region) {
|
||||
|
||||
public void setRegion(DhLitWorldGenRegion region)
|
||||
{
|
||||
genRegion = region;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BlockGetter getChunkForLighting(int chunkX, int chunkZ) {
|
||||
public #if MC_VER < MC_1_20_1 BlockGetter #else LightChunk #endif getChunkForLighting(int chunkX, int chunkZ)
|
||||
{
|
||||
if (genRegion == null)
|
||||
throw new IllegalStateException("World Gen region has not been set!");
|
||||
// May be null
|
||||
return genRegion.getChunk(chunkX, chunkZ, ChunkStatus.EMPTY, false);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BlockGetter getLevel() {
|
||||
public BlockGetter getLevel()
|
||||
{
|
||||
return shouldReturnNull ? null : (genRegion != null ? genRegion : heightGetter);
|
||||
}
|
||||
|
||||
#if POST_MC_1_17_1
|
||||
public LevelHeightAccessor getLevelHeightAccessor() {
|
||||
|
||||
#if MC_VER >= MC_1_17_1
|
||||
public LevelHeightAccessor getLevelHeightAccessor()
|
||||
{
|
||||
return heightGetter;
|
||||
}
|
||||
#endif
|
||||
+240
@@ -0,0 +1,240 @@
|
||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.nbt.NbtIo;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.chunk.storage.RegionFile;
|
||||
import net.minecraft.world.level.chunk.storage.RegionFileStorage;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
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
|
||||
* prevent potential file corruption and issues with the C2ME mod.
|
||||
* Generally this would be done via (MC ServerLevel) level.getChunkSource().chunkMap.worker#loadAsync()
|
||||
*/
|
||||
@Deprecated
|
||||
public class RegionFileStorageExternalCache implements AutoCloseable
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
|
||||
/** Can be null due to the C2ME mod */
|
||||
@Nullable
|
||||
public final RegionFileStorage storage;
|
||||
public static final int MAX_CACHE_SIZE = 16;
|
||||
|
||||
public static boolean regionCacheNullPointerWarningSent = false;
|
||||
|
||||
/**
|
||||
* 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()"
|
||||
*/
|
||||
ReentrantLock getRegionFileLock = new ReentrantLock();
|
||||
|
||||
|
||||
|
||||
static class RegionFileCache
|
||||
{
|
||||
public final long pos;
|
||||
public final RegionFile file;
|
||||
|
||||
public RegionFileCache(long pos, RegionFile file)
|
||||
{
|
||||
this.pos = pos;
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public ConcurrentLinkedQueue<RegionFileCache> regionFileCache = new ConcurrentLinkedQueue<>();
|
||||
|
||||
public RegionFileStorageExternalCache(RegionFileStorage storage) { this.storage = storage; }
|
||||
|
||||
@Nullable
|
||||
public RegionFile getRegionFile(ChunkPos pos) throws IOException
|
||||
{
|
||||
if (this.storage == null)
|
||||
{
|
||||
if (!regionCacheNullPointerWarningSent)
|
||||
{
|
||||
regionCacheNullPointerWarningSent = true;
|
||||
LOGGER.warn("Unable to access Minecraft's chunk cache. This may be due to another mod changing said cache. DH will be unable to access any Minecraft chunk data until said mod is removed.");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
long posLong = ChunkPos.asLong(pos.getRegionX(), pos.getRegionZ());
|
||||
RegionFile rFile = null;
|
||||
|
||||
// Check vanilla cache
|
||||
int retryCount = 0;
|
||||
int maxRetryCount = 8;
|
||||
while (retryCount < maxRetryCount)
|
||||
{
|
||||
retryCount++;
|
||||
|
||||
try
|
||||
{
|
||||
this.getRegionFileLock.lock();
|
||||
|
||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||
rFile = this.storage.getRegionFile(pos);
|
||||
|
||||
// keeping the region cache size low helps prevent concurrency issues
|
||||
if (this.storage.regionCache.size() > 150) // max 256
|
||||
{
|
||||
RegionFile removedFile = this.storage.regionCache.removeLast();
|
||||
if (removedFile != null)
|
||||
{
|
||||
removedFile.close();
|
||||
}
|
||||
}
|
||||
#else
|
||||
rFile = this.storage.regionCache.getOrDefault(posLong, null);
|
||||
#endif
|
||||
|
||||
break;
|
||||
}
|
||||
catch (ArrayIndexOutOfBoundsException e)
|
||||
{
|
||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||
// the file just wasn't cached
|
||||
break;
|
||||
#else
|
||||
// potential concurrency issue, wait a second and try to get the file again
|
||||
try
|
||||
{
|
||||
Thread.sleep(250);
|
||||
}
|
||||
catch (InterruptedException ignored)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
}
|
||||
catch (NullPointerException e)
|
||||
{
|
||||
// Can sometimes happen when other mods modify the region cache system (IE C2ME)
|
||||
// instead of blowing up, just use DH's cache instead
|
||||
|
||||
if (!regionCacheNullPointerWarningSent)
|
||||
{
|
||||
regionCacheNullPointerWarningSent = true;
|
||||
LOGGER.warn("Unable to access Minecraft's chunk cache. This may be due to another mod changing said cache. Falling back to DH's internal cache.");
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
finally
|
||||
{
|
||||
this.getRegionFileLock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
if (retryCount >= maxRetryCount)
|
||||
{
|
||||
BatchGenerationEnvironment.LOAD_LOGGER.warn("Concurrency issue detected when getting region file for chunk at " + pos + ".");
|
||||
}
|
||||
|
||||
|
||||
if (rFile != null)
|
||||
{
|
||||
return rFile;
|
||||
}
|
||||
|
||||
// Then check our custom cache
|
||||
for (RegionFileCache cache : this.regionFileCache)
|
||||
{
|
||||
if (cache.pos == posLong)
|
||||
{
|
||||
return cache.file;
|
||||
}
|
||||
}
|
||||
|
||||
// Otherwise, check if file exist, and if so, add it to the cache
|
||||
Path storageFolderPath;
|
||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||
storageFolderPath = this.storage.folder.toPath();
|
||||
#else
|
||||
storageFolderPath = this.storage.folder;
|
||||
#endif
|
||||
|
||||
if (!Files.exists(storageFolderPath))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Path regionFilePath = storageFolderPath.resolve("r." + pos.getRegionX() + "." + pos.getRegionZ() + ".mca");
|
||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||
rFile = new RegionFile(regionFilePath.toFile(), storageFolderPath.toFile(), false);
|
||||
#elif MC_VER <= MC_1_20_4
|
||||
rFile = new RegionFile(regionFilePath, storageFolderPath, false);
|
||||
#else
|
||||
rFile = new RegionFile(new RegionStorageInfo("level", null, "level type"), regionFilePath, storageFolderPath, false);
|
||||
#endif
|
||||
|
||||
this.regionFileCache.add(new RegionFileCache(ChunkPos.asLong(pos.getRegionX(), pos.getRegionZ()), rFile));
|
||||
while (this.regionFileCache.size() > MAX_CACHE_SIZE)
|
||||
{
|
||||
this.regionFileCache.poll().file.close();
|
||||
}
|
||||
|
||||
return rFile;
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
public CompoundTag read(ChunkPos pos) throws IOException
|
||||
{
|
||||
RegionFile file = this.getRegionFile(pos);
|
||||
if (file == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
try (DataInputStream stream = file.getChunkDataInputStream(pos))
|
||||
{
|
||||
if (stream == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return NbtIo.read(stream);
|
||||
}
|
||||
catch (Throwable e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void close() throws IOException
|
||||
{
|
||||
RegionFileCache cache;
|
||||
while ((cache = this.regionFileCache.poll()) != null)
|
||||
{
|
||||
cache.file.close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+110
-63
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
* 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
|
||||
@@ -16,82 +16,118 @@
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.common.wrappers.worldGeneration.mimicObject;
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
import it.unimi.dsi.fastutil.longs.LongIterator;
|
||||
import it.unimi.dsi.fastutil.longs.LongSet;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.SectionPos;
|
||||
import net.minecraft.server.level.WorldGenRegion;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import net.minecraft.world.level.LevelAccessor;
|
||||
import net.minecraft.world.level.WorldGenLevel;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||
import net.minecraft.world.level.levelgen.WorldGenSettings;
|
||||
#if PRE_MC_1_19
|
||||
#if MC_VER < MC_1_19_2
|
||||
import net.minecraft.world.level.levelgen.feature.ConfiguredStructureFeature;
|
||||
import net.minecraft.world.level.levelgen.feature.StructureFeature;
|
||||
import net.minecraft.world.level.StructureFeatureManager;
|
||||
#else
|
||||
#if MC_VER >= MC_1_19_4
|
||||
import net.minecraft.world.level.levelgen.WorldOptions;
|
||||
#endif
|
||||
import net.minecraft.world.level.levelgen.structure.Structure;
|
||||
import net.minecraft.world.level.StructureManager;
|
||||
#endif
|
||||
#if POST_MC_1_18_1
|
||||
#if MC_VER >= MC_1_18_2
|
||||
import net.minecraft.world.level.levelgen.structure.StructureCheck;
|
||||
#endif
|
||||
|
||||
import net.minecraft.world.level.levelgen.structure.StructureStart;
|
||||
|
||||
#if PRE_MC_1_19
|
||||
public class WorldGenStructFeatManager extends StructureFeatureManager {
|
||||
#if MC_VER < MC_1_18_2
|
||||
import net.minecraft.world.level.levelgen.feature.StructureFeature;
|
||||
#endif
|
||||
|
||||
#if MC_VER <= MC_1_20_4
|
||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||
#else
|
||||
public class WorldGenStructFeatManager extends StructureManager {
|
||||
#endif
|
||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
public class WorldGenStructFeatManager extends #if MC_VER < MC_1_19_2 StructureFeatureManager #else StructureManager #endif
|
||||
{
|
||||
final WorldGenLevel genLevel;
|
||||
|
||||
#if MC_VER < MC_1_19_4
|
||||
WorldGenSettings worldGenSettings;
|
||||
#if POST_MC_1_18_1
|
||||
StructureCheck structureCheck;
|
||||
|
||||
#else
|
||||
WorldOptions worldOptions;
|
||||
#endif
|
||||
public WorldGenStructFeatManager(WorldGenSettings worldGenSettings,
|
||||
WorldGenLevel genLevel #if POST_MC_1_18_1 , StructureCheck structureCheck #endif ) {
|
||||
|
||||
super(genLevel, worldGenSettings #if POST_MC_1_18_1 , structureCheck #endif );
|
||||
|
||||
#if MC_VER >= MC_1_18_2
|
||||
StructureCheck structureCheck;
|
||||
#endif
|
||||
|
||||
#if MC_VER < MC_1_19_4
|
||||
public WorldGenStructFeatManager(
|
||||
WorldGenSettings worldGenSettings,
|
||||
WorldGenLevel genLevel #if MC_VER >= MC_1_18_2 , StructureCheck structureCheck #endif )
|
||||
{
|
||||
|
||||
super(genLevel, worldGenSettings #if MC_VER >= MC_1_18_2 , structureCheck #endif );
|
||||
this.genLevel = genLevel;
|
||||
this.worldGenSettings = worldGenSettings;
|
||||
}
|
||||
|
||||
#else
|
||||
public WorldGenStructFeatManager(
|
||||
WorldOptions worldOptions,
|
||||
WorldGenLevel genLevel, StructureCheck structureCheck)
|
||||
{
|
||||
|
||||
super(genLevel, worldOptions, structureCheck);
|
||||
this.genLevel = genLevel;
|
||||
this.worldOptions = worldOptions;
|
||||
}
|
||||
#endif
|
||||
|
||||
@Override
|
||||
public WorldGenStructFeatManager forWorldGenRegion(WorldGenRegion worldGenRegion) {
|
||||
public WorldGenStructFeatManager forWorldGenRegion(WorldGenRegion worldGenRegion)
|
||||
{
|
||||
if (worldGenRegion == genLevel)
|
||||
return this;
|
||||
return new WorldGenStructFeatManager(worldGenSettings, worldGenRegion #if POST_MC_1_18_1 , structureCheck #endif );
|
||||
#if MC_VER < MC_1_19_4
|
||||
return new WorldGenStructFeatManager(worldGenSettings, worldGenRegion #if MC_VER >= MC_1_18_2 , structureCheck #endif );
|
||||
#else
|
||||
return new WorldGenStructFeatManager(worldOptions, worldGenRegion, structureCheck);
|
||||
#endif
|
||||
}
|
||||
|
||||
private ChunkAccess _getChunk(int x, int z, ChunkStatus status) {
|
||||
|
||||
private ChunkAccess _getChunk(int x, int z, ChunkStatus status)
|
||||
{
|
||||
if (genLevel == null) return null;
|
||||
return genLevel.getChunk(x, z, status, false);
|
||||
}
|
||||
|
||||
#if PRE_MC_1_18_1
|
||||
|
||||
#if MC_VER < MC_1_18_2
|
||||
@Override
|
||||
public Stream<? extends StructureStart<?>> startsForFeature(SectionPos sectionPos2,
|
||||
StructureFeature<?> structureFeature) {
|
||||
public Stream<? extends StructureStart<?>> startsForFeature(
|
||||
SectionPos sectionPos2,
|
||||
StructureFeature<?> structureFeature)
|
||||
{
|
||||
ChunkAccess chunk = _getChunk(sectionPos2.x(), sectionPos2.z(), ChunkStatus.STRUCTURE_REFERENCES);
|
||||
if (chunk == null) return Stream.empty();
|
||||
|
||||
|
||||
// FIXME getReferencesForFeature can throw ConcurrentModificationException's
|
||||
return chunk.getReferencesForFeature(structureFeature).stream().map(pos -> {
|
||||
SectionPos sectPos = SectionPos.of(ChunkPos.getX(pos), 0, ChunkPos.getZ(pos));
|
||||
ChunkAccess startChunk = _getChunk(sectPos.x(), sectPos.z(), ChunkStatus.STRUCTURE_STARTS);
|
||||
@@ -101,14 +137,15 @@ public class WorldGenStructFeatManager extends StructureManager {
|
||||
}
|
||||
#else
|
||||
@Override
|
||||
public boolean hasAnyStructureAt(BlockPos blockPos) {
|
||||
public boolean hasAnyStructureAt(BlockPos blockPos)
|
||||
{
|
||||
SectionPos sectionPos = SectionPos.of(blockPos);
|
||||
ChunkAccess chunk = _getChunk(sectionPos.x(), sectionPos.z(), ChunkStatus.STRUCTURE_REFERENCES);
|
||||
if (chunk == null) return false;
|
||||
return chunk.hasAnyStructureReferences();
|
||||
}
|
||||
|
||||
#if MC_1_18_1
|
||||
|
||||
#if MC_VER == MC_1_18_1
|
||||
@Override
|
||||
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||
public List<? extends StructureStart<?>> startsForFeature(SectionPos sectionPos,
|
||||
@@ -133,36 +170,40 @@ public class WorldGenStructFeatManager extends StructureManager {
|
||||
return builder.build();
|
||||
}
|
||||
#else
|
||||
#if PRE_MC_1_19
|
||||
#if MC_VER < MC_1_19_2
|
||||
@Override
|
||||
public List<StructureStart> startsForFeature(SectionPos sectionPos, Predicate<ConfiguredStructureFeature<?, ?>> predicate) {
|
||||
public List<StructureStart> startsForFeature(SectionPos sectionPos, Predicate<ConfiguredStructureFeature<?, ?>> predicate)
|
||||
{
|
||||
ChunkAccess chunk = _getChunk(sectionPos.x(), sectionPos.z(), ChunkStatus.STRUCTURE_REFERENCES);
|
||||
if (chunk == null) return List.of();
|
||||
|
||||
|
||||
// Copied from StructureFeatureManager::startsForFeature(...)
|
||||
Map<ConfiguredStructureFeature<?, ?>, LongSet> map = chunk.getAllReferences();
|
||||
|
||||
|
||||
ImmutableList.Builder<StructureStart> builder = ImmutableList.builder();
|
||||
Iterator<Map.Entry<ConfiguredStructureFeature<?, ?>, LongSet>> var5 = map.entrySet().iterator();
|
||||
|
||||
while(var5.hasNext()) {
|
||||
|
||||
while (var5.hasNext())
|
||||
{
|
||||
Map.Entry<ConfiguredStructureFeature<?, ?>, LongSet> entry = var5.next();
|
||||
ConfiguredStructureFeature<?, ?> configuredStructureFeature = entry.getKey();
|
||||
if (predicate.test(configuredStructureFeature)) {
|
||||
LongSet var10002 = (LongSet)entry.getValue();
|
||||
if (predicate.test(configuredStructureFeature))
|
||||
{
|
||||
LongSet var10002 = (LongSet) entry.getValue();
|
||||
Objects.requireNonNull(builder);
|
||||
this.fillStartsForFeature(configuredStructureFeature, var10002, builder::add);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<StructureStart> startsForFeature(SectionPos sectionPos, ConfiguredStructureFeature<?, ?> configuredStructureFeature) {
|
||||
public List<StructureStart> startsForFeature(SectionPos sectionPos, ConfiguredStructureFeature<?, ?> configuredStructureFeature)
|
||||
{
|
||||
ChunkAccess chunk = _getChunk(sectionPos.x(), sectionPos.z(), ChunkStatus.STRUCTURE_REFERENCES);
|
||||
if (chunk == null) return (List<StructureStart>) Stream.empty();
|
||||
|
||||
|
||||
// Copied from StructureFeatureManager::startsForFeature(...)
|
||||
LongSet longSet = chunk.getReferencesForFeature(configuredStructureFeature);
|
||||
ImmutableList.Builder<StructureStart> builder = ImmutableList.builder();
|
||||
@@ -170,44 +211,49 @@ public class WorldGenStructFeatManager extends StructureManager {
|
||||
this.fillStartsForFeature(configuredStructureFeature, longSet, builder::add);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Map<ConfiguredStructureFeature<?, ?>, LongSet> getAllStructuresAt(BlockPos blockPos) {
|
||||
public Map<ConfiguredStructureFeature<?, ?>, LongSet> getAllStructuresAt(BlockPos blockPos)
|
||||
{
|
||||
SectionPos sectionPos = SectionPos.of(blockPos);
|
||||
ChunkAccess chunk = _getChunk(sectionPos.x(), sectionPos.z(), ChunkStatus.STRUCTURE_REFERENCES);
|
||||
if (chunk == null) return (Map<ConfiguredStructureFeature<?, ?>, LongSet>) Stream.empty();
|
||||
return chunk.getAllReferences();
|
||||
return chunk.getAllReferences();
|
||||
}
|
||||
#else
|
||||
@Override
|
||||
public List<StructureStart> startsForStructure(ChunkPos sectionPos, Predicate<Structure> predicate) {
|
||||
public List<StructureStart> startsForStructure(ChunkPos sectionPos, Predicate<Structure> predicate)
|
||||
{
|
||||
ChunkAccess chunk = _getChunk(sectionPos.x, sectionPos.z, ChunkStatus.STRUCTURE_REFERENCES);
|
||||
if (chunk == null) return List.of();
|
||||
|
||||
|
||||
// Copied from StructureFeatureManager::startsForFeature(...)
|
||||
Map<Structure, LongSet> map = chunk.getAllReferences();
|
||||
|
||||
|
||||
ImmutableList.Builder<StructureStart> builder = ImmutableList.builder();
|
||||
Iterator<Map.Entry<Structure, LongSet>> var5 = map.entrySet().iterator();
|
||||
|
||||
while (var5.hasNext()) {
|
||||
|
||||
while (var5.hasNext())
|
||||
{
|
||||
Map.Entry<Structure, LongSet> entry = var5.next();
|
||||
Structure configuredStructureFeature = entry.getKey();
|
||||
if (predicate.test(configuredStructureFeature)) {
|
||||
if (predicate.test(configuredStructureFeature))
|
||||
{
|
||||
LongSet var10002 = (LongSet) entry.getValue();
|
||||
Objects.requireNonNull(builder);
|
||||
this.fillStartsForStructure(configuredStructureFeature, var10002, builder::add);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<StructureStart> startsForStructure(SectionPos sectionPos, Structure structure) {
|
||||
public List<StructureStart> startsForStructure(SectionPos sectionPos, Structure structure)
|
||||
{
|
||||
ChunkAccess chunk = _getChunk(sectionPos.x(), sectionPos.z(), ChunkStatus.STRUCTURE_REFERENCES);
|
||||
if (chunk == null) return (List<StructureStart>) Stream.empty();
|
||||
|
||||
|
||||
// Copied from StructureFeatureManager::startsForFeature(...)
|
||||
LongSet longSet = chunk.getReferencesForStructure(structure);
|
||||
ImmutableList.Builder<StructureStart> builder = ImmutableList.builder();
|
||||
@@ -215,9 +261,10 @@ public class WorldGenStructFeatManager extends StructureManager {
|
||||
this.fillStartsForStructure(structure, longSet, builder::add);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Map<Structure, LongSet> getAllStructuresAt(BlockPos blockPos) {
|
||||
public Map<Structure, LongSet> getAllStructuresAt(BlockPos blockPos)
|
||||
{
|
||||
SectionPos sectionPos = SectionPos.of(blockPos);
|
||||
ChunkAccess chunk = _getChunk(sectionPos.x(), sectionPos.z(), ChunkStatus.STRUCTURE_REFERENCES);
|
||||
if (chunk == null) return (Map<Structure, LongSet>) Stream.empty();
|
||||
+97
@@ -0,0 +1,97 @@
|
||||
/*
|
||||
* 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.worldGeneration.step;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters;
|
||||
|
||||
import net.minecraft.server.level.WorldGenRegion;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||
|
||||
#if MC_VER >= MC_1_18_2
|
||||
import net.minecraft.world.level.levelgen.blending.Blender;
|
||||
#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 static final ChunkStatus STATUS = ChunkStatus.BIOMES;
|
||||
|
||||
private final BatchGenerationEnvironment environment;
|
||||
|
||||
|
||||
public StepBiomes(BatchGenerationEnvironment batchGenerationEnvironment) { this.environment = batchGenerationEnvironment; }
|
||||
|
||||
|
||||
|
||||
public void generateGroup(
|
||||
ThreadedParameters tParams, WorldGenRegion worldGenRegion,
|
||||
List<ChunkWrapper> chunkWrappers)
|
||||
{
|
||||
|
||||
ArrayList<ChunkAccess> chunksToDo = new ArrayList<>();
|
||||
|
||||
for (ChunkWrapper chunkWrapper : chunkWrappers)
|
||||
{
|
||||
ChunkAccess chunk = chunkWrapper.getChunk();
|
||||
if (!chunkWrapper.getStatus().isOrAfter(STATUS))
|
||||
{
|
||||
#if MC_VER < MC_1_21
|
||||
((ProtoChunk) chunk).setStatus(STATUS);
|
||||
#else
|
||||
((ProtoChunk) chunk).setPersistedStatus(STATUS);
|
||||
#endif
|
||||
|
||||
chunksToDo.add(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
for (ChunkAccess chunk : chunksToDo)
|
||||
{
|
||||
// System.out.println("StepBiomes: "+chunk.getPos());
|
||||
#if MC_VER < MC_1_18_2
|
||||
this.environment.params.generator.createBiomes(this.environment.params.biomes, chunk);
|
||||
#elif MC_VER < MC_1_19_2
|
||||
chunk = this.environment.joinSync(this.environment.params.generator.createBiomes(this.environment.params.biomes, Runnable::run, Blender.of(worldGenRegion),
|
||||
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
|
||||
#elif MC_VER < MC_1_19_4
|
||||
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
|
||||
chunk = this.environment.joinSync(this.environment.params.generator.createBiomes(Runnable::run, this.environment.params.randomState, Blender.of(worldGenRegion),
|
||||
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
|
||||
#else
|
||||
chunk = this.environment.joinSync(this.environment.params.generator.createBiomes(this.environment.params.randomState, Blender.of(worldGenRegion),
|
||||
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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.worldGeneration.step;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject.DhLitWorldGenRegion;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.util.gridList.ArrayGridList;
|
||||
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
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
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
|
||||
public static final ChunkStatus STATUS = ChunkStatus.FEATURES;
|
||||
|
||||
private final BatchGenerationEnvironment environment;
|
||||
|
||||
|
||||
|
||||
public StepFeatures(BatchGenerationEnvironment batchGenerationEnvironment) { this.environment = batchGenerationEnvironment; }
|
||||
|
||||
|
||||
|
||||
public void generateGroup(
|
||||
ThreadedParameters tParams, DhLitWorldGenRegion worldGenRegion,
|
||||
ArrayGridList<ChunkWrapper> chunkWrappers)
|
||||
{
|
||||
for (ChunkWrapper chunkWrapper : chunkWrappers)
|
||||
{
|
||||
ChunkAccess chunk = chunkWrapper.getChunk();
|
||||
if (!chunkWrapper.getStatus().isOrAfter(STATUS)
|
||||
&& chunk instanceof ProtoChunk)
|
||||
{
|
||||
#if MC_VER < MC_1_21
|
||||
((ProtoChunk) chunk).setStatus(STATUS);
|
||||
#else
|
||||
((ProtoChunk) chunk).setPersistedStatus(STATUS);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
#if MC_VER < MC_1_18_2
|
||||
worldGenRegion.setOverrideCenter(chunk.getPos());
|
||||
environment.params.generator.applyBiomeDecoration(worldGenRegion, tParams.structFeat);
|
||||
#else
|
||||
if (worldGenRegion.hasChunk(chunkWrapper.getChunkPos().x, chunkWrapper.getChunkPos().z))
|
||||
{
|
||||
this.environment.params.generator.applyBiomeDecoration(worldGenRegion, chunk, tParams.structFeat.forWorldGenRegion(worldGenRegion));
|
||||
}
|
||||
else
|
||||
{
|
||||
LOGGER.warn("Unable to generate features for chunk at pos ["+chunkWrapper.getChunkPos()+"], world gen region doesn't contain the chunk.");
|
||||
}
|
||||
#endif
|
||||
|
||||
Heightmap.primeHeightmaps(chunk, STATUS.heightmapsAfter());
|
||||
BatchGenerationEnvironment.clearDistantGenerationMixinData();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.warn("Unexpected issue when generating features for chunk at pos ["+chunkWrapper.getChunkPos()+"], error: ["+e.getMessage()+"].", e);
|
||||
// FIXME: Features concurrent modification issue. Something about cocobeans might just
|
||||
// error out. For now just retry.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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.worldGeneration.step;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters;
|
||||
|
||||
import com.seibel.distanthorizons.core.util.objects.UncheckedInterruptedException;
|
||||
import net.minecraft.server.level.WorldGenRegion;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||
|
||||
#if MC_VER >= MC_1_18_2
|
||||
import net.minecraft.world.level.levelgen.blending.Blender;
|
||||
#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
|
||||
{
|
||||
private static final ChunkStatus STATUS = ChunkStatus.NOISE;
|
||||
|
||||
private final BatchGenerationEnvironment environment;
|
||||
|
||||
|
||||
|
||||
public StepNoise(BatchGenerationEnvironment batchGenerationEnvironment) { this.environment = batchGenerationEnvironment; }
|
||||
|
||||
|
||||
|
||||
public void generateGroup(
|
||||
ThreadedParameters tParams, WorldGenRegion worldGenRegion,
|
||||
List<ChunkWrapper> chunkWrappers)
|
||||
{
|
||||
|
||||
ArrayList<ChunkAccess> chunksToDo = new ArrayList<>();
|
||||
|
||||
for (ChunkWrapper chunkWrapper : chunkWrappers)
|
||||
{
|
||||
ChunkAccess chunk = chunkWrapper.getChunk();
|
||||
if (chunkWrapper.getStatus().isOrAfter(STATUS))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
#if MC_VER < MC_1_21
|
||||
((ProtoChunk) chunk).setStatus(STATUS);
|
||||
#else
|
||||
((ProtoChunk) chunk).setPersistedStatus(STATUS);
|
||||
#endif
|
||||
chunksToDo.add(chunk);
|
||||
}
|
||||
|
||||
for (ChunkAccess chunk : chunksToDo)
|
||||
{
|
||||
// System.out.println("StepNoise: "+chunk.getPos());
|
||||
#if MC_VER < MC_1_17_1
|
||||
this.environment.params.generator.fillFromNoise(worldGenRegion, tParams.structFeat, chunk);
|
||||
#elif MC_VER < MC_1_18_2
|
||||
chunk = this.environment.joinSync(this.environment.params.generator.fillFromNoise(Runnable::run,
|
||||
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
|
||||
#elif MC_VER < MC_1_19_2
|
||||
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
|
||||
chunk = this.environment.joinSync(this.environment.params.generator.fillFromNoise(Runnable::run, Blender.of(worldGenRegion), this.environment.params.randomState,
|
||||
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
|
||||
#else
|
||||
chunk = this.environment.joinSync(this.environment.params.generator.fillFromNoise(Blender.of(worldGenRegion), this.environment.params.randomState,
|
||||
tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk));
|
||||
#endif
|
||||
UncheckedInterruptedException.throwIfInterrupted();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* 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.worldGeneration.step;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters;
|
||||
|
||||
import net.minecraft.server.level.WorldGenRegion;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
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
|
||||
{
|
||||
private static final ChunkStatus STATUS = ChunkStatus.STRUCTURE_REFERENCES;
|
||||
|
||||
private final BatchGenerationEnvironment environment;
|
||||
|
||||
|
||||
|
||||
public StepStructureReference(BatchGenerationEnvironment batchGenerationEnvironment) { this.environment = batchGenerationEnvironment; }
|
||||
|
||||
|
||||
|
||||
public void generateGroup(
|
||||
ThreadedParameters tParams, WorldGenRegion worldGenRegion,
|
||||
List<ChunkWrapper> chunkWrappers)
|
||||
{
|
||||
|
||||
ArrayList<ChunkAccess> chunksToDo = new ArrayList<ChunkAccess>();
|
||||
|
||||
for (ChunkWrapper chunkWrapper : chunkWrappers)
|
||||
{
|
||||
ChunkAccess chunk = chunkWrapper.getChunk();
|
||||
if (!chunkWrapper.getStatus().isOrAfter(STATUS))
|
||||
{
|
||||
#if MC_VER < MC_1_21
|
||||
((ProtoChunk) chunk).setStatus(STATUS);
|
||||
#else
|
||||
((ProtoChunk) chunk).setPersistedStatus(STATUS);
|
||||
#endif
|
||||
chunksToDo.add(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
for (ChunkAccess chunk : chunksToDo)
|
||||
{
|
||||
// System.out.println("StepStructureReference: "+chunk.getPos());
|
||||
this.environment.params.generator.createReferences(worldGenRegion, tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+70
-34
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
* 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
|
||||
@@ -16,79 +16,111 @@
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.common.wrappers.worldGeneration.step;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration.step;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||
import com.seibel.lod.common.wrappers.worldGeneration.ThreadedParameters;
|
||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters;
|
||||
|
||||
import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import net.minecraft.server.level.WorldGenRegion;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||
import 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
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
private static final ChunkStatus STATUS = ChunkStatus.STRUCTURE_STARTS;
|
||||
private static final ReentrantLock STRUCTURE_PLACEMENT_LOCK = new ReentrantLock();
|
||||
|
||||
private final BatchGenerationEnvironment environment;
|
||||
|
||||
/**
|
||||
* @param batchGenerationEnvironment
|
||||
*/
|
||||
public StepStructureStart(BatchGenerationEnvironment batchGenerationEnvironment)
|
||||
{
|
||||
environment = batchGenerationEnvironment;
|
||||
}
|
||||
|
||||
public final ChunkStatus STATUS = ChunkStatus.STRUCTURE_STARTS;
|
||||
|
||||
public static class StructStartCorruptedException extends RuntimeException {
|
||||
|
||||
|
||||
public StepStructureStart(BatchGenerationEnvironment batchGenerationEnvironment) { this.environment = batchGenerationEnvironment; }
|
||||
|
||||
|
||||
|
||||
public static class StructStartCorruptedException extends RuntimeException
|
||||
{
|
||||
private static final long serialVersionUID = -8987434342051563358L;
|
||||
|
||||
public StructStartCorruptedException(ArrayIndexOutOfBoundsException e) {
|
||||
|
||||
public StructStartCorruptedException(ArrayIndexOutOfBoundsException e)
|
||||
{
|
||||
super("StructStartCorruptedException");
|
||||
super.initCause(e);
|
||||
fillInStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void generateGroup(ThreadedParameters tParams, WorldGenRegion worldGenRegion,
|
||||
List<ChunkAccess> chunks)
|
||||
|
||||
public void generateGroup(
|
||||
ThreadedParameters tParams, WorldGenRegion worldGenRegion,
|
||||
List<ChunkWrapper> chunkWrappers) throws InterruptedException
|
||||
{
|
||||
ArrayList<ChunkAccess> chunksToDo = new ArrayList<>();
|
||||
|
||||
for (ChunkAccess chunk : chunks)
|
||||
for (ChunkWrapper chunkWrapper : chunkWrappers)
|
||||
{
|
||||
if (!chunk.getStatus().isOrAfter(STATUS))
|
||||
ChunkAccess chunk = chunkWrapper.getChunk();
|
||||
if (!chunkWrapper.getStatus().isOrAfter(STATUS))
|
||||
{
|
||||
#if MC_VER < MC_1_21
|
||||
((ProtoChunk) chunk).setStatus(STATUS);
|
||||
#else
|
||||
((ProtoChunk) chunk).setPersistedStatus(STATUS);
|
||||
#endif
|
||||
chunksToDo.add(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
#if PRE_MC_1_19
|
||||
if (environment.params.worldGenSettings.generateFeatures()) {
|
||||
#elif POST_MC_1_19
|
||||
#if MC_VER < MC_1_19_2
|
||||
if (environment.params.worldGenSettings.generateFeatures())
|
||||
{
|
||||
#elif MC_VER < MC_1_19_4
|
||||
if (environment.params.worldGenSettings.generateStructures()) {
|
||||
#else
|
||||
if (environment.params.worldOptions.generateStructures())
|
||||
{
|
||||
#endif
|
||||
for (ChunkAccess chunk : chunksToDo)
|
||||
{
|
||||
// System.out.println("StepStructureStart: "+chunk.getPos());
|
||||
#if PRE_MC_1_19
|
||||
|
||||
// there are a few cases where the structure generator call may lock up (either due to teleporting or leaving the world).
|
||||
// hopefully allowing interrupts here will prevent that from happening.
|
||||
BatchGenerationEnvironment.throwIfThreadInterrupted();
|
||||
|
||||
// hopefully this shouldn't cause any performance issues (this step is generally quite quick so hopefully it should be fine)
|
||||
// and should prevent some concurrency issues
|
||||
STRUCTURE_PLACEMENT_LOCK.lock();
|
||||
|
||||
#if MC_VER < MC_1_19_2
|
||||
environment.params.generator.createStructures(environment.params.registry, tParams.structFeat, chunk, environment.params.structures,
|
||||
environment.params.worldSeed);
|
||||
#elif POST_MC_1_19
|
||||
#elif MC_VER < MC_1_19_4
|
||||
environment.params.generator.createStructures(environment.params.registry, environment.params.randomState, tParams.structFeat, chunk, environment.params.structures,
|
||||
environment.params.worldSeed);
|
||||
#else
|
||||
environment.params.generator.createStructures(environment.params.registry,
|
||||
environment.params.level.getChunkSource().getGeneratorState(),
|
||||
tParams.structFeat, chunk, environment.params.structures);
|
||||
#endif
|
||||
#if POST_MC_1_18_1
|
||||
|
||||
#if MC_VER >= MC_1_18_2
|
||||
try
|
||||
{
|
||||
tParams.structCheck.onStructureLoad(chunk.getPos(), chunk.getAllStarts());
|
||||
@@ -110,13 +142,17 @@ public final class StepStructureStart
|
||||
catch (ArrayIndexOutOfBoundsException secondEx)
|
||||
{
|
||||
// the structure logic failed again, log it and move on
|
||||
LOGGER.error("Unable to create structure starts for "+chunk.getPos()+". This is an error with MC's world generation. Ignoring and continuing generation. Error: "+secondEx.getMessage()); // don't log the full stack trace since it is long and will generally end up in MC's code
|
||||
LOGGER.error("Unable to create structure starts for " + chunk.getPos() + ". This is an error with MC's world generation. Ignoring and continuing generation. Error: " + secondEx.getMessage()); // don't log the full stack trace since it is long and will generally end up in MC's code
|
||||
|
||||
//throw new StepStructureStart.StructStartCorruptedException(secondEx);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
STRUCTURE_PLACEMENT_LOCK.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+46
-30
@@ -1,8 +1,8 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
* 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
|
||||
@@ -16,55 +16,71 @@
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.common.wrappers.worldGeneration.step;
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration.step;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||
import com.seibel.lod.common.wrappers.worldGeneration.ThreadedParameters;
|
||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||
import com.seibel.distanthorizons.common.wrappers.worldGeneration.ThreadedParameters;
|
||||
|
||||
import net.minecraft.server.level.WorldGenRegion;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||
import net.minecraft.world.level.chunk.ProtoChunk;
|
||||
|
||||
public final class StepSurface {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
#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
|
||||
{
|
||||
private static final ChunkStatus STATUS = ChunkStatus.SURFACE;
|
||||
|
||||
private final BatchGenerationEnvironment environment;
|
||||
|
||||
/**
|
||||
* @param batchGenerationEnvironment
|
||||
*/
|
||||
public StepSurface(BatchGenerationEnvironment batchGenerationEnvironment)
|
||||
|
||||
|
||||
|
||||
public StepSurface(BatchGenerationEnvironment batchGenerationEnvironment) { this.environment = batchGenerationEnvironment; }
|
||||
|
||||
|
||||
|
||||
public void generateGroup(
|
||||
ThreadedParameters tParams, WorldGenRegion worldGenRegion,
|
||||
List<ChunkWrapper> chunkWrappers)
|
||||
{
|
||||
environment = batchGenerationEnvironment;
|
||||
}
|
||||
|
||||
public final ChunkStatus STATUS = ChunkStatus.SURFACE;
|
||||
|
||||
public void generateGroup(ThreadedParameters tParams, WorldGenRegion worldGenRegion,
|
||||
List<ChunkAccess> chunks) {
|
||||
ArrayList<ChunkAccess> chunksToDo = new ArrayList<>();
|
||||
|
||||
for (ChunkAccess chunk : chunks) {
|
||||
if (chunk.getStatus().isOrAfter(STATUS)) continue;
|
||||
((ProtoChunk) chunk).setStatus(STATUS);
|
||||
chunksToDo.add(chunk);
|
||||
for (ChunkWrapper chunkWrapper : chunkWrappers)
|
||||
{
|
||||
ChunkAccess chunk = chunkWrapper.getChunk();
|
||||
if (!chunkWrapper.getStatus().isOrAfter(STATUS))
|
||||
{
|
||||
#if MC_VER < MC_1_21
|
||||
((ProtoChunk) chunk).setStatus(STATUS);
|
||||
#else
|
||||
((ProtoChunk) chunk).setPersistedStatus(STATUS);
|
||||
#endif
|
||||
|
||||
chunksToDo.add(chunk);
|
||||
}
|
||||
}
|
||||
|
||||
for (ChunkAccess chunk : chunksToDo) {
|
||||
for (ChunkAccess chunk : chunksToDo)
|
||||
{
|
||||
// System.out.println("StepSurface: "+chunk.getPos());
|
||||
#if PRE_MC_1_18_1
|
||||
#if MC_VER < MC_1_18_2
|
||||
environment.params.generator.buildSurfaceAndBedrock(worldGenRegion, chunk);
|
||||
#elif PRE_MC_1_19
|
||||
#elif MC_VER < MC_1_19_2
|
||||
environment.params.generator.buildSurface(worldGenRegion, tParams.structFeat.forWorldGenRegion(worldGenRegion), chunk);
|
||||
#else
|
||||
environment.params.generator.buildSurface(worldGenRegion, tParams.structFeat.forWorldGenRegion(worldGenRegion), environment.params.randomState, chunk);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.common;
|
||||
|
||||
import com.seibel.lod.common.forge.LodForgeMethodCaller;
|
||||
import com.seibel.lod.common.wrappers.DependencySetup;
|
||||
import com.seibel.lod.core.ModInfo;
|
||||
import com.seibel.lod.core.api.internal.SharedApi;
|
||||
import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.core.config.ConfigBase;
|
||||
|
||||
/**
|
||||
* This is the common main class
|
||||
* @author Ran
|
||||
*/
|
||||
public class LodCommonMain {
|
||||
public static boolean forge = false;
|
||||
public static LodForgeMethodCaller forgeMethodCaller;
|
||||
public static void startup(LodForgeMethodCaller caller) {
|
||||
if (caller != null) {
|
||||
LodCommonMain.forge = true;
|
||||
forgeMethodCaller = caller;
|
||||
}
|
||||
|
||||
DependencySetup.createSharedBindings();
|
||||
SharedApi.init();
|
||||
// if (!serverSided) {
|
||||
// new NetworkReceiver().register_Client();
|
||||
// } else {
|
||||
// new NetworkReceiver().register_Server();
|
||||
// }
|
||||
}
|
||||
|
||||
public static void initConfig() {
|
||||
ConfigBase.INSTANCE = new ConfigBase(ModInfo.ID, ModInfo.NAME, Config.class,1);
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.common.forge;
|
||||
|
||||
import com.seibel.lod.common.wrappers.minecraft.MinecraftClientWrapper;
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.core.Direction;
|
||||
#if POST_MC_1_19
|
||||
import net.minecraft.util.RandomSource;
|
||||
#endif
|
||||
import net.minecraft.world.level.ColorResolver;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
* used for calling methods that forge modified
|
||||
* (forge modifies vanilla methods for some reason)
|
||||
* @author Ran
|
||||
*/
|
||||
public interface LodForgeMethodCaller {
|
||||
#if PRE_MC_1_19
|
||||
List<BakedQuad> getQuads(MinecraftClientWrapper mc, Block block, BlockState blockState, Direction direction, Random random); // FIXME: For 1.19
|
||||
#else
|
||||
List<BakedQuad> getQuads(MinecraftClientWrapper mc, Block block, BlockState blockState, Direction direction, RandomSource random); // FIXME: For 1.19
|
||||
#endif
|
||||
|
||||
int colorResolverGetColor(ColorResolver resolver, Biome biome, double x, double z);
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.common.networking;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
|
||||
/**
|
||||
* This is packet handler for our mod
|
||||
* It basically handles the packets sent from the server & client
|
||||
*
|
||||
* @author Ran
|
||||
*/
|
||||
|
||||
// TODO: Server sided stuff here
|
||||
public class NetworkHandler {
|
||||
public static void receivePacketClient(Minecraft client, FriendlyByteBuf buf, Player player) {
|
||||
// This just exists here for testing purposes, it'll be removed in the future
|
||||
System.out.println("Received int " + buf.readInt());
|
||||
}
|
||||
|
||||
public static void receivePacketServer(FriendlyByteBuf buf, Player player) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.common.networking;
|
||||
|
||||
/*
|
||||
#if MC_1_16_5
|
||||
import me.shedaniel.architectury.networking.NetworkManager;
|
||||
#else
|
||||
import dev.architectury.networking.NetworkManager;
|
||||
#endif
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
*/
|
||||
|
||||
/**
|
||||
* @author Ran
|
||||
*/
|
||||
// Comment: What does the 'server' side mean? Dedicated server? Or does it include the internal server?
|
||||
// (I removed the hookup that calls the register method, since I'm not sure what it is doing yet)
|
||||
public class NetworkReceiver {
|
||||
/*
|
||||
public void register_Client() {
|
||||
NetworkManager.registerReceiver(NetworkManager.serverToClient(), Networking.RESOURCE_LOCATION, new ClientReceiver());
|
||||
}
|
||||
|
||||
public void register_Server() {
|
||||
NetworkManager.registerReceiver(NetworkManager.clientToServer(), Networking.RESOURCE_LOCATION, new ServerReceiver());
|
||||
}
|
||||
|
||||
static class ServerReceiver implements NetworkManager.NetworkReceiver {
|
||||
@Override
|
||||
public void receive(FriendlyByteBuf buf, NetworkManager.PacketContext context) {
|
||||
com.seibel.lod.common.networking.NetworkHandler.receivePacketServer(buf, context.getPlayer());
|
||||
}
|
||||
}
|
||||
|
||||
static class ClientReceiver implements NetworkManager.NetworkReceiver {
|
||||
@Override
|
||||
public void receive(FriendlyByteBuf buf, NetworkManager.PacketContext context) {
|
||||
com.seibel.lod.common.networking.NetworkHandler.receivePacketClient(Minecraft.getInstance(), buf, context.getPlayer());
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.common.networking;
|
||||
|
||||
import com.seibel.lod.core.ModInfo;
|
||||
//#if MC_1_16_5
|
||||
//import me.shedaniel.architectury.networking.NetworkManager;
|
||||
//#else
|
||||
//import dev.architectury.networking.NetworkManager;
|
||||
//#endif
|
||||
import io.netty.buffer.Unpooled;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.game.ClientboundCustomPayloadPacket;
|
||||
import net.minecraft.network.protocol.game.ServerboundCustomPayloadPacket;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* This class holds most of the networking code for the mod.
|
||||
* @author Ran
|
||||
*/
|
||||
public class Networking {
|
||||
public static final ResourceLocation RESOURCE_LOCATION = new ResourceLocation("lod", "data");
|
||||
|
||||
public static FriendlyByteBuf createNew() {
|
||||
// TODO: Probably replace the Unpooled.buffer()
|
||||
FriendlyByteBuf buf = new FriendlyByteBuf(Unpooled.buffer());
|
||||
buf.writeInt(ModInfo.PROTOCOL_VERSION);
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a packet to a player.
|
||||
*
|
||||
* @param player the player to send the packet to
|
||||
* @param buf the payload of the packet.
|
||||
*/
|
||||
public static void send(ServerPlayer player, FriendlyByteBuf buf) {
|
||||
// NetworkManager.sendToPlayer(player, RESOURCE_LOCATION, buf);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a packet to the connected server.
|
||||
*
|
||||
* @param buf the payload of the packet
|
||||
* @throws IllegalStateException if the client is not connected to a server
|
||||
*/
|
||||
public static void send(FriendlyByteBuf buf) throws IllegalStateException {
|
||||
// NetworkManager.sendToServer(RESOURCE_LOCATION, buf);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.common.wrappers;
|
||||
|
||||
import com.seibel.lod.common.wrappers.gui.LangWrapper;
|
||||
import com.seibel.lod.common.wrappers.minecraft.MinecraftDedicatedServerWrapper;
|
||||
import com.seibel.lod.core.wrapperInterfaces.config.ILangWrapper;
|
||||
import com.seibel.lod.common.wrappers.minecraft.MinecraftClientWrapper;
|
||||
import com.seibel.lod.common.wrappers.minecraft.MinecraftRenderWrapper;
|
||||
import com.seibel.lod.core.IReflectionHandler;
|
||||
import com.seibel.lod.core.ReflectionHandler;
|
||||
import com.seibel.lod.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.lod.core.wrapperInterfaces.IVersionConstants;
|
||||
import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory;
|
||||
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftRenderWrapper;
|
||||
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
|
||||
|
||||
/**
|
||||
* Binds all necessary dependencies, so we
|
||||
* can access them in Core. <br>
|
||||
* This needs to be called before any Core classes
|
||||
* are loaded.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @author Ran
|
||||
* @version 12-1-2021
|
||||
*/
|
||||
public class DependencySetup {
|
||||
public static void createSharedBindings()
|
||||
{
|
||||
SingletonInjector.INSTANCE.bind(ILangWrapper.class, LangWrapper.INSTANCE);
|
||||
SingletonInjector.INSTANCE.bind(IVersionConstants.class, VersionConstants.INSTANCE);
|
||||
SingletonInjector.INSTANCE.bind(IWrapperFactory.class, WrapperFactory.INSTANCE);
|
||||
DependencySetupDoneCheck.isDone = true;
|
||||
}
|
||||
|
||||
//@Environment(EnvType.SERVER)
|
||||
public static void createServerBindings() {
|
||||
SingletonInjector.INSTANCE.bind(IMinecraftSharedWrapper.class, MinecraftDedicatedServerWrapper.INSTANCE);
|
||||
}
|
||||
|
||||
//@Environment(EnvType.CLIENT)
|
||||
public static void createClientBindings() {
|
||||
SingletonInjector.INSTANCE.bind(IMinecraftClientWrapper.class, MinecraftClientWrapper.INSTANCE);
|
||||
SingletonInjector.INSTANCE.bind(IMinecraftSharedWrapper.class, MinecraftClientWrapper.INSTANCE);
|
||||
SingletonInjector.INSTANCE.bind(IMinecraftRenderWrapper.class, MinecraftRenderWrapper.INSTANCE);
|
||||
SingletonInjector.INSTANCE.bind(IReflectionHandler.class, ReflectionHandler.INSTANCE);
|
||||
}
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.common.wrappers;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.mojang.math.Matrix4f;
|
||||
import com.seibel.lod.core.enums.ELodDirection;
|
||||
import com.seibel.lod.core.pos.DhBlockPos;
|
||||
import com.seibel.lod.core.pos.DhChunkPos;
|
||||
import com.seibel.lod.core.util.math.Mat4f;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
|
||||
/**
|
||||
* This class converts to and from Minecraft objects (Ex: Matrix4f)
|
||||
* and objects we created (Ex: Mat4f).
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 11-20-2021
|
||||
*/
|
||||
public class McObjectConverter
|
||||
{
|
||||
/** 4x4 float matrix converter */
|
||||
public static Mat4f Convert(Matrix4f mcMatrix)
|
||||
{
|
||||
FloatBuffer buffer = FloatBuffer.allocate(16);
|
||||
mcMatrix.store(buffer);
|
||||
Mat4f matrix = new Mat4f(buffer);
|
||||
matrix.transpose();
|
||||
return matrix;
|
||||
}
|
||||
|
||||
|
||||
static final Direction[] directions;
|
||||
static final ELodDirection[] lodDirections;
|
||||
static {
|
||||
ELodDirection[] lodDirs = ELodDirection.values();
|
||||
directions = new Direction[lodDirs.length];
|
||||
lodDirections = new ELodDirection[lodDirs.length];
|
||||
for (ELodDirection lodDir : lodDirs)
|
||||
{
|
||||
Direction dir;
|
||||
switch (lodDir.name().toUpperCase())
|
||||
{
|
||||
case "DOWN":
|
||||
dir = Direction.DOWN;
|
||||
break;
|
||||
case "UP":
|
||||
dir = Direction.UP;
|
||||
break;
|
||||
case "NORTH":
|
||||
dir = Direction.NORTH;
|
||||
break;
|
||||
case "SOUTH":
|
||||
dir = Direction.SOUTH;
|
||||
break;
|
||||
case "WEST":
|
||||
dir = Direction.WEST;
|
||||
break;
|
||||
case "EAST":
|
||||
dir = Direction.EAST;
|
||||
break;
|
||||
default:
|
||||
dir = null;
|
||||
break;
|
||||
}
|
||||
|
||||
if (dir == null)
|
||||
{
|
||||
throw new IllegalArgumentException("Invalid direction on init mapping: " + lodDir);
|
||||
}
|
||||
directions[lodDir.ordinal()] = dir;
|
||||
lodDirections[dir.ordinal()] = lodDir;
|
||||
}
|
||||
}
|
||||
|
||||
public static BlockPos Convert(DhBlockPos wrappedPos) {
|
||||
return new BlockPos(wrappedPos.x, wrappedPos.y, wrappedPos.z);
|
||||
}
|
||||
public static ChunkPos Convert(DhChunkPos wrappedPos) {
|
||||
return new ChunkPos(wrappedPos.x, wrappedPos.z);
|
||||
}
|
||||
|
||||
public static Direction Convert(ELodDirection lodDirection)
|
||||
{
|
||||
return directions[lodDirection.ordinal()];
|
||||
}
|
||||
public static ELodDirection Convert(Direction direction)
|
||||
{
|
||||
return lodDirections[direction.ordinal()];
|
||||
}
|
||||
public static void DebugCheckAllPackers() {
|
||||
BiConsumer<Integer, Integer> func = (x, z) -> DhChunkPos._DebugCheckPacker(x,z,ChunkPos.asLong(x,z));
|
||||
func.accept(0,0);
|
||||
func.accept(12345,134);
|
||||
func.accept(-12345,-134);
|
||||
func.accept(-30000000/16,30000000/16);
|
||||
func.accept(30000000/16,-30000000/16);
|
||||
func.accept(30000000/16,30000000/16);
|
||||
func.accept(-30000000/16,-30000000/16);
|
||||
Consumer<BlockPos> func2 = (p) -> DhBlockPos._DebugCheckPacker(p.getX(),p.getY(),p.getZ(),p.asLong());
|
||||
func2.accept(new BlockPos(0,0,0));
|
||||
func2.accept(new BlockPos(12345,134,123));
|
||||
func2.accept(new BlockPos(-12345,-134,-80));
|
||||
func2.accept(new BlockPos(-30000000, 2047, 30000000));
|
||||
func2.accept(new BlockPos(30000000, -2048, -30000000));
|
||||
func2.accept(new BlockPos(30000000, 2047, 30000000));
|
||||
func2.accept(new BlockPos(-30000000, -2048, -30000000));
|
||||
}
|
||||
}
|
||||
@@ -1,148 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.common.wrappers;
|
||||
|
||||
import com.seibel.lod.api.interfaces.override.worldGenerator.IDhApiWorldGenerator;
|
||||
import com.seibel.lod.common.wrappers.block.BlockStateWrapper;
|
||||
import com.seibel.lod.common.wrappers.block.BiomeWrapper;
|
||||
import com.seibel.lod.common.wrappers.chunk.ChunkWrapper;
|
||||
import com.seibel.lod.core.level.IDhLevel;
|
||||
import com.seibel.lod.core.level.IDhServerLevel;
|
||||
import com.seibel.lod.core.wrapperInterfaces.IWrapperFactory;
|
||||
import com.seibel.lod.core.wrapperInterfaces.block.IBlockStateWrapper;
|
||||
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||
import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper;
|
||||
import com.seibel.lod.core.wrapperInterfaces.worldGeneration.AbstractBatchGenerationEnvironmentWrapper;
|
||||
import com.seibel.lod.common.wrappers.worldGeneration.BatchGenerationEnvironment;
|
||||
import net.minecraft.world.level.LevelReader;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* This handles creating abstract wrapper objects.
|
||||
* @author James Seibel
|
||||
* @version 2022-12-5
|
||||
*/
|
||||
public class WrapperFactory implements IWrapperFactory
|
||||
{
|
||||
public static final WrapperFactory INSTANCE = new WrapperFactory();
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public AbstractBatchGenerationEnvironmentWrapper createBatchGenerator(IDhLevel targetLevel)
|
||||
{
|
||||
if (targetLevel instanceof IDhServerLevel)
|
||||
{
|
||||
return new BatchGenerationEnvironment((IDhServerLevel) targetLevel);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalArgumentException("The target level must be a server-side level.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBiomeWrapper deserializeBiomeWrapper(String str) throws IOException { return BiomeWrapper.deserialize(str); }
|
||||
|
||||
@Override
|
||||
public IBlockStateWrapper deserializeBlockStateWrapper(String str) throws IOException { return BlockStateWrapper.deserialize(str); }
|
||||
|
||||
@Override
|
||||
public IBlockStateWrapper getAirBlockStateWrapper() { return BlockStateWrapper.AIR; }
|
||||
|
||||
|
||||
/**
|
||||
* Note: when this is updated for different MC versions, make sure you also update the documentation in
|
||||
* {@link IDhApiWorldGenerator#generateChunks} and the type list in {@link WrapperFactory#createChunkWrapperErrorMessage}. <br><br>
|
||||
*
|
||||
* For full method documentation please see: {@link IWrapperFactory#createChunkWrapper}
|
||||
* @see IWrapperFactory#createChunkWrapper
|
||||
*/
|
||||
public IChunkWrapper createChunkWrapper(Object[] objectArray) throws ClassCastException
|
||||
{
|
||||
if (objectArray.length == 1 && objectArray[0] instanceof IChunkWrapper) // alternate option if "instanceof" can't be compiled down to older JRE versions "IChunkWrapper.class.isInstance(objectArray[0])" Feel free to delete this comment if we've compiled the mod for 1.16 or earlier - James
|
||||
{
|
||||
try
|
||||
{
|
||||
// this path should only happen when called by Distant Horizons code
|
||||
// API implementors should never hit this path
|
||||
return (IChunkWrapper) objectArray[0];
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new ClassCastException(createChunkWrapperErrorMessage(objectArray));
|
||||
}
|
||||
}
|
||||
// correct number of parameters from the API
|
||||
else if (objectArray.length == 2)
|
||||
{
|
||||
// chunk
|
||||
if (!(objectArray[0] instanceof ChunkAccess))
|
||||
{
|
||||
throw new ClassCastException(createChunkWrapperErrorMessage(objectArray));
|
||||
}
|
||||
ChunkAccess chunk = (ChunkAccess) objectArray[0];
|
||||
|
||||
// light source
|
||||
if (!(objectArray[1] instanceof LevelReader))
|
||||
{
|
||||
throw new ClassCastException(createChunkWrapperErrorMessage(objectArray));
|
||||
}
|
||||
LevelReader lightSource = (LevelReader) objectArray[1];
|
||||
|
||||
|
||||
return new ChunkWrapper(chunk, lightSource, /*A DH wrapped level isn't necessary*/null);
|
||||
}
|
||||
// incorrect number of parameters from the API
|
||||
else
|
||||
{
|
||||
throw new ClassCastException(createChunkWrapperErrorMessage(objectArray));
|
||||
}
|
||||
}
|
||||
/** Note: when this is updated for different MC versions, make sure you also update the documentation in {@link IDhApiWorldGenerator#generateChunks}. */
|
||||
private static String createChunkWrapperErrorMessage(Object[] objectArray)
|
||||
{
|
||||
StringBuilder message = new StringBuilder(
|
||||
"Chunk wrapper creation failed. \n" +
|
||||
"Expected parameters: " +
|
||||
"[" + ChunkAccess.class.getName() + "], " +
|
||||
"[" + LevelReader.class.getName() + "]. \n");
|
||||
|
||||
if (objectArray.length != 0)
|
||||
{
|
||||
message.append("Given parameters: ");
|
||||
for (Object obj : objectArray)
|
||||
{
|
||||
message.append("[").append(obj.getClass().getName()).append("], ");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
message.append(" No parameters given.");
|
||||
}
|
||||
|
||||
return message.toString();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.common.wrappers;
|
||||
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
|
||||
/**
|
||||
* Stores any variables or code that
|
||||
* may be shared between wrapper objects.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 11-20-2021
|
||||
*/
|
||||
public class WrapperUtil {
|
||||
/** If we ever need to use a heightmap for any reason, use this one. */
|
||||
public static final Heightmap.Types DEFAULT_HEIGHTMAP = Heightmap.Types.WORLD_SURFACE_WG;
|
||||
}
|
||||
@@ -1,118 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.common.wrappers.block;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.function.Function;
|
||||
|
||||
import com.google.common.collect.ImmutableBiMap;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.mojang.serialization.JsonOps;
|
||||
import com.mojang.serialization.Lifecycle;
|
||||
import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.core.Holder;
|
||||
#if POST_MC_1_19
|
||||
import net.minecraft.data.worldgen.biome.EndBiomes;
|
||||
import net.minecraft.data.worldgen.biome.NetherBiomes;
|
||||
#endif
|
||||
import net.minecraft.resources.RegistryFixedCodec;
|
||||
import net.minecraft.resources.RegistryOps;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.biome.Biomes;
|
||||
|
||||
|
||||
/** This class wraps the minecraft BlockPos.Mutable (and BlockPos) class */
|
||||
public class BiomeWrapper implements IBiomeWrapper
|
||||
{
|
||||
#if PRE_MC_1_18_2
|
||||
public static final ConcurrentMap<Biome, BiomeWrapper> biomeWrapperMap = new ConcurrentHashMap<>();
|
||||
public final Biome biome;
|
||||
#else
|
||||
public static final ConcurrentMap<Holder<Biome>, BiomeWrapper> biomeWrapperMap = new ConcurrentHashMap<>();
|
||||
public final Holder<Biome> biome;
|
||||
#endif
|
||||
|
||||
static public IBiomeWrapper getBiomeWrapper(#if PRE_MC_1_18_2 Biome #else Holder<Biome> #endif biome)
|
||||
{
|
||||
return biomeWrapperMap.computeIfAbsent(biome, BiomeWrapper::new);
|
||||
}
|
||||
|
||||
private BiomeWrapper(#if PRE_MC_1_18_2 Biome #else Holder<Biome> #endif biome)
|
||||
{
|
||||
this.biome = biome;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
#if PRE_MC_1_18_2
|
||||
return biome.toString();
|
||||
#else
|
||||
return biome.unwrapKey().orElse(Biomes.THE_VOID).registry().toString();
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public String serialize() {
|
||||
//FIXME: Pass in a level obj
|
||||
String data = Biome.CODEC.encodeStart(RegistryOps.create(JsonOps.INSTANCE, Minecraft.getInstance().level.registryAccess()),
|
||||
biome).get().orThrow().toString();
|
||||
return data;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
BiomeWrapper that = (BiomeWrapper) o;
|
||||
return Objects.equals(biome, that.biome);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(biome);
|
||||
}
|
||||
|
||||
public static IBiomeWrapper deserialize(String str) throws IOException
|
||||
{
|
||||
try
|
||||
{
|
||||
#if PRE_MC_1_18_2 Biome #else
|
||||
Holder<Biome> #endif
|
||||
biome = Biome.CODEC.decode(RegistryOps.create(JsonOps.INSTANCE, Minecraft.getInstance().level.registryAccess()),
|
||||
JsonParser.parseString(str)).get().orThrow().getFirst();
|
||||
return getBiomeWrapper(biome);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new IOException("Failed to deserialize biome wrapper", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object getWrappedMcObject_UNSAFE() { return this.biome; }
|
||||
|
||||
}
|
||||
@@ -1,90 +0,0 @@
|
||||
package com.seibel.lod.common.wrappers.block;
|
||||
|
||||
import com.google.gson.JsonParser;
|
||||
import com.mojang.serialization.JsonOps;
|
||||
import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.lod.core.wrapperInterfaces.block.IBlockStateWrapper;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class BlockStateWrapper implements IBlockStateWrapper
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
public static final BlockStateWrapper AIR = new BlockStateWrapper(null);
|
||||
|
||||
public static ConcurrentHashMap<BlockState, BlockStateWrapper> cache = new ConcurrentHashMap<>();
|
||||
|
||||
public static BlockStateWrapper fromBlockState(BlockState blockState)
|
||||
{
|
||||
if (blockState == null || blockState.isAir())
|
||||
return AIR;
|
||||
|
||||
if (blockState.getFluidState().isEmpty())
|
||||
return cache.computeIfAbsent(blockState, BlockStateWrapper::new);
|
||||
else
|
||||
return cache.computeIfAbsent(blockState.getFluidState().createLegacyBlock(), BlockStateWrapper::new);
|
||||
}
|
||||
|
||||
public final BlockState blockState;
|
||||
BlockStateWrapper(BlockState blockState) {
|
||||
this.blockState = blockState;
|
||||
//LOGGER.info("Created BlockStateWrapper for {}", blockState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String serialize()
|
||||
{
|
||||
if (this.blockState == null)
|
||||
{
|
||||
return "AIR";
|
||||
}
|
||||
|
||||
return BlockState.CODEC.encodeStart(JsonOps.COMPRESSED, this.blockState).get().orThrow().toString();
|
||||
}
|
||||
|
||||
public static BlockStateWrapper deserialize(String str) throws IOException {
|
||||
if (str.equals("AIR")) {
|
||||
return AIR;
|
||||
}
|
||||
try {
|
||||
return new BlockStateWrapper(
|
||||
BlockState.CODEC.decode(JsonOps.COMPRESSED, JsonParser.parseString(str)).get().orThrow().getFirst()
|
||||
);
|
||||
} catch (Exception e) {
|
||||
throw new IOException("Failed to deserialize BlockStateWrapper", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
BlockStateWrapper that = (BlockStateWrapper) o;
|
||||
return Objects.equals(blockState, that.blockState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(blockState);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Object getWrappedMcObject_UNSAFE() { return this.blockState; }
|
||||
|
||||
@Override
|
||||
public boolean isAir() { return this.isAir(this.blockState); }
|
||||
public boolean isAir(BlockState blockState) { return blockState == null || blockState.isAir(); }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
-52
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.common.wrappers.block;
|
||||
|
||||
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
|
||||
/**
|
||||
* For wrapping/utilizing around TextureAtlasSprite
|
||||
* @author Ran
|
||||
*/
|
||||
public class TextureAtlasSpriteWrapper {
|
||||
|
||||
/**
|
||||
* This code is from Minecraft Forge
|
||||
* Which is licensed under the terms of GNU Lesser General Public License
|
||||
* as published by the Free Software Foundation version 2.1
|
||||
* of the License.
|
||||
*
|
||||
* The code has been modified to use TextureAtlasSprite
|
||||
*/
|
||||
public static int getPixelRGBA(TextureAtlasSprite sprite, int frameIndex, int x, int y) {
|
||||
#if PRE_MC_1_17_1
|
||||
return sprite.mainImage[0].getPixelRGBA(
|
||||
x + sprite.framesX[frameIndex] * sprite.getWidth(),
|
||||
y + sprite.framesY[frameIndex] * sprite.getHeight());
|
||||
#else
|
||||
if (sprite.animatedTexture != null) {
|
||||
x += sprite.animatedTexture.getFrameX(frameIndex) * sprite.width;
|
||||
y += sprite.animatedTexture.getFrameY(frameIndex) * sprite.height;
|
||||
}
|
||||
return sprite.mainImage[0].getPixelRGBA(x, y);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
-217
@@ -1,217 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.common.wrappers.block;
|
||||
|
||||
import com.seibel.lod.common.LodCommonMain;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.client.color.block.BlockTintCache;
|
||||
import net.minecraft.client.renderer.BiomeColors;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Cursor3D;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.level.*;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.lighting.LevelLightEngine;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class TintGetterOverrideFast implements BlockAndTintGetter {
|
||||
LevelReader parent;
|
||||
|
||||
public TintGetterOverrideFast(LevelReader parent) {
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
private Biome _getBiome(BlockPos pos) {
|
||||
#if POST_MC_1_18_2
|
||||
return parent.getBiome(pos).value();
|
||||
#else
|
||||
return parent.getBiome(pos);
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver) {
|
||||
if (LodCommonMain.forgeMethodCaller != null) {
|
||||
return LodCommonMain.forgeMethodCaller.colorResolverGetColor(colorResolver, _getBiome(blockPos),
|
||||
blockPos.getX(), blockPos.getZ());
|
||||
} else {
|
||||
return colorResolver.getColor(_getBiome(blockPos), blockPos.getX(), blockPos.getZ());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getShade(Direction direction, boolean bl) {
|
||||
return parent.getShade(direction, bl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LevelLightEngine getLightEngine() {
|
||||
return parent.getLightEngine();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBrightness(LightLayer lightLayer, BlockPos blockPos) {
|
||||
return parent.getBrightness(lightLayer, blockPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRawBrightness(BlockPos blockPos, int i) {
|
||||
return parent.getRawBrightness(blockPos, i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSeeSky(BlockPos blockPos) {
|
||||
return parent.canSeeSky(blockPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public BlockEntity getBlockEntity(BlockPos blockPos) {
|
||||
return parent.getBlockEntity(blockPos);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public BlockState getBlockState(BlockPos blockPos) {
|
||||
return parent.getBlockState(blockPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidState getFluidState(BlockPos blockPos) {
|
||||
return parent.getFluidState(blockPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightEmission(BlockPos blockPos) {
|
||||
return parent.getLightEmission(blockPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxLightLevel() {
|
||||
return parent.getMaxLightLevel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<BlockState> getBlockStates(AABB aABB) {
|
||||
return parent.getBlockStates(aABB);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockHitResult clip(ClipContext clipContext) {
|
||||
return parent.clip(clipContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public BlockHitResult clipWithInteractionOverride(Vec3 vec3, Vec3 vec32, BlockPos blockPos, VoxelShape voxelShape, BlockState blockState) {
|
||||
return parent.clipWithInteractionOverride(vec3, vec32, blockPos, voxelShape, blockState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getBlockFloorHeight(VoxelShape voxelShape, Supplier<VoxelShape> supplier) {
|
||||
return parent.getBlockFloorHeight(voxelShape, supplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getBlockFloorHeight(BlockPos blockPos) {
|
||||
return parent.getBlockFloorHeight(blockPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxBuildHeight() {
|
||||
return parent.getMaxBuildHeight();
|
||||
}
|
||||
|
||||
#if POST_MC_1_17_1
|
||||
@Override
|
||||
public <T extends BlockEntity> Optional<T> getBlockEntity(BlockPos blockPos, BlockEntityType<T> blockEntityType) {
|
||||
return parent.getBlockEntity(blockPos, blockEntityType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockHitResult isBlockInLine(ClipBlockStateContext clipBlockStateContext) {
|
||||
return parent.isBlockInLine(clipBlockStateContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return parent.getHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinBuildHeight() {
|
||||
return parent.getMinBuildHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSectionsCount() {
|
||||
return parent.getSectionsCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinSection() {
|
||||
return parent.getMinSection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxSection() {
|
||||
return parent.getMaxSection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOutsideBuildHeight(BlockPos blockPos) {
|
||||
return parent.isOutsideBuildHeight(blockPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOutsideBuildHeight(int i) {
|
||||
return parent.isOutsideBuildHeight(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSectionIndex(int i) {
|
||||
return parent.getSectionIndex(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSectionIndexFromSectionY(int i) {
|
||||
return parent.getSectionIndexFromSectionY(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSectionYFromSectionIndex(int i) {
|
||||
return parent.getSectionYFromSectionIndex(i);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
-241
@@ -1,241 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.common.wrappers.block;
|
||||
|
||||
import com.seibel.lod.common.LodCommonMain;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectArrayMap;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.client.color.block.BlockTintCache;
|
||||
import net.minecraft.client.renderer.BiomeColors;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Cursor3D;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.level.*;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.lighting.LevelLightEngine;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class TintGetterOverrideSmooth implements BlockAndTintGetter {
|
||||
LevelReader parent;
|
||||
public int smoothingRange;
|
||||
|
||||
public TintGetterOverrideSmooth(LevelReader parent, int smoothingRange) {
|
||||
this.parent = parent;
|
||||
this.smoothingRange = smoothingRange;
|
||||
}
|
||||
|
||||
private Biome _getBiome(BlockPos pos) {
|
||||
#if POST_MC_1_18_2
|
||||
return parent.getBiome(pos).value();
|
||||
#else
|
||||
return parent.getBiome(pos);
|
||||
#endif
|
||||
}
|
||||
|
||||
public int calculateBlockTint(BlockPos blockPos, ColorResolver colorResolver)
|
||||
{
|
||||
int i = smoothingRange;
|
||||
if (i == 0)
|
||||
return colorResolver.getColor(_getBiome(blockPos), blockPos.getX(), blockPos.getZ());
|
||||
int j = (i * 2 + 1) * (i * 2 + 1);
|
||||
int k = 0;
|
||||
int l = 0;
|
||||
int m = 0;
|
||||
Cursor3D cursor3D = new Cursor3D(blockPos.getX() - i, blockPos.getY(), blockPos.getZ() - i, blockPos.getX() + i, blockPos.getY(), blockPos.getZ() + i);
|
||||
BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
|
||||
while (cursor3D.advance())
|
||||
{
|
||||
mutableBlockPos.set(cursor3D.nextX(), cursor3D.nextY(), cursor3D.nextZ());
|
||||
int n;
|
||||
if (LodCommonMain.forgeMethodCaller != null) {
|
||||
n = LodCommonMain.forgeMethodCaller.colorResolverGetColor(colorResolver, _getBiome(mutableBlockPos),
|
||||
mutableBlockPos.getX(), mutableBlockPos.getZ());
|
||||
} else {
|
||||
n = colorResolver.getColor(_getBiome(mutableBlockPos), mutableBlockPos.getX(), mutableBlockPos.getZ());
|
||||
}
|
||||
|
||||
k += (n & 0xFF0000) >> 16;
|
||||
l += (n & 0xFF00) >> 8;
|
||||
m += n & 0xFF;
|
||||
}
|
||||
return (k / j & 0xFF) << 16 | (l / j & 0xFF) << 8 | m / j & 0xFF;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver) {
|
||||
return calculateBlockTint(blockPos, colorResolver);
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getShade(Direction direction, boolean bl) {
|
||||
return parent.getShade(direction, bl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LevelLightEngine getLightEngine() {
|
||||
return parent.getLightEngine();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBrightness(LightLayer lightLayer, BlockPos blockPos) {
|
||||
return parent.getBrightness(lightLayer, blockPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRawBrightness(BlockPos blockPos, int i) {
|
||||
return parent.getRawBrightness(blockPos, i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canSeeSky(BlockPos blockPos) {
|
||||
return parent.canSeeSky(blockPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public BlockEntity getBlockEntity(BlockPos blockPos) {
|
||||
return parent.getBlockEntity(blockPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlockState(BlockPos blockPos) {
|
||||
return parent.getBlockState(blockPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FluidState getFluidState(BlockPos blockPos) {
|
||||
return parent.getFluidState(blockPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightEmission(BlockPos blockPos) {
|
||||
return parent.getLightEmission(blockPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxLightLevel() {
|
||||
return parent.getMaxLightLevel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Stream<BlockState> getBlockStates(AABB aABB) {
|
||||
return parent.getBlockStates(aABB);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockHitResult clip(ClipContext clipContext) {
|
||||
return parent.clip(clipContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public BlockHitResult clipWithInteractionOverride(Vec3 vec3, Vec3 vec32, BlockPos blockPos, VoxelShape voxelShape, BlockState blockState) {
|
||||
return parent.clipWithInteractionOverride(vec3, vec32, blockPos, voxelShape, blockState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getBlockFloorHeight(VoxelShape voxelShape, Supplier<VoxelShape> supplier) {
|
||||
return parent.getBlockFloorHeight(voxelShape, supplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getBlockFloorHeight(BlockPos blockPos) {
|
||||
return parent.getBlockFloorHeight(blockPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxBuildHeight() {
|
||||
return parent.getMaxBuildHeight();
|
||||
}
|
||||
|
||||
#if POST_MC_1_17_1
|
||||
@Override
|
||||
public <T extends BlockEntity> Optional<T> getBlockEntity(BlockPos blockPos, BlockEntityType<T> blockEntityType) {
|
||||
return parent.getBlockEntity(blockPos, blockEntityType);
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockHitResult isBlockInLine(ClipBlockStateContext clipBlockStateContext) {
|
||||
return parent.isBlockInLine(clipBlockStateContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return parent.getHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinBuildHeight() {
|
||||
return parent.getMinBuildHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSectionsCount() {
|
||||
return parent.getSectionsCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinSection() {
|
||||
return parent.getMinSection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxSection() {
|
||||
return parent.getMaxSection();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOutsideBuildHeight(BlockPos blockPos) {
|
||||
return parent.isOutsideBuildHeight(blockPos);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOutsideBuildHeight(int i) {
|
||||
return parent.isOutsideBuildHeight(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSectionIndex(int i) {
|
||||
return parent.getSectionIndex(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSectionIndexFromSectionY(int i) {
|
||||
return parent.getSectionIndexFromSectionY(i);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSectionYFromSectionIndex(int i) {
|
||||
return parent.getSectionYFromSectionIndex(i);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
-91
@@ -1,91 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.common.wrappers.block;
|
||||
|
||||
import com.seibel.lod.common.LodCommonMain;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.world.level.*;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.entity.BlockEntityType;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.lighting.LevelLightEngine;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class TintWithoutLevelOverrider implements BlockAndTintGetter {
|
||||
final BiomeWrapper biome;
|
||||
|
||||
public TintWithoutLevelOverrider(BiomeWrapper biome) {
|
||||
this.biome = biome;
|
||||
}
|
||||
@Override
|
||||
public int getBlockTint(BlockPos blockPos, ColorResolver colorResolver) {
|
||||
return colorResolver.getColor(_unwrap(biome.biome), blockPos.getX(), blockPos.getZ());
|
||||
}
|
||||
private Biome _unwrap(#if POST_MC_1_18_2 Holder<Biome> #else Biome #endif biome) {
|
||||
#if POST_MC_1_18_2
|
||||
return biome.value();
|
||||
#else
|
||||
return biome;
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getShade(Direction direction, boolean shade) {
|
||||
throw new UnsupportedOperationException("ERROR: getShade() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
||||
}
|
||||
@Override
|
||||
public LevelLightEngine getLightEngine() {
|
||||
throw new UnsupportedOperationException("ERROR: getLightEngine() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
||||
}
|
||||
@Nullable
|
||||
@Override
|
||||
public BlockEntity getBlockEntity(BlockPos pos) {
|
||||
throw new UnsupportedOperationException("ERROR: getBlockEntity() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
||||
}
|
||||
|
||||
@Override
|
||||
public BlockState getBlockState(BlockPos pos) {
|
||||
throw new UnsupportedOperationException("ERROR: getBlockState() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
||||
}
|
||||
@Override
|
||||
public FluidState getFluidState(BlockPos pos) {
|
||||
throw new UnsupportedOperationException("ERROR: getFluidState() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
||||
}
|
||||
@Override
|
||||
public int getHeight() {
|
||||
throw new UnsupportedOperationException("ERROR: getHeight() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
||||
}
|
||||
@Override
|
||||
public int getMinBuildHeight() {
|
||||
throw new UnsupportedOperationException("ERROR: getMinBuildHeight() called on TintWithoutLevelOverrider. Object is for tinting only.");
|
||||
}
|
||||
}
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
package com.seibel.lod.common.wrappers.block.cache;
|
||||
|
||||
import com.seibel.lod.common.wrappers.block.BiomeWrapper;
|
||||
import com.seibel.lod.common.wrappers.world.ClientLevelWrapper;
|
||||
import com.seibel.lod.core.pos.DhBlockPos;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class ClientBlockDetailMap {
|
||||
private final ConcurrentHashMap<BlockState, ClientBlockStateCache> blockCache = new ConcurrentHashMap<>();
|
||||
//private final ConcurrentHashMap<#if PRE_MC_1_18_2 Biome #else Holder<Biome> #endif, Biome> biomeMap = new ConcurrentHashMap<>();
|
||||
private final ClientLevelWrapper level;
|
||||
public ClientBlockDetailMap(ClientLevelWrapper level) { this.level = level; }
|
||||
|
||||
public ClientBlockStateCache getBlockStateData(BlockState state, DhBlockPos pos) { //TODO: Allow a per pos unique setting
|
||||
return blockCache.computeIfAbsent(state, (s) -> new ClientBlockStateCache(s, level, new DhBlockPos(0,0,0)));
|
||||
}
|
||||
|
||||
public void clear() { blockCache.clear(); }
|
||||
|
||||
public int getColor(BlockState state, BiomeWrapper biome, DhBlockPos pos) {
|
||||
return getBlockStateData(state, pos).getAndResolveFaceColor(biome);
|
||||
}
|
||||
}
|
||||
-186
@@ -1,186 +0,0 @@
|
||||
package com.seibel.lod.common.wrappers.block.cache;
|
||||
|
||||
import com.seibel.lod.common.wrappers.McObjectConverter;
|
||||
import com.seibel.lod.common.wrappers.block.*;
|
||||
import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.lod.core.pos.DhBlockPos;
|
||||
import com.seibel.lod.core.util.ColorUtil;
|
||||
import com.seibel.lod.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.level.LevelReader;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.FlowerBlock;
|
||||
import net.minecraft.world.level.block.LeavesBlock;
|
||||
import net.minecraft.world.level.block.RotatedPillarBlock;
|
||||
#if POST_MC_1_19
|
||||
import net.minecraft.util.RandomSource;
|
||||
#endif
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Random;
|
||||
|
||||
/**
|
||||
*
|
||||
* @version 2022-9-16
|
||||
*/
|
||||
public class ClientBlockStateCache
|
||||
{
|
||||
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
|
||||
#if PRE_MC_1_19
|
||||
public static final Random random = new Random(0);
|
||||
#else
|
||||
public static final RandomSource random = RandomSource.create();
|
||||
#endif
|
||||
|
||||
public final BlockState state;
|
||||
public final LevelReader level;
|
||||
public final BlockPos pos;
|
||||
public ClientBlockStateCache(BlockState blockState, IClientLevelWrapper samplingLevel, DhBlockPos samplingPos) {
|
||||
state = blockState;
|
||||
level = (LevelReader) samplingLevel.getWrappedMcObject_UNSAFE();
|
||||
pos = McObjectConverter.Convert(samplingPos);
|
||||
resolveColors();
|
||||
//LOGGER.info("ClientBlocKCache created for {}", blockState);
|
||||
}
|
||||
|
||||
boolean isColorResolved = false;
|
||||
int baseColor = 0; //TODO: Impl per-face color
|
||||
boolean needShade = true;
|
||||
boolean needPostTinting = false;
|
||||
int tintIndex = 0;
|
||||
|
||||
|
||||
public static final int FLOWER_COLOR_SCALE = 5;
|
||||
|
||||
enum ColorMode {
|
||||
Default,
|
||||
Flower,
|
||||
Leaves;
|
||||
static ColorMode getColorMode(Block b) {
|
||||
if (b instanceof LeavesBlock) return Leaves;
|
||||
if (b instanceof FlowerBlock) return Flower;
|
||||
return Default;
|
||||
}
|
||||
}
|
||||
//TODO: Perhaps make this not just use the first frame?
|
||||
private static int calculateColorFromTexture(TextureAtlasSprite texture, ColorMode colorMode) {
|
||||
int count = 0;
|
||||
double alpha = 0;
|
||||
double red = 0;
|
||||
double green = 0;
|
||||
double blue = 0;
|
||||
int tempColor;
|
||||
{
|
||||
// textures normally use u and v instead of x and y
|
||||
for (int u = 0; u < texture.getWidth(); u++)
|
||||
{
|
||||
for (int v = 0; v < texture.getHeight(); v++)
|
||||
{
|
||||
//note: Minecraft color format is: 0xAA BB GG RR
|
||||
//________ DH mod color format is: 0xAA RR GG BB
|
||||
//OpenGL RGBA format native order: 0xRR GG BB AA
|
||||
//_ OpenGL RGBA format Java Order: 0xAA BB GG RR
|
||||
tempColor = TextureAtlasSpriteWrapper.getPixelRGBA(texture, 0, u, v);
|
||||
|
||||
double r = ((tempColor & 0x000000FF) )/255.;
|
||||
double g = ((tempColor & 0x0000FF00) >>> 8)/255.;
|
||||
double b = ((tempColor & 0x00FF0000) >>> 16)/255.;
|
||||
double a = ((tempColor & 0xFF000000) >>> 24)/255.;
|
||||
int scale = 1;
|
||||
|
||||
if (colorMode == ColorMode.Leaves) {
|
||||
r *= a;
|
||||
g *= a;
|
||||
b *= a;
|
||||
a = 1.;
|
||||
} else if (a==0.) {
|
||||
continue;
|
||||
} else if (colorMode == ColorMode.Flower && (g+0.1<b || g+0.1<r)) {
|
||||
scale = FLOWER_COLOR_SCALE;
|
||||
}
|
||||
|
||||
count += scale;
|
||||
alpha += a*a*scale;
|
||||
red += r*r*scale;
|
||||
green += g*g*scale;
|
||||
blue += b*b*scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
// this block is entirely transparent
|
||||
tempColor = ColorUtil.rgbToInt(0,255,255,255);
|
||||
else
|
||||
{
|
||||
// determine the average color
|
||||
tempColor = ColorUtil.rgbToInt(
|
||||
(int) (Math.sqrt(alpha/count)*255.),
|
||||
(int) (Math.sqrt(red / count)*255.),
|
||||
(int) (Math.sqrt(green / count)*255.),
|
||||
(int) (Math.sqrt(blue / count)*255.));
|
||||
}
|
||||
return tempColor;
|
||||
}
|
||||
private static final Direction[] DIRECTION_ORDER = {Direction.UP, Direction.NORTH, Direction.EAST, Direction.WEST, Direction.SOUTH, Direction.DOWN};
|
||||
|
||||
private void resolveColors() {
|
||||
if (isColorResolved) return;
|
||||
if (state.getFluidState().isEmpty()) {
|
||||
List<BakedQuad> quads = null;
|
||||
for (Direction direction : DIRECTION_ORDER)
|
||||
{
|
||||
quads = Minecraft.getInstance().getModelManager().getBlockModelShaper().
|
||||
getBlockModel(state).getQuads(state, direction, random);
|
||||
if (quads != null && !quads.isEmpty() &&
|
||||
!(state.getBlock() instanceof RotatedPillarBlock && direction == Direction.UP))
|
||||
break;
|
||||
};
|
||||
if (quads == null || quads.isEmpty()) {
|
||||
quads = Minecraft.getInstance().getModelManager().getBlockModelShaper().
|
||||
getBlockModel(state).getQuads(state, null, random);
|
||||
}
|
||||
if (quads != null && !quads.isEmpty()) {
|
||||
needPostTinting = quads.get(0).isTinted();
|
||||
needShade = quads.get(0).isShade();
|
||||
tintIndex = quads.get(0).getTintIndex();
|
||||
baseColor = calculateColorFromTexture(
|
||||
#if PRE_MC_1_17_1 quads.get(0).sprite,
|
||||
#else quads.get(0).getSprite(), #endif
|
||||
ColorMode.getColorMode(state.getBlock()));
|
||||
} else { // Backup method.
|
||||
needPostTinting = false;
|
||||
needShade = false;
|
||||
tintIndex = 0;
|
||||
baseColor = calculateColorFromTexture(Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(state),
|
||||
ColorMode.getColorMode(state.getBlock()));
|
||||
}
|
||||
} else { // Liquid Block
|
||||
needPostTinting = true;
|
||||
needShade = false;
|
||||
tintIndex = 0;
|
||||
baseColor = calculateColorFromTexture(Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(state),
|
||||
ColorMode.getColorMode(state.getBlock()));
|
||||
}
|
||||
isColorResolved = true;
|
||||
}
|
||||
|
||||
public int getAndResolveFaceColor(BiomeWrapper biome)
|
||||
{
|
||||
// FIXME: impl per-face colors
|
||||
if (!needPostTinting) return baseColor;
|
||||
int tintColor = Minecraft.getInstance().getBlockColors()
|
||||
.getColor(state, new TintWithoutLevelOverrider(biome), pos, tintIndex);
|
||||
if (tintColor == -1) return baseColor;
|
||||
return ColorUtil.multiplyARGBwithRGB(baseColor, tintColor);
|
||||
}
|
||||
|
||||
}
|
||||
-77
@@ -1,77 +0,0 @@
|
||||
package com.seibel.lod.common.wrappers.block.cache;
|
||||
|
||||
import com.seibel.lod.common.wrappers.McObjectConverter;
|
||||
import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.lod.core.pos.DhBlockPos;
|
||||
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.level.LevelReader;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.shapes.VoxelShape;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
*
|
||||
* @version 2022-9-16
|
||||
*/
|
||||
public class ServerBlockStateCache
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
|
||||
public final BlockState state;
|
||||
public final LevelReader level;
|
||||
public final BlockPos pos;
|
||||
|
||||
public ServerBlockStateCache(BlockState blockState, ILevelWrapper samplingLevel, DhBlockPos samplingPos) {
|
||||
state = blockState;
|
||||
level = (LevelReader) samplingLevel.getWrappedMcObject_UNSAFE();
|
||||
pos = McObjectConverter.Convert(samplingPos);
|
||||
resolveShapes();
|
||||
//LOGGER.info("ServerBlockState created for {}", blockState);
|
||||
}
|
||||
|
||||
boolean noCollision = false;
|
||||
boolean[] occludeFaces = null;
|
||||
boolean[] fullFaces = null;
|
||||
boolean isShapeResolved = false;
|
||||
public void resolveShapes() {
|
||||
if (isShapeResolved) return;
|
||||
if (state.getFluidState().isEmpty()) {
|
||||
noCollision = state.getCollisionShape(level, pos).isEmpty();
|
||||
occludeFaces = new boolean[6];
|
||||
if (state.canOcclude()) {
|
||||
for (Direction dir : Direction.values()) {
|
||||
// Note: isEmpty() isn't quite correct... best would be a isFull() or something...
|
||||
occludeFaces[McObjectConverter.Convert(dir).ordinal()]
|
||||
= !state.getFaceOcclusionShape(level, pos, dir).isEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
VoxelShape voxelShape = state.getShape(level, pos);
|
||||
fullFaces = new boolean[6];
|
||||
if (!voxelShape.isEmpty()) {
|
||||
for (Direction dir : Direction.values()) {
|
||||
VoxelShape faceShape = voxelShape.getFaceShape(dir);
|
||||
AABB aabb = faceShape.bounds();
|
||||
boolean xFull = aabb.minX <= 0.01 && aabb.maxX >= 0.99;
|
||||
boolean yFull = aabb.minY <= 0.01 && aabb.maxY >= 0.99;
|
||||
boolean zFull = aabb.minZ <= 0.01 && aabb.maxZ >= 0.99;
|
||||
fullFaces[McObjectConverter.Convert(dir).ordinal()] =
|
||||
(xFull || dir.getAxis().equals(Direction.Axis.X))
|
||||
&& (yFull || dir.getAxis().equals(Direction.Axis.Y))
|
||||
&& (zFull || dir.getAxis().equals(Direction.Axis.Z));
|
||||
}
|
||||
}
|
||||
} else { // Liquid Block. Treat as full block
|
||||
occludeFaces = new boolean[6];
|
||||
Arrays.fill(occludeFaces, true);
|
||||
fullFaces = new boolean[6];
|
||||
Arrays.fill(fullFaces, true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,217 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.common.wrappers.chunk;
|
||||
|
||||
import com.seibel.lod.common.wrappers.block.BlockStateWrapper;
|
||||
import com.seibel.lod.core.pos.DhChunkPos;
|
||||
import com.seibel.lod.core.wrapperInterfaces.block.IBlockStateWrapper;
|
||||
import com.seibel.lod.core.wrapperInterfaces.chunk.IChunkWrapper;
|
||||
import com.seibel.lod.core.wrapperInterfaces.world.IBiomeWrapper;
|
||||
|
||||
import com.seibel.lod.common.wrappers.WrapperUtil;
|
||||
import com.seibel.lod.common.wrappers.block.BiomeWrapper;
|
||||
import com.seibel.lod.common.wrappers.worldGeneration.mimicObject.LightedWorldGenRegion;
|
||||
|
||||
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import net.minecraft.core.BlockPos;
|
||||
#if POST_MC_1_17_1
|
||||
import net.minecraft.core.QuartPos;
|
||||
#endif
|
||||
import net.minecraft.world.level.LevelReader;
|
||||
import net.minecraft.world.level.LightLayer;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||
import net.minecraft.world.level.chunk.LevelChunk;
|
||||
import net.minecraft.world.level.levelgen.Heightmap;
|
||||
|
||||
// Which nullable should be used???
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
//import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 3-5-2022
|
||||
*/
|
||||
public class ChunkWrapper implements IChunkWrapper
|
||||
{
|
||||
private final ChunkAccess chunk;
|
||||
private final DhChunkPos chunkPos;
|
||||
private final LevelReader lightSource;
|
||||
private final ILevelWrapper wrappedLevel;
|
||||
|
||||
|
||||
public ChunkWrapper(ChunkAccess chunk, LevelReader lightSource, @Nullable ILevelWrapper wrappedLevel)
|
||||
{
|
||||
this.chunk = chunk;
|
||||
this.lightSource = lightSource;
|
||||
this.wrappedLevel = wrappedLevel;
|
||||
chunkPos = new DhChunkPos(chunk.getPos().x, chunk.getPos().z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight(){
|
||||
#if PRE_MC_1_17_1
|
||||
return 255;
|
||||
#else
|
||||
return chunk.getHeight();
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinBuildHeight()
|
||||
{
|
||||
#if PRE_MC_1_17_1
|
||||
return 0;
|
||||
#else
|
||||
return chunk.getMinBuildHeight();
|
||||
#endif
|
||||
}
|
||||
@Override
|
||||
public int getMaxBuildHeight()
|
||||
{
|
||||
return chunk.getMaxBuildHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeightMapValue(int xRel, int zRel)
|
||||
{
|
||||
return chunk.getOrCreateHeightmapUnprimed(WrapperUtil.DEFAULT_HEIGHTMAP).getFirstAvailable(xRel, zRel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBiomeWrapper getBiome(int x, int y, int z)
|
||||
{
|
||||
//if (wrappedLevel != null) return wrappedLevel.getBiome(new DhBlockPos(x + getMinX(), y, z + getMinZ()));
|
||||
|
||||
#if PRE_MC_1_17_1
|
||||
return BiomeWrapper.getBiomeWrapper(chunk.getBiomes().getNoiseBiome(
|
||||
x >> 2, y >> 2, z >> 2));
|
||||
#elif PRE_MC_1_18_1
|
||||
return BiomeWrapper.getBiomeWrapper(chunk.getBiomes().getNoiseBiome(
|
||||
QuartPos.fromBlock(x), QuartPos.fromBlock(y), QuartPos.fromBlock(z)));
|
||||
#elif PRE_MC_1_18_2
|
||||
return BiomeWrapper.getBiomeWrapper(chunk.getNoiseBiome(
|
||||
QuartPos.fromBlock(x), QuartPos.fromBlock(y), QuartPos.fromBlock(z)));
|
||||
#else //Now returns a Holder<Biome> instead of Biome
|
||||
return BiomeWrapper.getBiomeWrapper(chunk.getNoiseBiome(
|
||||
QuartPos.fromBlock(x), QuartPos.fromBlock(y), QuartPos.fromBlock(z)));
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public DhChunkPos getChunkPos() {
|
||||
return chunkPos;
|
||||
}
|
||||
|
||||
public ChunkAccess getChunk() {
|
||||
return chunk;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxY(int x, int z) {
|
||||
return chunk.getHeight(Heightmap.Types.WORLD_SURFACE, Math.floorMod(x, 16), Math.floorMod(z, 16));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxX(){
|
||||
return chunk.getPos().getMaxBlockX();
|
||||
}
|
||||
@Override
|
||||
public int getMaxZ(){
|
||||
return chunk.getPos().getMaxBlockZ();
|
||||
}
|
||||
@Override
|
||||
public int getMinX(){
|
||||
return chunk.getPos().getMinBlockX();
|
||||
}
|
||||
@Override
|
||||
public int getMinZ() {
|
||||
return chunk.getPos().getMinBlockZ();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLongChunkPos() {
|
||||
return chunk.getPos().toLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLightCorrect(){
|
||||
#if PRE_MC_1_18_1
|
||||
return true;
|
||||
#else
|
||||
if (chunk instanceof LevelChunk)
|
||||
{
|
||||
// called when connected to a server (and sometimes when in a singleplayer world)
|
||||
return ((LevelChunk) chunk).isClientLightReady() || chunk.isLightCorrect();
|
||||
}
|
||||
else
|
||||
{
|
||||
// called when in a single player world
|
||||
return chunk.isLightCorrect();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBlockLight(int x, int y, int z) {
|
||||
if (lightSource == null) return -1;
|
||||
return lightSource.getBrightness(LightLayer.BLOCK, new BlockPos(x + getMinX(),y,z + getMinZ()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSkyLight(int x, int y, int z) {
|
||||
if (lightSource == null) return -1;
|
||||
return lightSource.getBrightness(LightLayer.SKY, new BlockPos(x + getMinX(),y,z + getMinZ()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean doesNearbyChunksExist() {
|
||||
if (lightSource instanceof LightedWorldGenRegion) return true;
|
||||
for (int dx = -1; dx <= 1; dx++) {
|
||||
for (int dz = -1; dz <= 1; dz++) {
|
||||
if (dx==0 && dz==0) continue;
|
||||
if (lightSource.getChunk(dx+chunk.getPos().x, dz+chunk.getPos().z, ChunkStatus.BIOMES, false) == null) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public LevelReader getColorResolver()
|
||||
{
|
||||
return lightSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return chunk.getClass().getSimpleName() + chunk.getPos();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockStateWrapper getBlockState(int x, int y, int z) {
|
||||
//if (wrappedLevel != null) return wrappedLevel.getBlockState(new DhBlockPos(x + getMinX(), y, z + getMinZ()));
|
||||
return BlockStateWrapper.fromBlockState(chunk.getBlockState(new BlockPos(x,y,z)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isStillValid() {
|
||||
return wrappedLevel == null || wrappedLevel.tryGetChunk(chunkPos) == this;
|
||||
}
|
||||
}
|
||||
@@ -1,460 +0,0 @@
|
||||
package com.seibel.lod.common.wrappers.gui;
|
||||
|
||||
import java.util.AbstractMap;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
// Logger (for debug stuff)
|
||||
|
||||
import com.seibel.lod.core.ModInfo;
|
||||
import com.seibel.lod.core.config.file.ConfigFileHandling;
|
||||
import com.seibel.lod.core.config.types.AbstractConfigType;
|
||||
import com.seibel.lod.core.config.types.ConfigCategory;
|
||||
import com.seibel.lod.core.config.types.ConfigEntry;
|
||||
|
||||
// Uses https://github.com/TheElectronWill/night-config for toml (only for Fabric since Forge already includes this)
|
||||
|
||||
// Gets info from our own mod
|
||||
|
||||
import com.seibel.lod.core.config.*;
|
||||
|
||||
// Minecraft imports
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.seibel.lod.core.jar.updater.SelfUpdater;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.Font;
|
||||
import net.minecraft.client.gui.GuiComponent;
|
||||
import net.minecraft.client.gui.components.AbstractWidget;
|
||||
import net.minecraft.client.gui.components.Button;
|
||||
import net.minecraft.client.gui.components.ContainerObjectSelectionList;
|
||||
import net.minecraft.client.gui.components.EditBox;
|
||||
import net.minecraft.client.gui.components.events.GuiEventListener;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import net.minecraft.network.chat.CommonComponents;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.client.resources.language.I18n; // translation
|
||||
#if POST_MC_1_17_1
|
||||
import net.minecraft.client.gui.narration.NarratableEntry;
|
||||
#endif
|
||||
#if PRE_MC_1_19
|
||||
import net.minecraft.network.chat.TextComponent;
|
||||
import net.minecraft.network.chat.TranslatableComponent;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Based upon TinyConfig but is highly modified
|
||||
* https://github.com/Minenash/TinyConfig
|
||||
*
|
||||
* Credits to Motschen
|
||||
*
|
||||
* @author coolGi
|
||||
* @version 4-28-2022
|
||||
*/
|
||||
// FLOATS DONT WORK WITH THIS
|
||||
@SuppressWarnings("unchecked")
|
||||
public abstract class ClassicConfigGUI {
|
||||
/*
|
||||
This would be removed later on
|
||||
*/
|
||||
|
||||
|
||||
//==============//
|
||||
// Initializers //
|
||||
//==============//
|
||||
|
||||
// Some regexes to check if an input is valid
|
||||
private static final Pattern INTEGER_ONLY_REGEX = Pattern.compile("(-?[0-9]*)");
|
||||
private static final Pattern DECIMAL_ONLY_REGEX = Pattern.compile("-?([\\d]+\\.?[\\d]*|[\\d]*\\.?[\\d]+|\\.)");
|
||||
|
||||
private static class ConfigScreenConfigs {
|
||||
// This contains all the configs for the configs
|
||||
public static final int SpaceFromRightScreen = 10;
|
||||
public static final int ButtonWidthSpacing = 5;
|
||||
public static final int ResetButtonWidth = 40;
|
||||
}
|
||||
|
||||
/**
|
||||
* The terribly coded old stuff
|
||||
*/
|
||||
public static class EntryInfo {
|
||||
Object widget;
|
||||
Map.Entry<EditBox, Component> error;
|
||||
String tempValue;
|
||||
int index;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* creates a text field
|
||||
*/
|
||||
private static void textField(AbstractConfigType info, Function<String, Number> func, Pattern pattern, boolean cast) {
|
||||
boolean isNumber = pattern != null;
|
||||
((EntryInfo) info.guiValue).widget = (BiFunction<EditBox, Button, Predicate<String>>) (editBox, button) -> stringValue ->
|
||||
{
|
||||
stringValue = stringValue.trim();
|
||||
if (!(stringValue.isEmpty() || !isNumber || pattern.matcher(stringValue).matches()))
|
||||
return false;
|
||||
|
||||
Number value = 0;
|
||||
((EntryInfo) info.guiValue).error = null;
|
||||
if (isNumber && !stringValue.isEmpty() && !stringValue.equals("-") && !stringValue.equals(".")) {
|
||||
value = func.apply(stringValue);
|
||||
#if PRE_MC_1_19
|
||||
((EntryInfo) info.guiValue).error = ((ConfigEntry) info).isValid(value) == 0 ? null : new AbstractMap.SimpleEntry<>(editBox, new TextComponent(((ConfigEntry) info).isValid(value) == -1 ?
|
||||
#else
|
||||
((EntryInfo) info.guiValue).error = ((ConfigEntry) info).isValidMemoryAddress(value) == 0 ? null : new AbstractMap.SimpleEntry<>(editBox, Component.translatable(((ConfigEntry) info).isValidMemoryAddress(value) == -1 ?
|
||||
#endif
|
||||
"§cMinimum " + "length" + (cast ? " is " + (int) ((ConfigEntry) info).getMin() : " is " + ((ConfigEntry) info).getMin()) :
|
||||
"§cMaximum " + "length" + (cast ? " is " + (int) ((ConfigEntry) info).getMax() : " is " + ((ConfigEntry) info).getMax())));
|
||||
}
|
||||
|
||||
((EntryInfo) info.guiValue).tempValue = stringValue;
|
||||
editBox.setTextColor(((ConfigEntry) info).isValid(value) == 0 ? 0xFFFFFFFF : 0xFFFF7777);
|
||||
// button.active = entries.stream().allMatch(e -> e.inLimits);
|
||||
|
||||
|
||||
if (((ConfigEntry) info).isValid(value) == 0 && info.getType() != List.class) {
|
||||
if (!cast)
|
||||
((ConfigEntry) info).setWithoutSaving(value);
|
||||
else
|
||||
((ConfigEntry) info).setWithoutSaving(value.intValue());
|
||||
}
|
||||
// else if (((ConfigEntry) info).isValidMemoryAddress() == 0)
|
||||
// {
|
||||
// if (((List<String>) info.get()).size() == ((EntryInfo) info.guiValue).index)
|
||||
// info.set(((List<String>) info.get()).add(""));
|
||||
// info.set(((List<String>) info.get()).set(((EntryInfo) info.guiValue).index, Arrays.stream(((EntryInfo) info.guiValue).tempValue.replace("[", "").replace("]", "").split(", ")).collect(Collectors.toList()).get(0)));
|
||||
// }
|
||||
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
//==============//
|
||||
// GUI handling //
|
||||
//==============//
|
||||
|
||||
/**
|
||||
* if you want to get this config gui's screen call this
|
||||
*/
|
||||
public static Screen getScreen(ConfigBase configBase, Screen parent, String category) {
|
||||
return new ConfigScreen(configBase, parent, category);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pain
|
||||
*/
|
||||
private static class ConfigScreen extends Screen {
|
||||
protected ConfigScreen(ConfigBase configBase, Screen parent, String category) {
|
||||
#if PRE_MC_1_19
|
||||
super(new TranslatableComponent(
|
||||
#else
|
||||
super(Component.translatable(
|
||||
#endif
|
||||
I18n.exists(configBase.modID + ".config" + (category.isEmpty() ? "." + category : "") + ".title") ?
|
||||
configBase.modID + ".config.title" :
|
||||
configBase.modID + ".config" + (category.isEmpty() ? "" : "." + category) + ".title")
|
||||
);
|
||||
this.configBase = configBase;
|
||||
this.parent = parent;
|
||||
this.category = category;
|
||||
this.translationPrefix = configBase.modID + ".config.";
|
||||
}
|
||||
private final ConfigBase configBase;
|
||||
|
||||
private final String translationPrefix;
|
||||
private final Screen parent;
|
||||
private final String category;
|
||||
private ConfigListWidget list;
|
||||
private boolean reload = false;
|
||||
|
||||
// Real Time config update //
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* When you close it, it goes to the previous screen and saves
|
||||
*/
|
||||
@Override
|
||||
public void onClose() {
|
||||
ConfigBase.INSTANCE.configFileINSTANCE.saveToFile();
|
||||
Objects.requireNonNull(minecraft).setScreen(this.parent);
|
||||
}
|
||||
|
||||
// addRenderableWidget in 1.17 and over
|
||||
// addButton in 1.16 and below
|
||||
private Button addBtn(Button button) {
|
||||
#if PRE_MC_1_17_1
|
||||
this.addButton(button);
|
||||
#else
|
||||
this.addRenderableWidget(button);
|
||||
#endif
|
||||
return button;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
super.init();
|
||||
if (!reload)
|
||||
ConfigBase.INSTANCE.configFileINSTANCE.loadFromFile();
|
||||
|
||||
addBtn(new Button(this.width / 2 - 154, this.height - 28, 150, 20, CommonComponents.GUI_CANCEL, button -> {
|
||||
ConfigBase.INSTANCE.configFileINSTANCE.loadFromFile();
|
||||
Objects.requireNonNull(minecraft).setScreen(parent);
|
||||
}));
|
||||
Button done = addBtn(new Button(this.width / 2 + 4, this.height - 28, 150, 20, CommonComponents.GUI_DONE, (button) -> {
|
||||
ConfigBase.INSTANCE.configFileINSTANCE.saveToFile();
|
||||
Objects.requireNonNull(minecraft).setScreen(parent);
|
||||
}));
|
||||
|
||||
this.list = new ConfigListWidget(this.minecraft, this.width * 2, this.height, 32, this.height - 32, 25);
|
||||
if (this.minecraft != null && this.minecraft.level != null)
|
||||
this.list.setRenderBackground(false);
|
||||
this.addWidget(this.list);
|
||||
for (AbstractConfigType info : ConfigBase.INSTANCE.entries) {
|
||||
if (info.getCategory().matches(category) && info.getAppearance().showInGui) {
|
||||
initEntry(info, this.translationPrefix);
|
||||
#if PRE_MC_1_19
|
||||
TranslatableComponent name = new TranslatableComponent(translationPrefix + info.getNameWCategory());
|
||||
#else
|
||||
Component name = Component.translatable(translationPrefix + info.getNameWCategory());
|
||||
#endif
|
||||
if (ConfigEntry.class.isAssignableFrom(info.getClass())) {
|
||||
#if PRE_MC_1_19
|
||||
Button resetButton = new Button(this.width - ConfigScreenConfigs.SpaceFromRightScreen - 150 - ConfigScreenConfigs.ButtonWidthSpacing - ConfigScreenConfigs.ResetButtonWidth, 0, ConfigScreenConfigs.ResetButtonWidth, 20, new TextComponent("Reset").withStyle(ChatFormatting.RED), (button -> {
|
||||
#else
|
||||
Button resetButton = new Button(this.width - ConfigScreenConfigs.SpaceFromRightScreen - 150 - ConfigScreenConfigs.ButtonWidthSpacing - ConfigScreenConfigs.ResetButtonWidth, 0, ConfigScreenConfigs.ResetButtonWidth, 20, Component.translatable("Reset").withStyle(ChatFormatting.RED), (button -> {
|
||||
#endif
|
||||
((ConfigEntry) info).setWithoutSaving(((ConfigEntry) info).getDefaultValue());
|
||||
((EntryInfo) info.guiValue).index = 0;
|
||||
this.reload = true;
|
||||
Objects.requireNonNull(minecraft).setScreen(this);
|
||||
}));
|
||||
|
||||
if (((EntryInfo) info.guiValue).widget instanceof Map.Entry) {
|
||||
Map.Entry<Button.OnPress, Function<Object, Component>> widget = (Map.Entry<Button.OnPress, Function<Object, Component>>) ((EntryInfo) info.guiValue).widget;
|
||||
if (info.getType().isEnum())
|
||||
#if PRE_MC_1_19
|
||||
widget.setValue(value -> new TranslatableComponent(translationPrefix + "enum." + info.getType().getSimpleName() + "." + info.get().toString()));
|
||||
#else
|
||||
widget.setValue(value -> Component.translatable(translationPrefix + "enum." + info.getType().getSimpleName() + "." + info.get().toString()));
|
||||
#endif
|
||||
this.list.addButton(new Button(this.width - 150 - ConfigScreenConfigs.SpaceFromRightScreen, 0, 150, 20, widget.getValue().apply(info.get()), widget.getKey()), resetButton, null, name);
|
||||
} else if (((EntryInfo) info.guiValue).widget != null) {
|
||||
EditBox widget = new EditBox(font, this.width - 150 - ConfigScreenConfigs.SpaceFromRightScreen + 2, 0, 150 - 4, 20, null);
|
||||
widget.setMaxLength(150);
|
||||
widget.insertText(String.valueOf(info.get()));
|
||||
Predicate<String> processor = ((BiFunction<EditBox, Button, Predicate<String>>) ((EntryInfo) info.guiValue).widget).apply(widget, done);
|
||||
widget.setFilter(processor);
|
||||
this.list.addButton(widget, resetButton, null, name);
|
||||
}
|
||||
} else if (ConfigCategory.class.isAssignableFrom(info.getClass())) {
|
||||
Button widget = new Button(this.width / 2 - 100, this.height - 28, 100 * 2, 20, name, (button -> {
|
||||
ConfigBase.INSTANCE.configFileINSTANCE.saveToFile();
|
||||
Objects.requireNonNull(minecraft).setScreen(ClassicConfigGUI.getScreen(this.configBase, this, ((ConfigCategory) info).getDestination()));
|
||||
}));
|
||||
this.list.addButton(widget, null, null, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(PoseStack matrices, int mouseX, int mouseY, float delta) {
|
||||
this.renderBackground(matrices); // Renders background
|
||||
this.list.render(matrices, mouseX, mouseY, delta); // Render buttons
|
||||
drawCenteredString(matrices, font, title, width / 2, 15, 0xFFFFFF); // Render title
|
||||
if (SelfUpdater.deleteOldOnClose)
|
||||
drawString(matrices, font, new TranslatableComponent("lod.updater.waitingForClose"), 4, height-38, 0xFFFFFF);
|
||||
|
||||
// Render the tooltip only if it can find a tooltip in the language file
|
||||
for (AbstractConfigType info : ConfigBase.INSTANCE.entries) {
|
||||
if (info.getCategory().matches(category) && info.getAppearance().showInGui) {
|
||||
if (list.getHoveredButton(mouseX, mouseY).isPresent()) {
|
||||
AbstractWidget buttonWidget = list.getHoveredButton(mouseX, mouseY).get();
|
||||
Component text = ButtonEntry.buttonsWithText.get(buttonWidget);
|
||||
#if PRE_MC_1_19
|
||||
TranslatableComponent name = new TranslatableComponent(this.translationPrefix + (info.category.isEmpty() ? "" : info.category + ".") + info.getName());
|
||||
#else
|
||||
Component name = Component.translatable(this.translationPrefix + (info.category.isEmpty() ? "" : info.category + ".") + info.getName());
|
||||
#endif
|
||||
String key = translationPrefix + (info.category.isEmpty() ? "" : info.category + ".") + info.getName() + ".@tooltip";
|
||||
|
||||
if (((EntryInfo) info.guiValue).error != null && text.equals(name))
|
||||
renderTooltip(matrices, (Component) ((EntryInfo) info.guiValue).error.getValue(), mouseX, mouseY);
|
||||
else if (I18n.exists(key) && (text != null && text.equals(name))) {
|
||||
List<Component> list = new ArrayList<>();
|
||||
for (String str : I18n.get(key).split("\n"))
|
||||
#if PRE_MC_1_19
|
||||
list.add(new TextComponent(str));
|
||||
#else
|
||||
list.add(Component.translatable(str));
|
||||
#endif
|
||||
renderComponentTooltip(matrices, list, mouseX, mouseY);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
super.render(matrices, mouseX, mouseY, delta);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private static void initEntry(AbstractConfigType info, String translationPrefix) {
|
||||
info.guiValue = new EntryInfo();
|
||||
Class<?> fieldClass = info.getType();
|
||||
|
||||
if (ConfigEntry.class.isAssignableFrom(info.getClass())) {
|
||||
if (fieldClass == Integer.class) {
|
||||
// For int
|
||||
textField(info, Integer::parseInt, INTEGER_ONLY_REGEX, true);
|
||||
} else if (fieldClass == Double.class) {
|
||||
// For double
|
||||
textField(info, Double::parseDouble, DECIMAL_ONLY_REGEX, false);
|
||||
} else if (fieldClass == String.class || fieldClass == List.class) {
|
||||
// For string or list
|
||||
textField(info, String::length, null, true);
|
||||
} else if (fieldClass == Boolean.class) {
|
||||
// For boolean
|
||||
#if PRE_MC_1_19
|
||||
Function<Object, Component> func = value -> new TextComponent((Boolean) value ? "True" : "False").withStyle((Boolean) value ? ChatFormatting.GREEN : ChatFormatting.RED);
|
||||
#else
|
||||
Function<Object, Component> func = value -> Component.translatable((Boolean) value ? "True" : "False").withStyle((Boolean) value ? ChatFormatting.GREEN : ChatFormatting.RED);
|
||||
#endif
|
||||
((EntryInfo) info.guiValue).widget = new AbstractMap.SimpleEntry<Button.OnPress, Function<Object, Component>>(button -> {
|
||||
((ConfigEntry) info).setWithoutSaving(!(Boolean) info.get());
|
||||
button.setMessage(func.apply(info.get()));
|
||||
}, func);
|
||||
}
|
||||
else if (fieldClass.isEnum())
|
||||
{
|
||||
// For enum
|
||||
List<?> values = Arrays.asList(info.getType().getEnumConstants());
|
||||
#if PRE_MC_1_19
|
||||
Function<Object, Component> func = value -> new TranslatableComponent(translationPrefix + "enum." + fieldClass.getSimpleName() + "." + info.get().toString());
|
||||
#else
|
||||
Function<Object, Component> func = value -> Component.translatable(translationPrefix + "enum." + fieldClass.getSimpleName() + "." + info.get().toString());
|
||||
#endif
|
||||
((EntryInfo) info.guiValue).widget = new AbstractMap.SimpleEntry<Button.OnPress, Function<Object, Component>>(button -> {
|
||||
int index = values.indexOf(info.get()) + 1;
|
||||
info.set(values.get(index >= values.size() ? 0 : index));
|
||||
button.setMessage(func.apply(info.get()));
|
||||
}, func);
|
||||
}
|
||||
} else if (ConfigCategory.class.isAssignableFrom(info.getClass())) {
|
||||
// if (!info.info.getName().equals(""))
|
||||
// info.name = new TranslatableComponent(info.info.getName());
|
||||
}
|
||||
// return info;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
public static class ConfigListWidget extends ContainerObjectSelectionList<ButtonEntry> {
|
||||
Font textRenderer;
|
||||
|
||||
public ConfigListWidget(Minecraft minecraftClient, int i, int j, int k, int l, int m) {
|
||||
super(minecraftClient, i, j, k, l, m);
|
||||
this.centerListVertically = false;
|
||||
textRenderer = minecraftClient.font;
|
||||
}
|
||||
|
||||
public void addButton(AbstractWidget button, AbstractWidget resetButton, AbstractWidget indexButton, Component text) {
|
||||
this.addEntry(ButtonEntry.create(button, text, resetButton, indexButton));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRowWidth() {
|
||||
return 10000;
|
||||
}
|
||||
|
||||
public Optional<AbstractWidget> getHoveredButton(double mouseX, double mouseY) {
|
||||
for (ButtonEntry buttonEntry : this.children()) {
|
||||
if (buttonEntry.button != null && buttonEntry.button.isMouseOver(mouseX, mouseY)) {
|
||||
return Optional.of(buttonEntry.button);
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class ButtonEntry extends ContainerObjectSelectionList.Entry<ButtonEntry> {
|
||||
private static final Font textRenderer = Minecraft.getInstance().font;
|
||||
public final AbstractWidget button;
|
||||
private final AbstractWidget resetButton;
|
||||
private final AbstractWidget indexButton;
|
||||
private final Component text;
|
||||
private final List<AbstractWidget> children = new ArrayList<>();
|
||||
public static final Map<AbstractWidget, Component> buttonsWithText = new HashMap<>();
|
||||
|
||||
private ButtonEntry(AbstractWidget button, Component text, AbstractWidget resetButton, AbstractWidget indexButton) {
|
||||
buttonsWithText.put(button, text);
|
||||
this.button = button;
|
||||
this.resetButton = resetButton;
|
||||
this.text = text;
|
||||
this.indexButton = indexButton;
|
||||
if (button != null)
|
||||
children.add(button);
|
||||
if (resetButton != null)
|
||||
children.add(resetButton);
|
||||
if (indexButton != null)
|
||||
children.add(indexButton);
|
||||
}
|
||||
|
||||
public static ButtonEntry create(AbstractWidget button, Component text, AbstractWidget resetButton, AbstractWidget indexButton) {
|
||||
return new ButtonEntry(button, text, resetButton, indexButton);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) {
|
||||
if (button != null) {
|
||||
button.y = y;
|
||||
button.render(matrices, mouseX, mouseY, tickDelta);
|
||||
}
|
||||
if (resetButton != null) {
|
||||
resetButton.y = y;
|
||||
resetButton.render(matrices, mouseX, mouseY, tickDelta);
|
||||
}
|
||||
if (indexButton != null) {
|
||||
indexButton.y = y;
|
||||
indexButton.render(matrices, mouseX, mouseY, tickDelta);
|
||||
}
|
||||
if (text != null && (!text.getString().contains("spacer") || button != null))
|
||||
GuiComponent.drawString(matrices, textRenderer, text, 12, y + 5, 0xFFFFFF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends GuiEventListener> children() {
|
||||
return children;
|
||||
}
|
||||
|
||||
// Only for 1.17 and over
|
||||
// Remove in 1.16 and below
|
||||
#if POST_MC_1_17_1
|
||||
@Override
|
||||
public List<? extends NarratableEntry> narratables() {
|
||||
return children;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package com.seibel.lod.common.wrappers.gui;
|
||||
|
||||
import com.seibel.lod.core.ModInfo;
|
||||
import com.seibel.lod.core.config.ConfigBase;
|
||||
import com.seibel.lod.core.config.gui.ConfigScreen;
|
||||
import com.seibel.lod.core.config.gui.JavaScreenHandlerScreen;
|
||||
import com.seibel.lod.core.config.gui.OpenGLConfigScreen;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
|
||||
public class GetConfigScreen {
|
||||
public static type useScreen = type.Classic;
|
||||
public static enum type {
|
||||
Classic,
|
||||
@Deprecated
|
||||
OpenGL, // This was jsut an attempt, it didn't work out, and we are going to change to javafx soon (as soon as that works)
|
||||
JavaFX;
|
||||
}
|
||||
|
||||
public static Screen getScreen(Screen parent) {
|
||||
return switch (useScreen) {
|
||||
case Classic -> ClassicConfigGUI.getScreen(ConfigBase.INSTANCE, parent, "client");
|
||||
case OpenGL -> MinecraftScreen.getScreen(parent, new OpenGLConfigScreen(), ModInfo.ID + ".title");
|
||||
// case JavaFX -> MinecraftScreen.getScreen(parent, new JavaScreenHandlerScreen(new JavaScreenHandlerScreen.ExampleScreen()), ModInfo.ID + ".title");
|
||||
case JavaFX -> MinecraftScreen.getScreen(parent, new JavaScreenHandlerScreen(new ConfigScreen()), ModInfo.ID + ".title");
|
||||
default -> null;
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package com.seibel.lod.common.wrappers.gui;
|
||||
|
||||
import com.seibel.lod.core.wrapperInterfaces.config.ILangWrapper;
|
||||
import net.minecraft.client.resources.language.I18n;
|
||||
|
||||
public class LangWrapper implements ILangWrapper {
|
||||
public static final LangWrapper INSTANCE = new LangWrapper();
|
||||
@Override
|
||||
public boolean langExists(String str) {
|
||||
return I18n.exists(str);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getLang(String str) {
|
||||
return I18n.get(str);
|
||||
}
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
package com.seibel.lod.common.wrappers.gui;
|
||||
|
||||
import com.mojang.blaze3d.platform.Window;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.seibel.lod.core.config.gui.AbstractScreen;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.components.ContainerObjectSelectionList;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
|
||||
public class MinecraftScreen {
|
||||
public static Screen getScreen(Screen parent, AbstractScreen screen, String translationName) {
|
||||
return new ConfigScreenRenderer(parent, screen, translationName);
|
||||
}
|
||||
|
||||
private static class ConfigScreenRenderer extends Screen {
|
||||
private final Screen parent;
|
||||
private ConfigListWidget list;
|
||||
private AbstractScreen screen;
|
||||
|
||||
|
||||
#if PRE_MC_1_19
|
||||
public static net.minecraft.network.chat.TranslatableComponent translate (String str, Object... args) {
|
||||
return new net.minecraft.network.chat.TranslatableComponent(str, args);
|
||||
}
|
||||
#else
|
||||
public static net.minecraft.network.chat.MutableComponent translate (String str, Object... args) {
|
||||
return net.minecraft.network.chat.Component.translatable(str, args);
|
||||
}
|
||||
#endif
|
||||
|
||||
protected ConfigScreenRenderer(Screen parent, AbstractScreen screen, String translationName) {
|
||||
super(translate(translationName));
|
||||
screen.minecraftWindow = Minecraft.getInstance().getWindow().getWindow();
|
||||
this.parent = parent;
|
||||
this.screen = screen;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
super.init(); // Init Minecraft's screen
|
||||
Window mcWindow = this.minecraft.getWindow();
|
||||
screen.width = mcWindow.getWidth();
|
||||
screen.height = mcWindow.getHeight();
|
||||
screen.scaledWidth = this.width;
|
||||
screen.scaledHeight = this.height;
|
||||
screen.init(); // Init our own config screen
|
||||
|
||||
this.list = new ConfigListWidget(this.minecraft, this.width, this.height, 0, this.height, 25); // Select the area to tint
|
||||
if (this.minecraft != null && this.minecraft.level != null) // Check if in game
|
||||
this.list.setRenderBackground(false); // Disable from rendering
|
||||
this.addWidget(this.list); // Add the tint to the things to be rendered
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(PoseStack matrices, int mouseX, int mouseY, float delta) {
|
||||
this.renderBackground(matrices); // Render background
|
||||
this.list.render(matrices, mouseX, mouseY, delta); // Renders the items in the render list (currently only used to tint background darker)
|
||||
|
||||
screen.mouseX = mouseX;
|
||||
screen.mouseY = mouseY;
|
||||
screen.render(delta); // Render everything on the main screen
|
||||
|
||||
super.render(matrices, mouseX, mouseY, delta); // Render the vanilla stuff (currently only used for the background and tint)
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resize(Minecraft mc, int width, int height) {
|
||||
super.resize(mc, width, height); // Resize Minecraft's screen
|
||||
Window mcWindow = this.minecraft.getWindow();
|
||||
screen.width = mcWindow.getWidth();
|
||||
screen.height = mcWindow.getHeight();
|
||||
screen.scaledWidth = this.width;
|
||||
screen.scaledHeight = this.height;
|
||||
screen.onResize(); // Resize our screen
|
||||
}
|
||||
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick(); // Tick Minecraft's screen
|
||||
screen.tick(); // Tick our screen
|
||||
if (screen.close) // If we decide to close the screen, then actually close the screen
|
||||
onClose();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose() {
|
||||
screen.onClose(); // Close our screen
|
||||
Objects.requireNonNull(minecraft).setScreen(this.parent); // Goto the parent screen
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFilesDrop(@NotNull List<Path> files) {
|
||||
screen.onFilesDrop(files);
|
||||
}
|
||||
|
||||
// For checking if it should close when you press the escape key
|
||||
@Override
|
||||
public boolean shouldCloseOnEsc() {
|
||||
return screen.shouldCloseOnEsc;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ConfigListWidget extends ContainerObjectSelectionList {
|
||||
public ConfigListWidget(Minecraft minecraftClient, int i, int j, int k, int l, int m) {
|
||||
super(minecraftClient, i, j, k, l, m);
|
||||
this.centerListVertically = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.common.wrappers.gui;
|
||||
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.gui.components.ImageButton;
|
||||
import net.minecraft.client.renderer.GameRenderer;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
/**
|
||||
* Creates a button with a texture on it
|
||||
*/
|
||||
public class TexturedButtonWidget extends ImageButton {
|
||||
#if POST_MC_1_17_1
|
||||
public TexturedButtonWidget(int x, int y, int width, int height, int u, int v, ResourceLocation texture, OnPress pressAction) {
|
||||
super(x, y, width, height, u, v, texture, pressAction);
|
||||
}
|
||||
#endif
|
||||
|
||||
public TexturedButtonWidget(int x, int y, int width, int height, int u, int v, int hoveredVOffset, ResourceLocation texture, int textureWidth, int textureHeight, OnPress pressAction) {
|
||||
super(x, y, width, height, u, v, hoveredVOffset, texture, textureWidth, textureHeight, pressAction);
|
||||
}
|
||||
|
||||
public TexturedButtonWidget(int x, int y, int width, int height, int u, int v, int hoveredVOffset, ResourceLocation texture, int textureWidth, int textureHeight, OnPress pressAction, Component text) {
|
||||
super(x, y, width, height, u, v, hoveredVOffset, texture, textureWidth, textureHeight, pressAction, text);
|
||||
}
|
||||
|
||||
public TexturedButtonWidget(int x, int y, int width, int height, int u, int v, int hoveredVOffset, ResourceLocation texture, int textureWidth, int textureHeight, OnPress pressAction, OnTooltip tooltipSupplier, Component text) {
|
||||
super(x, y, width, height, u, v, hoveredVOffset, texture, textureWidth, textureHeight, pressAction, tooltipSupplier, text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void renderButton(PoseStack matrices, int mouseX, int mouseY, float delta) {
|
||||
#if PRE_MC_1_17_1
|
||||
Minecraft.getInstance().getTextureManager().bind(WIDGETS_LOCATION);
|
||||
RenderSystem.color4f(1.0F, 1.0F, 1.0F, this.alpha);
|
||||
#else
|
||||
RenderSystem.setShader(GameRenderer::getPositionTexShader);
|
||||
RenderSystem.setShaderTexture(0, WIDGETS_LOCATION);
|
||||
RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, this.alpha);
|
||||
#endif
|
||||
|
||||
int i = this.getYImage(this.isHovered);
|
||||
RenderSystem.enableBlend();
|
||||
RenderSystem.defaultBlendFunc();
|
||||
RenderSystem.enableDepthTest();
|
||||
this.blit(matrices, this.x, this.y, 0, 46 + i * 20, this.width / 2, this.height);
|
||||
this.blit(matrices, this.x + this.width / 2, this.y, 200 - this.width / 2, 46 + i * 20, this.width / 2, this.height);
|
||||
|
||||
super.renderButton(matrices, mouseX, mouseY, delta);
|
||||
}
|
||||
}
|
||||
@@ -1,188 +0,0 @@
|
||||
package com.seibel.lod.common.wrappers.gui.updater;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import com.mojang.blaze3d.platform.NativeImage;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.seibel.lod.common.wrappers.gui.ClassicConfigGUI;
|
||||
import com.seibel.lod.core.ModInfo;
|
||||
import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.core.jar.JarUtils;
|
||||
import com.seibel.lod.core.jar.installer.MarkdownFormatter;
|
||||
import com.seibel.lod.core.jar.installer.ModrinthGetter;
|
||||
import com.seibel.lod.core.jar.updater.SelfUpdater;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.StringSplitter;
|
||||
import net.minecraft.client.gui.Font;
|
||||
import net.minecraft.client.gui.GuiComponent;
|
||||
import net.minecraft.client.gui.components.AbstractWidget;
|
||||
import net.minecraft.client.gui.components.Button;
|
||||
import net.minecraft.client.gui.components.ContainerObjectSelectionList;
|
||||
import net.minecraft.client.gui.components.ImageButton;
|
||||
import net.minecraft.client.gui.components.events.GuiEventListener;
|
||||
import net.minecraft.client.gui.narration.NarratableEntry;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import net.minecraft.client.renderer.texture.DynamicTexture;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.FormattedText;
|
||||
import net.minecraft.network.chat.Style;
|
||||
import net.minecraft.network.chat.TextComponent;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.FormattedCharSequence;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* The screen that pops up if the mod has an update.
|
||||
*
|
||||
* @author coolGi
|
||||
*/
|
||||
// TODO: After finishing the config, rewrite this in openGL as well
|
||||
// TODO: Make this
|
||||
public class ChangelogScreen extends Screen {
|
||||
private Screen parent;
|
||||
private String versionID;
|
||||
private List<String> changelog;
|
||||
private TextArea changelogArea;
|
||||
|
||||
|
||||
public ChangelogScreen(Screen parent, String versionID) {
|
||||
super(translate(ModInfo.ID + ".updater.title"));
|
||||
this.parent = parent;
|
||||
this.versionID = versionID;
|
||||
|
||||
this.changelog = new ArrayList<>();
|
||||
// Get the release changelog and split it by the new lines
|
||||
List<String> unwrappedChangelog =
|
||||
List.of(new MarkdownFormatter.MinecraftFormat().convertTo( // This formats markdown to minecraft's "§" characters
|
||||
ModrinthGetter.changeLogs.get(versionID)
|
||||
).split("\\n"));
|
||||
// Makes the words wrap around to not go off the screen
|
||||
for (String str: unwrappedChangelog) {
|
||||
this.changelog.addAll(
|
||||
MarkdownFormatter.splitString(str, 75)
|
||||
);
|
||||
}
|
||||
// Debugging
|
||||
// System.out.println(this.changelog);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
super.init();
|
||||
|
||||
|
||||
this.addBtn( // Close
|
||||
new Button(5, this.height - 25, 100, 20, translate(ModInfo.ID + ".general.back"), (btn) -> {
|
||||
this.onClose();
|
||||
})
|
||||
);
|
||||
|
||||
|
||||
this.changelogArea = new TextArea(this.minecraft, this.width*2, this.height, 32, this.height - 32, 10);
|
||||
for (int i = 0; i < changelog.size(); i++) {
|
||||
this.changelogArea.addButton(new TextComponent(changelog.get(i)));
|
||||
// drawString(matrices, this.font, changelog.get(i), this.width / 2 - 175, this.height / 2 - 100 + i*10, 0xFFFFFF);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(PoseStack matrices, int mouseX, int mouseY, float delta) {
|
||||
this.renderBackground(matrices); // Render background
|
||||
|
||||
// Set the scroll position to the mouse height relative to the screen
|
||||
this.changelogArea.setScrollAmount(
|
||||
((double) mouseY)/((double) this.height) * this.changelogArea.getMaxScroll()
|
||||
);
|
||||
|
||||
this.changelogArea.render(matrices, mouseX, mouseY, delta); // Render the changelog
|
||||
|
||||
super.render(matrices, mouseX, mouseY, delta); // Render the buttons
|
||||
|
||||
drawCenteredString(matrices, font, title, width / 2, 15, 0xFFFFFF); // Render title
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose() {
|
||||
Objects.requireNonNull(minecraft).setScreen(this.parent); // Goto the parent screen
|
||||
}
|
||||
|
||||
|
||||
// addRenderableWidget in 1.17 and over
|
||||
// addButton in 1.16 and below
|
||||
private void addBtn(Button button) {
|
||||
#if PRE_MC_1_17_1
|
||||
this.addButton(button);
|
||||
#else
|
||||
this.addRenderableWidget(button);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if PRE_MC_1_19
|
||||
public static net.minecraft.network.chat.TranslatableComponent translate (String str, Object... args) {
|
||||
return new net.minecraft.network.chat.TranslatableComponent(str, args);
|
||||
}
|
||||
#else
|
||||
public static net.minecraft.network.chat.MutableComponent translate (String str, Object... args) {
|
||||
return net.minecraft.network.chat.Component.translatable(str, args);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
public static class TextArea extends ContainerObjectSelectionList<ButtonEntry> {
|
||||
Font textRenderer;
|
||||
|
||||
public TextArea(Minecraft minecraftClient, int i, int j, int k, int l, int m) {
|
||||
super(minecraftClient, i, j, k, l, m);
|
||||
this.centerListVertically = false;
|
||||
textRenderer = minecraftClient.font;
|
||||
}
|
||||
|
||||
public void addButton(Component text) {
|
||||
this.addEntry(ButtonEntry.create(text));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRowWidth() {
|
||||
return 10000;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ButtonEntry extends ContainerObjectSelectionList.Entry<ButtonEntry> {
|
||||
private static final Font textRenderer = Minecraft.getInstance().font;
|
||||
private final Component text;
|
||||
private final List<AbstractWidget> children = new ArrayList<>();
|
||||
|
||||
private ButtonEntry(Component text) {
|
||||
this.text = text;
|
||||
}
|
||||
|
||||
public static ButtonEntry create(Component text) {
|
||||
return new ButtonEntry(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(PoseStack matrices, int index, int y, int x, int entryWidth, int entryHeight, int mouseX, int mouseY, boolean hovered, float tickDelta) {
|
||||
GuiComponent.drawString(matrices, textRenderer, text, 12, y + 5, 0xFFFFFF);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<? extends GuiEventListener> children() {
|
||||
return children;
|
||||
}
|
||||
#if POST_MC_1_17_1
|
||||
@Override
|
||||
public List<? extends NarratableEntry> narratables() {
|
||||
return children;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -1,159 +0,0 @@
|
||||
package com.seibel.lod.common.wrappers.gui.updater;
|
||||
|
||||
import com.mojang.blaze3d.platform.NativeImage;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.seibel.lod.common.wrappers.gui.TexturedButtonWidget;
|
||||
import com.seibel.lod.core.ModInfo;
|
||||
import com.seibel.lod.core.config.Config;
|
||||
import com.seibel.lod.core.jar.JarUtils;
|
||||
import com.seibel.lod.core.jar.installer.ModrinthGetter;
|
||||
import com.seibel.lod.core.jar.updater.SelfUpdater;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.components.Button;
|
||||
import net.minecraft.client.gui.components.ImageButton;
|
||||
import net.minecraft.client.gui.screens.Screen;
|
||||
import net.minecraft.client.renderer.texture.DynamicTexture;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* The screen that pops up if the mod has an update.
|
||||
*
|
||||
* @author coolGi
|
||||
*/
|
||||
// TODO: After finishing the config, rewrite this in openGL as well
|
||||
// and also maybe add this suggestion https://discord.com/channels/881614130614767666/1035863487110467625/1035949054485594192
|
||||
public class UpdateModScreen extends Screen {
|
||||
private Screen parent;
|
||||
private String newVersionID;
|
||||
|
||||
|
||||
public UpdateModScreen(Screen parent, String newVersionID) {
|
||||
super(translate(ModInfo.ID + ".updater.title"));
|
||||
this.parent = parent;
|
||||
this.newVersionID = newVersionID;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
super.init();
|
||||
|
||||
|
||||
try {
|
||||
// We cannot get assets from the root of the mod so we use this hack
|
||||
// TODO: Load the icon.png and logo.png in the mod initialise rather than here
|
||||
ResourceLocation logoLocation = new ResourceLocation(ModInfo.ID, "logo.png");
|
||||
Minecraft.getInstance().getTextureManager().register(
|
||||
logoLocation,
|
||||
new DynamicTexture(NativeImage.read(JarUtils.accessFile("logo.png")))
|
||||
);
|
||||
|
||||
|
||||
// Logo image
|
||||
this.addBtn(new ImageButton(
|
||||
// Where the button is on the screen
|
||||
this.width / 2 - 65, this.height / 2 - 110,
|
||||
// Width and height of the button
|
||||
130, 65,
|
||||
// Offset
|
||||
0, 0,
|
||||
// Some textuary stuff
|
||||
0, logoLocation, 130, 65,
|
||||
// Create the button and tell it where to go
|
||||
// For now it goes to the client option by default
|
||||
(buttonWidget) -> System.out.println("Nice, you found an easter egg :)"), // TODO: Add a proper easter egg to pressing the logo (maybe with confetti)
|
||||
// Add a title to the button
|
||||
translate(ModInfo.ID + ".updater.title")
|
||||
));
|
||||
} catch (Exception e) { e.printStackTrace(); }
|
||||
|
||||
|
||||
this.addBtn(new TexturedButtonWidget(
|
||||
// Where the button is on the screen
|
||||
this.width / 2 - 97, this.height / 2 + 8,
|
||||
// Width and height of the button
|
||||
20, 20,
|
||||
// Offset
|
||||
0, 0,
|
||||
// Some textuary stuff
|
||||
0, new ResourceLocation(ModInfo.ID, "textures/gui/changelog.png"), 20, 20,
|
||||
// Create the button and tell it where to go
|
||||
// For now it goes to the client option by default
|
||||
(buttonWidget) -> Objects.requireNonNull(minecraft).setScreen(new ChangelogScreen(this, this.newVersionID)), // TODO: Add a proper easter egg to pressing the logo (maybe with confetti)
|
||||
// Add a title to the button
|
||||
translate(ModInfo.ID + ".updater.title")
|
||||
));
|
||||
|
||||
|
||||
this.addBtn( // Update
|
||||
new Button(this.width / 2 - 75, this.height / 2 + 8, 150, 20, translate(ModInfo.ID + ".updater.update"), (btn) -> {
|
||||
SelfUpdater.deleteOldOnClose = true;
|
||||
SelfUpdater.updateMod();
|
||||
this.onClose();
|
||||
})
|
||||
);
|
||||
this.addBtn( // Silent update
|
||||
new Button(this.width / 2 - 75, this.height / 2 + 30, 150, 20, translate(ModInfo.ID + ".updater.silent"), (btn) -> {
|
||||
Config.Client.AutoUpdater.promptForUpdate.set(false);
|
||||
SelfUpdater.updateMod();
|
||||
this.onClose();
|
||||
})
|
||||
);
|
||||
this.addBtn( // Later (not now)
|
||||
new Button(this.width / 2 + 2, this.height / 2 + 70, 100, 20, translate(ModInfo.ID + ".updater.later"), (btn) -> {
|
||||
this.onClose();
|
||||
})
|
||||
);
|
||||
this.addBtn( // Never
|
||||
new Button(this.width / 2 - 102, this.height / 2 + 70, 100, 20, translate(ModInfo.ID + ".updater.never"), (btn) -> {
|
||||
Config.Client.AutoUpdater.enableAutoUpdater.set(false);
|
||||
this.onClose();
|
||||
})
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void render(PoseStack matrices, int mouseX, int mouseY, float delta) {
|
||||
this.renderBackground(matrices); // Render background
|
||||
|
||||
|
||||
// Render the text's
|
||||
drawCenteredString(matrices, this.font, translate(ModInfo.ID + ".updater.text1"), this.width / 2, this.height / 2 - 35, 0xFFFFFF);
|
||||
drawCenteredString(matrices, this.font, translate(ModInfo.ID + ".updater.text2", ModInfo.VERSION, ModrinthGetter.releaseNames.get(this.newVersionID)), this.width / 2, this.height / 2 -20, 0x52FD52);
|
||||
|
||||
// TODO: add the tooltips for the buttons
|
||||
super.render(matrices, mouseX, mouseY, delta); // Render the buttons
|
||||
|
||||
// TODO: Add tooltips
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose() {
|
||||
Objects.requireNonNull(minecraft).setScreen(this.parent); // Goto the parent screen
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// addRenderableWidget in 1.17 and over
|
||||
// addButton in 1.16 and below
|
||||
private void addBtn(Button button) {
|
||||
#if PRE_MC_1_17_1
|
||||
this.addButton(button);
|
||||
#else
|
||||
this.addRenderableWidget(button);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if PRE_MC_1_19
|
||||
public static net.minecraft.network.chat.TranslatableComponent translate (String str, Object... args) {
|
||||
return new net.minecraft.network.chat.TranslatableComponent(str, args);
|
||||
}
|
||||
#else
|
||||
public static net.minecraft.network.chat.MutableComponent translate (String str, Object... args) {
|
||||
return net.minecraft.network.chat.Component.translatable(str, args);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
-262
@@ -1,262 +0,0 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod (formerly the LOD Mod),
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020-2022 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.lod.common.wrappers.minecraft;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.ArrayList;
|
||||
|
||||
import com.mojang.blaze3d.platform.NativeImage;
|
||||
import com.seibel.lod.common.wrappers.world.ClientLevelWrapper;
|
||||
import com.seibel.lod.common.wrappers.world.ServerLevelWrapper;
|
||||
import com.seibel.lod.core.ModInfo;
|
||||
import com.seibel.lod.core.enums.ELodDirection;
|
||||
import com.seibel.lod.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftClientWrapper;
|
||||
import com.seibel.lod.core.wrapperInterfaces.minecraft.IMinecraftSharedWrapper;
|
||||
import com.seibel.lod.core.wrapperInterfaces.minecraft.IProfilerWrapper;
|
||||
import com.seibel.lod.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import com.seibel.lod.common.wrappers.McObjectConverter;
|
||||
import com.seibel.lod.core.pos.DhBlockPos;
|
||||
import com.seibel.lod.core.pos.DhChunkPos;
|
||||
|
||||
import net.minecraft.CrashReport;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.client.resources.model.ModelManager;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
#if PRE_MC_1_19
|
||||
import net.minecraft.network.chat.TextComponent;
|
||||
#endif
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* A singleton that wraps the Minecraft object.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 3-5-2022
|
||||
*/
|
||||
//@Environment(EnvType.CLIENT)
|
||||
public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecraftSharedWrapper
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
|
||||
|
||||
public static final MinecraftClientWrapper INSTANCE = new MinecraftClientWrapper();
|
||||
|
||||
public final Minecraft mc = Minecraft.getInstance();
|
||||
|
||||
/**
|
||||
* The lightmap for the current:
|
||||
* Time, dimension, brightness setting, etc.
|
||||
*/
|
||||
private NativeImage lightMap = null;
|
||||
|
||||
private ProfilerWrapper profilerWrapper;
|
||||
|
||||
|
||||
private MinecraftClientWrapper()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// helper methods //
|
||||
//================//
|
||||
|
||||
/**
|
||||
* This should be called at the beginning of every frame to
|
||||
* clear any Minecraft data that becomes out of date after a frame. <br> <br>
|
||||
* <p>
|
||||
* LightMaps and other time sensitive objects fall in this category. <br> <br>
|
||||
* <p>
|
||||
* This doesn't affect OpenGL objects in any way.
|
||||
*/
|
||||
@Override
|
||||
public void clearFrameObjectCache()
|
||||
{
|
||||
lightMap = null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=================//
|
||||
// method wrappers //
|
||||
//=================//
|
||||
|
||||
@Override
|
||||
public float getShade(ELodDirection lodDirection) {
|
||||
if (mc.level != null)
|
||||
{
|
||||
Direction mcDir = McObjectConverter.Convert(lodDirection);
|
||||
return mc.level.getShade(mcDir, true);
|
||||
}
|
||||
else return 0.0f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSinglePlayerServer() { return mc.hasSingleplayerServer(); }
|
||||
@Override
|
||||
public boolean clientConnectedToDedicatedServer() { return mc.getCurrentServer() != null && !this.hasSinglePlayerServer(); }
|
||||
|
||||
@Override
|
||||
public String getCurrentServerName() { return mc.getCurrentServer().name; }
|
||||
|
||||
@Override
|
||||
public String getCurrentServerIp() { return mc.getCurrentServer().ip; }
|
||||
|
||||
@Override
|
||||
public String getCurrentServerVersion()
|
||||
{
|
||||
return mc.getCurrentServer().version.getString();
|
||||
}
|
||||
|
||||
//=============//
|
||||
// Simple gets //
|
||||
//=============//
|
||||
|
||||
public LocalPlayer getPlayer()
|
||||
{
|
||||
return mc.player;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean playerExists()
|
||||
{
|
||||
return mc.player != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DhBlockPos getPlayerBlockPos()
|
||||
{
|
||||
BlockPos playerPos = getPlayer().blockPosition();
|
||||
return new DhBlockPos(playerPos.getX(), playerPos.getY(), playerPos.getZ());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DhChunkPos getPlayerChunkPos()
|
||||
{
|
||||
#if PRE_MC_1_17_1
|
||||
ChunkPos playerPos = new ChunkPos(getPlayer().blockPosition());
|
||||
#else
|
||||
ChunkPos playerPos = getPlayer().chunkPosition();
|
||||
#endif
|
||||
return new DhChunkPos(playerPos.x, playerPos.z);
|
||||
}
|
||||
|
||||
public ModelManager getModelManager()
|
||||
{
|
||||
return mc.getModelManager();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ILevelWrapper getWrappedClientWorld()
|
||||
{
|
||||
if (mc.level == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return ClientLevelWrapper.getWrapper(mc.level);
|
||||
}
|
||||
|
||||
/** Please move over to getInstallationDirectory() */
|
||||
@Deprecated
|
||||
@Override
|
||||
public File getGameDirectory()
|
||||
{
|
||||
return getInstallationDirectory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IProfilerWrapper getProfiler()
|
||||
{
|
||||
if (profilerWrapper == null)
|
||||
profilerWrapper = new ProfilerWrapper(mc.getProfiler());
|
||||
else if (mc.getProfiler() != profilerWrapper.profiler)
|
||||
profilerWrapper.profiler = mc.getProfiler();
|
||||
return profilerWrapper;
|
||||
}
|
||||
|
||||
/** Returns all worlds available to the server */
|
||||
@Override
|
||||
public ArrayList<ILevelWrapper> getAllServerWorlds()
|
||||
{
|
||||
ArrayList<ILevelWrapper> worlds = new ArrayList<ILevelWrapper>();
|
||||
|
||||
Iterable<ServerLevel> serverWorlds = mc.getSingleplayerServer().getAllLevels();
|
||||
for (ServerLevel world : serverWorlds)
|
||||
{
|
||||
worlds.add(ServerLevelWrapper.getWrapper(world));
|
||||
}
|
||||
|
||||
return worlds;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void sendChatMessage(String string)
|
||||
{
|
||||
#if PRE_MC_1_19
|
||||
getPlayer().sendMessage(new TextComponent(string), getPlayer().getUUID());
|
||||
#else
|
||||
getPlayer().sendSystemMessage(net.minecraft.network.chat.Component.translatable(string));
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Crashes Minecraft, displaying the given errorMessage <br> <br>
|
||||
* In the following format: <br>
|
||||
*
|
||||
* The game crashed whilst <strong>errorMessage</strong> <br>
|
||||
* Error: <strong>ExceptionClass: exceptionErrorMessage</strong> <br>
|
||||
* Exit Code: -1 <br>
|
||||
*/
|
||||
@Override
|
||||
public void crashMinecraft(String errorMessage, Throwable exception)
|
||||
{
|
||||
LOGGER.error(ModInfo.READABLE_NAME + " had the following error: [" + errorMessage + "]. Crashing Minecraft...");
|
||||
CrashReport report = new CrashReport(errorMessage, exception);
|
||||
Minecraft.crash(report);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getOptionsObject()
|
||||
{
|
||||
return mc.options;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDedicatedServer() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getInstallationDirectory() {
|
||||
return mc.gameDirectory;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user