Compare commits
2675 Commits
1.16.5-a1.5.0
...
2.3.4b
| Author | SHA1 | Date | |
|---|---|---|---|
| d09ddf57d3 | |||
| 486edac1d8 | |||
| 3b3731a137 | |||
| 563ec70154 | |||
| 175f5ed6d6 | |||
| 1e63607233 | |||
| 4dd8be23fa | |||
| 7fac5b4c6e | |||
| f2ec1ecf3f | |||
| 2674e6b2e9 | |||
| bcbe3f0fb7 | |||
| f85108ed11 | |||
| 2bc5169ce5 | |||
| 1edd809708 | |||
| 475111b38b | |||
| b44a967e56 | |||
| acea685e75 | |||
| 20f15a6b39 | |||
| debf52418c | |||
| cf71491381 | |||
| 0a4a8466cf | |||
| 31fac60d34 | |||
| c335020c2f | |||
| 4db4f2fbc6 | |||
| f9f4a208e7 | |||
| b5fa5936b3 | |||
| 6ceabe7895 | |||
| ec3d8afbfc | |||
| e9a0c6d097 | |||
| 0238568370 | |||
| 74be00e025 | |||
| c10af6dd04 | |||
| 85ee5ac833 | |||
| 21877d67a5 | |||
| ae33a79d6e | |||
| 9204b357d8 | |||
| 78b1b74036 | |||
| 864c5b5f86 | |||
| b271c8e119 | |||
| 79bdae5b8b | |||
| d5dc9f6b79 | |||
| a50f13caa0 | |||
| 75b3649a97 | |||
| 69adb54b91 | |||
| 458c1ae7e0 | |||
| a647551d26 | |||
| 3a45bdd2a2 | |||
| 4806cd2445 | |||
| af7f90f128 | |||
| f72ad60f58 | |||
| 6015afbf4c | |||
| 0369ae63f3 | |||
| 278d5063fb | |||
| a64e72034e | |||
| fcdb56660c | |||
| 0c26261cd5 | |||
| b50525fff9 | |||
| 92e403823b | |||
| e02f56f4ef | |||
| aa4681e044 | |||
| 1c9130c3f1 | |||
| c3597cd843 | |||
| d4a52ac5a3 | |||
| 1b9d14e7b4 | |||
| 0ea27b676e | |||
| cd73608b07 | |||
| 03fc22f611 | |||
| cc251e46b0 | |||
| 7aa0bfefec | |||
| 9bdad5e4f1 | |||
| baebb7323d | |||
| 8a3175f345 | |||
| dc58efb301 | |||
| c9ac4b2ada | |||
| 6e1ec476ed | |||
| d1aa5a524b | |||
| 5c661a3a76 | |||
| d29e9085a1 | |||
| d392de3c0d | |||
| 7209193f8f | |||
| ed4f644a3f | |||
| 34038684a7 | |||
| 6fe6694c82 | |||
| 8e52f1aca5 | |||
| 5ce3dda2d5 | |||
| f4f81f4d7f | |||
| 7c37a5c370 | |||
| b495ac4799 | |||
| 2ddeaf50eb | |||
| 3721ebea6e | |||
| 98f8a87362 | |||
| 10a743ddef | |||
| 95c896f964 | |||
| 040bc16874 | |||
| 35d3fdb473 | |||
| 549f7510f7 | |||
| fab64d8477 | |||
| 4a6a35f617 | |||
| 2b519a826f | |||
| 445c01b5ae | |||
| 0f08bd540e | |||
| 77088465f9 | |||
| affe014433 | |||
| 4c06bf6dbd | |||
| dcab616385 | |||
| 89b7d08e9b | |||
| 724e318221 | |||
| a40d62d46a | |||
| 2f6b4c079b | |||
| 951e3c0271 | |||
| 84825c2d09 | |||
| ec627e2eba | |||
| 06bc9a349f | |||
| ff6c4e227b | |||
| a4d46ffe94 | |||
| bd5c140782 | |||
| 229c3f7c91 | |||
| 693369bc08 | |||
| d109fe6c43 | |||
| 3c9d3707cf | |||
| 6e53564835 | |||
| 2480fe0d86 | |||
| 691c9d3f45 | |||
| 3faf25636d | |||
| ab3bfbefb4 | |||
| 890e802de4 | |||
| c13bc0cd6e | |||
| 7143b7de08 | |||
| d136d782f5 | |||
| 29a160316c | |||
| 1f6f64d322 | |||
| 37c0af529d | |||
| 1341ea3f3d | |||
| c0bb120669 | |||
| f8887e403f | |||
| 949ee423c8 | |||
| b19ed3f30c | |||
| 2d085e1074 | |||
| 6ba0490cf7 | |||
| b6a0878241 | |||
| 50f5371084 | |||
| df74b8d243 | |||
| fce2868c62 | |||
| a36cd0763b | |||
| 0fba015f54 | |||
| f251c90472 | |||
| 492a051a3b | |||
| 0aa4743c1b | |||
| 85f16944b2 | |||
| dddb0be2ac | |||
| 4a3effa2f5 | |||
| a0a9151bfd | |||
| aa3d15f38f | |||
| adcb2a3a05 | |||
| 78f2cb24cc | |||
| 67945509ed | |||
| c653e526a5 | |||
| 49b50c4c88 | |||
| 7449f46c5e | |||
| 069fc39aad | |||
| 4979ccf3e2 | |||
| dd7f9c20b6 | |||
| e96f9de1f0 | |||
| c902e1957f | |||
| d40afb7a2a | |||
| 01474d72e3 | |||
| 7c5af1836b | |||
| a9bf6ae7e4 | |||
| aef3162246 | |||
| 97ce869076 | |||
| 91b3c83ffd | |||
| 1522df19cb | |||
| 3845564128 | |||
| 23ef7cf27a | |||
| bec28a5694 | |||
| 8f20f103ad | |||
| 246e77cc56 | |||
| 87fa29c77a | |||
| 5010256ce6 | |||
| a66ad19343 | |||
| 913a458a1a | |||
| 093d3a801e | |||
| 61ccf7bf60 | |||
| f948072253 | |||
| b748f27a1c | |||
| 4dd4bb9ef0 | |||
| 5051bde3b0 | |||
| 42cf639acc | |||
| 9e6953a596 | |||
| 7f4f8a40eb | |||
| 89ca535a6f | |||
| 145182502e | |||
| d61dfc9e03 | |||
| 611d7d87ae | |||
| 2f6a2d99ab | |||
| d88ca0c98d | |||
| 0f64df7be0 | |||
| 23a1f0b025 | |||
| 4a72e02550 | |||
| 521bcdcc0f | |||
| 4eb20d5ce8 | |||
| 3ad68aaf42 | |||
| 2a9a03771e | |||
| 8f7823a4d2 | |||
| cc4b965966 | |||
| a6418de927 | |||
| 5303415d05 | |||
| 836515934f | |||
| 228dc46d6b | |||
| a91f9670dc | |||
| 81313252f2 | |||
| f65d411978 | |||
| 8c8a5ffeaf | |||
| 68793fbe8d | |||
| d8401a8f49 | |||
| 07ff00f7c9 | |||
| fadaff1113 | |||
| ff6bf7b4c9 | |||
| 082b1224a8 | |||
| bc475373fc | |||
| 498e958eca | |||
| 82e0cfe0b4 | |||
| 31d89e3349 | |||
| a3775c1f88 | |||
| e070bf4244 | |||
| 8287192cd0 | |||
| d40f4dfe19 | |||
| 595cdf011a | |||
| 96f2f8c3b2 | |||
| c883ded7c4 | |||
| 834269da67 | |||
| a9bebf03d5 | |||
| 939f6304bf | |||
| 6e9f466570 | |||
| a0b5cc7a5c | |||
| 82708d998d | |||
| 613e444490 | |||
| f493e201d4 | |||
| 2a8013b1d6 | |||
| 54fed62507 | |||
| e51bec9ce4 | |||
| e47a83b706 | |||
| 8029c7b00c | |||
| 2b38dc2575 | |||
| 46cafb4cbe | |||
| ff96533c93 | |||
| 89e73f6383 | |||
| 069ebfe24e | |||
| 8b374c4734 | |||
| 1febade083 | |||
| deedd85914 | |||
| 218c27adae | |||
| fde48b6f1a | |||
| f2a36e73d0 | |||
| c5429ad139 | |||
| 7bc2ee296c | |||
| 4e26e4ab31 | |||
| a91685b590 | |||
| 06f73c9b0a | |||
| 062dc29fd4 | |||
| 4096a24306 | |||
| 2563de3ba3 | |||
| 4a99b42fa8 | |||
| f12f119ce2 | |||
| 775adfaad5 | |||
| 2a9c319935 | |||
| fda44c41a8 | |||
| 8247f5f215 | |||
| 7eba6848bb | |||
| 6e84cac0d2 | |||
| 2bf96ea781 | |||
| d5de4a8171 | |||
| 3cd7c7f1a3 | |||
| 1741ebf8b2 | |||
| 55776f8beb | |||
| a469770e5d | |||
| 851dabc18b | |||
| dccdbaeb73 | |||
| f4126f5378 | |||
| 97af075c7d | |||
| 1dfdd422db | |||
| 072082c56a | |||
| 43caa2a55c | |||
| b8bad9b6bf | |||
| 8afdd6ed2b | |||
| 34968a6945 | |||
| 851a79a77e | |||
| 1ca1db705f | |||
| 8f57c2cce2 | |||
| 942e3093cb | |||
| f3e65010f1 | |||
| b3cfb35fac | |||
| b60d778303 | |||
| 9ec28aa661 | |||
| 98400a9d3c | |||
| ae8658ae77 | |||
| e928fe3ecd | |||
| 963dc4a404 | |||
| 04f42999df | |||
| 730d014f13 | |||
| 1f81c50ce1 | |||
| f60c550879 | |||
| 0d556b5d95 | |||
| 70d897f09c | |||
| 9accb6d584 | |||
| 843dc580c8 | |||
| 77aa4773ef | |||
| fc3c944e3d | |||
| 7d6aecc4c7 | |||
| 528beb8384 | |||
| 5f1180a5dd | |||
| a9f1e8587c | |||
| 7a076f5509 | |||
| 3349e51655 | |||
| 77a366065d | |||
| c2d6ecaae6 | |||
| c9bc830058 | |||
| 6125031d9d | |||
| c041cde574 | |||
| bd946af229 | |||
| 559626456a | |||
| c6843c1d95 | |||
| 0d32fab434 | |||
| 94571de00f | |||
| d062eff8b4 | |||
| b1e46faf6f | |||
| 04ed5b2e03 | |||
| 15d9ff503f | |||
| 64942d77e4 | |||
| f287dbd4d3 | |||
| c387f57d9c | |||
| 2dacb91b79 | |||
| d809568cc3 | |||
| beee44df14 | |||
| f651fc4b50 | |||
| 596e4eae0e | |||
| 6e70073ae4 | |||
| 1beef2b4ad | |||
| a0e4ed8371 | |||
| f40adfd9c6 | |||
| 7fb5e95809 | |||
| 03d5cb9289 | |||
| 3b4b4d6b7e | |||
| b9a97a0fda | |||
| 0dae6942cb | |||
| 8bb6aeb526 | |||
| 32ec420248 | |||
| 1925537da0 | |||
| 3bb4c21fa2 | |||
| 5b61a98196 | |||
| 7c6eba983a | |||
| 0023ab09ed | |||
| c289f5d717 | |||
| 6df3ad722c | |||
| 56f6abd858 | |||
| c326e0ba81 | |||
| 60b28fcf2e | |||
| a9ffd3bd3b | |||
| bc72e925df | |||
| 108df99633 | |||
| ba245ea266 | |||
| ec721ce172 | |||
| 3ad2a95c10 | |||
| e22e241d06 | |||
| cd70d55b4d | |||
| b6c98d3bde | |||
| 5fe605540d | |||
| c232b64f24 | |||
| f94b6dbaa5 | |||
| 928bc5df6c | |||
| a5865b3545 | |||
| 8f15ab7ccd | |||
| 131e4124f3 | |||
| ae6333c7b5 | |||
| d38c622d9b | |||
| fe625e5b55 | |||
| 38a6ad552b | |||
| 222a008514 | |||
| 56684bdf4c | |||
| eb4525c68d | |||
| 66eb2ed0f9 | |||
| 9866842e01 | |||
| e9487b0481 | |||
| 82c5aa907b | |||
| 47b145cb90 | |||
| ff46b925b2 | |||
| 8ca7ff5ae0 | |||
| 70550a21a0 | |||
| 50f911f63c | |||
| 4b0dca5823 | |||
| 0e777f04bc | |||
| b12f27cc18 | |||
| 1a66f457af | |||
| b4dca6a1b4 | |||
| 7759a2f9ea | |||
| fe9bccb91f | |||
| fc6fd310f6 | |||
| 8be161b381 | |||
| 8eba8cb40b | |||
| 44326344e6 | |||
| 17b7ee9045 | |||
| 6a47a2150f | |||
| 13728a7540 | |||
| c51e941413 | |||
| 2a05c32a2f | |||
| 353a507914 | |||
| f3b73d54f8 | |||
| 92ed9b8070 | |||
| 9c3c37bc3e | |||
| 79fb7c654a | |||
| 520b4e0930 | |||
| 45a07206c9 | |||
| ad0b78936a | |||
| 2babae40de | |||
| 17713a9f93 | |||
| 48120a4a38 | |||
| 69ffd795c9 | |||
| 1df5dd5458 | |||
| b77acaa3b2 | |||
| d8024ab488 | |||
| 064d8b3506 | |||
| 9ca6a2116b | |||
| 449c87982c | |||
| 7edfc40b9d | |||
| 9acda97f54 | |||
| 14edd63029 | |||
| f3a1235dd3 | |||
| de93bfee2f | |||
| 6eb80ace00 | |||
| 3ac8d6a8b1 | |||
| 269c8dc4e3 | |||
| c8173005a7 | |||
| ed846ea564 | |||
| f6a8f5c6b5 | |||
| 3c60a7d842 | |||
| 3c97feeaf8 | |||
| b2ac91f7db | |||
| 1ebad39fc1 | |||
| 38a2edff06 | |||
| b2cf38798e | |||
| ed83e41f19 | |||
| 6d52cdba0a | |||
| 05449c9e86 | |||
| 33ef1297ba | |||
| 3b13786990 | |||
| 222d06898e | |||
| 4438adad24 | |||
| 986e474657 | |||
| e8288a0df9 | |||
| 74cab8f4ad | |||
| 5e35572de8 | |||
| 7e0e02bafc | |||
| a301532443 | |||
| 940448f219 | |||
| 8510deb6aa | |||
| 0d0ba5d3bf | |||
| 036371dd76 | |||
| 5aae584ffe | |||
| 201c619915 | |||
| 7cd6a3bb79 | |||
| ca36d4797d | |||
| b5fe3bcbf9 | |||
| e43f9e76f6 | |||
| b8901c3edd | |||
| d28938f8af | |||
| 9f108220f5 | |||
| ffe53a7196 | |||
| 9e12849107 | |||
| 0a8c093682 | |||
| 60056e1654 | |||
| 11a752a99d | |||
| 68097f61eb | |||
| 8b514b07dc | |||
| 8e6010bbe5 | |||
| 95eb07ca79 | |||
| e6e03e78ea | |||
| d2c572414c | |||
| d2e0d5b32b | |||
| d4ba227a44 | |||
| caba007899 | |||
| d5cfe9b8e9 | |||
| f1707236fa | |||
| c55cbdb69a | |||
| 00b69dcc68 | |||
| cd74e33c54 | |||
| 3f14e5dfa5 | |||
| 8c9e6ea79a | |||
| c71de31f57 | |||
| ac869bf06e | |||
| 3175bc0439 | |||
| 23ac6ec957 | |||
| f080a59b41 | |||
| 603200ed8b | |||
| b0774052a0 | |||
| 7e163ce626 | |||
| d19654cf15 | |||
| 838d8be08b | |||
| 2de82b1223 | |||
| 650012fb08 | |||
| a1ef3466ad | |||
| 97421feb33 | |||
| 0c90af6515 | |||
| 9cebd0298c | |||
| 9afcddca4f | |||
| 02fb7eedba | |||
| 4aa9bec15c | |||
| a6eeaa5b3e | |||
| c462325ce6 | |||
| d208b0ab19 | |||
| ab4ef429db | |||
| 86473e022e | |||
| fd89f569d0 | |||
| eefc765823 | |||
| ebccb2516b | |||
| 8c62a40da9 | |||
| d56af5c38f | |||
| 39b1ec61ba | |||
| cb613cf7df | |||
| 28e33b4c36 | |||
| 855e6b8180 | |||
| d62161f529 | |||
| 71d48411f1 | |||
| 731842e09c | |||
| 61169f87c0 | |||
| 9fb3b196d2 | |||
| 867b875cf9 | |||
| 3875c8c4ce | |||
| 89b959d3f5 | |||
| d62e50d6f4 | |||
| 16836a2b49 | |||
| f5651f26a5 | |||
| 82ff59c857 | |||
| 8af61041f0 | |||
| 2a9136b56f | |||
| 64da6c811d | |||
| e6b93e0d92 | |||
| f874219a64 | |||
| b4822740f4 | |||
| af205a50b4 | |||
| 2f6eaf79bd | |||
| 625f1e700f | |||
| 897d5b0b11 | |||
| 95641e2f4e | |||
| cd856b86c7 | |||
| c00aa6d627 | |||
| 398a3fb0bc | |||
| e0fa638ad9 | |||
| 4e42cbd4ce | |||
| b6c6be77cd | |||
| 0964293a72 | |||
| c8b6141ce0 | |||
| 948540369f | |||
| 363df0ad6f | |||
| a37e105434 | |||
| aeea0c00c3 | |||
| 137352674e | |||
| 4734552954 | |||
| 879c2f1ec4 | |||
| 7dc9d2a352 | |||
| cabc470ebd | |||
| 0bf1f493aa | |||
| 705bd14ee4 | |||
| 155955e49b | |||
| c76a793b18 | |||
| 50cc8501a0 | |||
| 209279e3e4 | |||
| 41239572a5 | |||
| 106ab47c3d | |||
| a84f9b60e5 | |||
| 4481e8634a | |||
| 3e432682fb | |||
| 05569c03a4 | |||
| 2d567b84be | |||
| e2a378250f | |||
| e2083a1836 | |||
| 334946ab59 | |||
| 8c9bb98125 | |||
| 726f0f3d3c | |||
| 50e5898692 | |||
| de05a5f674 | |||
| 31b57fae50 | |||
| 2f686057f3 | |||
| 132251341f | |||
| 2bac5f933a | |||
| 2e565aa83a | |||
| 4e9d0f4861 | |||
| 7216b193e8 | |||
| c33a5bf814 | |||
| 97756a5196 | |||
| 377f7d23e3 | |||
| 7005202384 | |||
| 99e8f57bac | |||
| afddf4168e | |||
| fbffdc0c9f | |||
| e6d3647490 | |||
| 13363ff363 | |||
| 7f98e4b1eb | |||
| 408460b0ae | |||
| b69ef5835d | |||
| 0428fa0912 | |||
| 9f3124fa56 | |||
| fbbdab73c6 | |||
| ee9441c521 | |||
| a9e0fd5d9b | |||
| 98464889ca | |||
| eed5fd60c6 | |||
| ac43cd5496 | |||
| 1f16a7c808 | |||
| 39e4c70754 | |||
| 82eb27af4c | |||
| 3aaab94b39 | |||
| 07a0779ca4 | |||
| 2adba02a38 | |||
| 9dd76db3fc | |||
| 97dacf2429 | |||
| 1c189e162a | |||
| f7a0fff869 | |||
| 2f985d0926 | |||
| 2a3c544fba | |||
| 09d133b994 | |||
| 26a4223ecf | |||
| e2943fdcaf | |||
| f1053251b4 | |||
| be1dcaf43c | |||
| a899d988fc | |||
| 06b5b2c514 | |||
| 864a19b79f | |||
| 8974323406 | |||
| 46c9e0103a | |||
| 02203466ed | |||
| 87b22ea1cc | |||
| d26327a930 | |||
| 469d2bdcb7 | |||
| 5516603a0c | |||
| b737adc3da | |||
| f3a8afeee3 | |||
| a4501f86e9 | |||
| 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 | |||
| 077e25d7a8 | |||
| ef84fe97d5 | |||
| fc3653e577 | |||
| d708867c74 | |||
| e6273fa6a4 | |||
| d517279ca2 | |||
| 71284c3e98 | |||
| 85c7dbaf99 | |||
| 7cc21a2b8e | |||
| 2c8d8e2b2e | |||
| d366da4947 | |||
| 02490440ec | |||
| 019ec0e55d | |||
| c8ef38da3c | |||
| b449072a69 | |||
| 35fde21098 | |||
| 10bad0bc84 | |||
| 27492ba093 | |||
| ed6576df4b | |||
| 1c89f9e88a | |||
| 9cdd7fc687 | |||
| 3a5485ea56 | |||
| 955d1df400 | |||
| d39000fa56 | |||
| 231e98efb8 | |||
| 87299de2ab | |||
| 33c9b48bc9 | |||
| 416208c33a | |||
| 7bba8d2862 | |||
| 8b22349d0f | |||
| cd156630a8 | |||
| 769d5739b8 | |||
| 6d29f58ebd | |||
| 2d8027cd28 | |||
| be9547612d | |||
| 67f8ff841d | |||
| 51a7ccc8d0 | |||
| 3fdaa42206 | |||
| 70c783194f | |||
| aec1d2bbe8 | |||
| cabcbef34b | |||
| d952e5400b | |||
| eba908c153 | |||
| 65feda4e04 | |||
| 81e636b1c6 | |||
| 4c4861b2e3 | |||
| 28972421ad | |||
| 3619acbd54 | |||
| c539f1eeef | |||
| 23cf213200 | |||
| a371c6b364 | |||
| d1e58ccf28 | |||
| 0062a28504 | |||
| 9d00a1eb67 | |||
| 7e75640263 | |||
| 32f1cfa634 | |||
| aed5f54710 | |||
| 267fa4acfa | |||
| a4f731da16 | |||
| 8ee9c42848 | |||
| a43335466c | |||
| 1a0b86d056 | |||
| d96cc5c74b | |||
| 54faa2cbdc | |||
| e7e25cb5b7 | |||
| b4afb2f495 | |||
| 2a5e67a461 | |||
| a71dd0b3b8 | |||
| b2d9c2eec6 | |||
| 518262c515 | |||
| 1de5983260 | |||
| 3c5b1eb423 | |||
| 4d195a6378 | |||
| cdbfad060b | |||
| e9eeba944a | |||
| 3c111cd8d6 | |||
| 68c5362024 | |||
| 40ea294663 | |||
| 1b2afcd02c | |||
| 6c5eb09486 | |||
| 221d011b48 | |||
| ad36204dfb | |||
| 70f8599a0e | |||
| 211ec7f3a6 | |||
| 43a75df119 | |||
| 679c6791c7 | |||
| 033616db7a | |||
| 1a09edd8bb | |||
| 0ff7a5cd11 | |||
| 4e0574af35 | |||
| 027dbf35f8 | |||
| a9dc1e232a | |||
| f50cfab3f7 | |||
| 981d9a095d | |||
| d1670673f2 | |||
| 82fa375afc | |||
| 95d0765ccb | |||
| 8f9524a319 | |||
| a680aa97d2 | |||
| 7ca0092501 | |||
| 4d7321941c | |||
| 8d1c5e4b5b | |||
| 1ebcd49601 | |||
| 9ac7753f04 | |||
| 7ca81fe281 | |||
| 1b5762a133 | |||
| e373969b34 | |||
| f16472c415 | |||
| 72169f271f | |||
| b1149bda39 | |||
| 8f838891cb | |||
| e4518cafeb | |||
| 6022161e0c | |||
| dd8b695cdf | |||
| e896be7324 | |||
| 06298418cb | |||
| fdcbbae3b1 | |||
| a719ec5a3e | |||
| 55bf0c04f4 | |||
| 666293f59d | |||
| 4442fda70a | |||
| cf976cef84 | |||
| e2dcbf48af | |||
| 79ba86d8c2 | |||
| 8de6ca33af | |||
| 89faf6e976 | |||
| bc5861ea95 | |||
| cc3a3c451c | |||
| f0956c0cdb | |||
| dcc143c9f8 | |||
| 56603e8076 | |||
| 06922458f1 | |||
| 17b7a6eb89 | |||
| 52b222de50 | |||
| 35d45057ba | |||
| 6a5ba1a607 | |||
| c01c77e11d | |||
| 27a01d4da3 | |||
| 76f3a3cfcb | |||
| 52005d0b19 | |||
| af6f477f15 | |||
| bf2ffd6dfb | |||
| dd6380d49d | |||
| d59fc82cc7 | |||
| 2f62dd2c49 | |||
| 379f8911b5 | |||
| 1a72c30684 | |||
| 6891bdc34e | |||
| c6a7e52a86 | |||
| 951ef5ed72 | |||
| 20f8e59f2b | |||
| 23b35282a9 | |||
| 27c3c0c404 | |||
| df7728707a | |||
| 6bd7f54a8e | |||
| 954175943d | |||
| a1e8af623d | |||
| af625d912a | |||
| 04d61e81ed | |||
| 78fc6be193 | |||
| 969dfa1dd0 | |||
| 19578f2104 | |||
| de60b15d2b | |||
| 7c5ffe3f10 | |||
| 2daf47f202 | |||
| ec8e54d31b | |||
| d538b5c12b | |||
| 4fe24abc51 | |||
| 4644121fe3 | |||
| f75c9ec06a | |||
| e174939cf5 | |||
| b8ecbdd27d | |||
| 100401e0ac | |||
| a5f2ce79e4 | |||
| 4358360362 | |||
| 889fc7d7fe | |||
| 8fec85d4cb | |||
| de744d1f10 | |||
| 4e50099308 | |||
| e17f201e6b | |||
| 14fb775212 | |||
| 9742a2146a | |||
| 270476f4d2 | |||
| b1205c73d5 | |||
| 760019aac6 | |||
| a89df000d0 | |||
| 3278d3518d | |||
| 0f8bf01d30 | |||
| e4132fe469 | |||
| f593df5d1d | |||
| a42153dc14 | |||
| 7dbb17b339 | |||
| 4e226130df | |||
| abf5ec313a | |||
| 2257ceae53 | |||
| e330a7cd3b | |||
| 9316575534 | |||
| 3046127b03 | |||
| 7a4e784701 | |||
| 96a2b406aa | |||
| e2db3cdc5c | |||
| 99fa754e91 | |||
| be28eaf122 | |||
| cd05d5d811 | |||
| f6f7c1702a | |||
| b593293c05 | |||
| 1f1f44766d | |||
| 6ebd768d97 | |||
| bd75c7454c | |||
| 1c2fab1528 | |||
| 92a096a708 | |||
| e331def140 | |||
| 31c1e40ec1 | |||
| 8ced3f838d | |||
| b37bf72eb2 | |||
| c6485f5e92 | |||
| 4d2132cc08 | |||
| cb3dfd6786 | |||
| 0af836f2f5 | |||
| 509184f5ce | |||
| d788ded283 | |||
| 131e257739 | |||
| 9333c006b7 | |||
| 59ca964231 | |||
| 293942b7de | |||
| fce9a94b96 | |||
| a344389500 | |||
| 000d87ccdd | |||
| f241d849b7 | |||
| a315b1190a | |||
| a35a268670 | |||
| dff898e228 | |||
| 9ab67716bc | |||
| cc554991fe | |||
| 7366b543bd | |||
| 480f3d9563 | |||
| 991e4b8b20 | |||
| 2f6551904a | |||
| dc1ee3faaf | |||
| f96196a421 | |||
| 678eeaa3bf | |||
| 87dbda685b | |||
| 954dc49932 | |||
| 0c031588aa | |||
| 6e419b3120 | |||
| de0ddee3fb | |||
| 59fac2fa11 | |||
| ef0d3b3957 | |||
| f34be62af4 | |||
| 151ee93842 | |||
| c89757aa5d | |||
| 2617fcfab1 | |||
| 0528a2d423 | |||
| aa62921986 | |||
| f39ae98a48 | |||
| e10e51ae26 | |||
| 758e941da9 | |||
| 34777b1672 | |||
| a8156d90d8 | |||
| 45527ada14 | |||
| b6b98b1c00 | |||
| d7b98c9762 | |||
| fc9faeb6e5 | |||
| c965fb41b9 | |||
| 379a09b9c9 | |||
| da0b34b2dc | |||
| 6153b68302 | |||
| 3fc60909d2 | |||
| a20ab505ef | |||
| 8f412d5dc7 | |||
| bb7e993d10 | |||
| 8aeceb717c | |||
| 1b2fc0e364 | |||
| 2bf6b59419 | |||
| 5e6080da78 | |||
| a4a23121c8 | |||
| fa6e36cb44 | |||
| 64eb773ab8 | |||
| 841e831ce0 | |||
| 427b54b1eb | |||
| 00e831c8f3 | |||
| a5d5168b07 | |||
| 521dfb83e4 | |||
| d414a27498 | |||
| 7e8ce1c695 | |||
| 302a894cb3 | |||
| 0c213aa860 | |||
| 142deb47cb | |||
| 4390b1c694 | |||
| c26f196318 | |||
| 4cae95a942 | |||
| d07219758f | |||
| 051b2e31b9 | |||
| 6e0ea18ca3 | |||
| 407d633a6c | |||
| a4ae25886a | |||
| ae02066093 | |||
| fd4f628618 | |||
| b389b144c1 | |||
| 95e929220a | |||
| 3d6d2a62f9 | |||
| 60d8d0be50 | |||
| 18f5c6aa95 | |||
| 13f28a9bd8 | |||
| 640c6b8a9c | |||
| 69202b86cd | |||
| 330bab0616 | |||
| c77d0bab6d | |||
| 7ef14602f5 | |||
| 762ef42a48 | |||
| ba07a4188b | |||
| 4a6387b383 | |||
| b7254c7d12 | |||
| 8873503853 | |||
| 430b23bb45 | |||
| 1c785fded8 | |||
| f2bfc50a31 | |||
| 17ffa3eaba | |||
| a6805eeb9a | |||
| b3d7623276 | |||
| df5e61f4bd | |||
| 8cd841220d | |||
| fd5fd05622 | |||
| 6769702d45 | |||
| 2ce16a0594 | |||
| cd2f2c4ae5 | |||
| 0f4e9792d2 | |||
| cf1be5f3ba | |||
| f2c919725a | |||
| 5e5b218e14 | |||
| 0d18b38434 | |||
| 3838f06723 | |||
| d255e08204 | |||
| c2feac4642 | |||
| 93f2605c6d | |||
| c1c80f1000 | |||
| 7555073c14 | |||
| fa607062fa | |||
| 8bfe624f97 | |||
| 32a5880c17 | |||
| d51d403906 | |||
| 1fb42f3c8e | |||
| 87fdfc5048 | |||
| 5f7de8ff5b | |||
| 3e6a2314bd | |||
| deebd9a8cf | |||
| 3e71f31f8e | |||
| f7d4642a44 | |||
| 59a6cae353 | |||
| ef53a299f9 | |||
| c5def9b663 | |||
| 71860612af | |||
| 354a3c6133 | |||
| bc49bfe2ba | |||
| c0e48a29a5 | |||
| 363f865168 | |||
| d6ceeee2a3 | |||
| f6dc7492f9 | |||
| 4b4b1f0ddc | |||
| e5524edc4a | |||
| 75de1e5fd1 | |||
| 9c1c6d3503 | |||
| ee55f066a9 | |||
| e06889a322 | |||
| 7dd26b110b | |||
| de7dbcb622 | |||
| 9678be05a8 | |||
| db8581da57 | |||
| f7423af5f4 | |||
| 518fcfca97 | |||
| ecdada10c0 | |||
| 7ffdf6f514 | |||
| 2b8aea39d7 | |||
| 502d3424b0 | |||
| 33748510fe | |||
| 9f55203d69 | |||
| 241dd14431 | |||
| bf5fded327 | |||
| 7423b9577d | |||
| 54a3c5750e | |||
| 1bf8317398 | |||
| 5a0d7b0d67 | |||
| 64b0e312f3 | |||
| d22aab08cb | |||
| 0368342336 | |||
| 0ccae5ebbc | |||
| e5a8464647 | |||
| 6acb4d4184 | |||
| 2798368099 | |||
| bcdce2bdf5 | |||
| 43773652aa | |||
| 10072200b5 | |||
| a00647f8e7 | |||
| 96429eec00 | |||
| c49e38a58c | |||
| b2047ce0c0 | |||
| 5b60d515e9 | |||
| cf0205caa4 | |||
| c91ab1deb1 | |||
| 2b5dd236aa | |||
| 0658479921 | |||
| ff8b07ac12 | |||
| fb87ee529a | |||
| 1fabc24e45 | |||
| 9ab2cfcb6a | |||
| e81e31fc24 | |||
| e69b7dec7d | |||
| 534e4a4377 | |||
| 3193773583 | |||
| 4d4906228e | |||
| e4a1d7478a | |||
| cf8eaa57cf | |||
| 2211add5e0 | |||
| e432358e1b | |||
| 3ccce80e1d | |||
| 1952f91540 | |||
| 0e1017111e | |||
| b4be8ab83f | |||
| 3b807dae95 | |||
| 9fdaeed69b | |||
| b7d627f0f5 | |||
| 733bbc0b58 | |||
| 17f6147e13 | |||
| 08c4c8667a | |||
| 526791aae7 | |||
| 8fdd6dcccc | |||
| fb4f5819fd | |||
| 58554f3891 | |||
| 5020084663 | |||
| 5aaab01ac9 | |||
| 024f60de9b | |||
| 1ccc46869d | |||
| 3edcb8d03d | |||
| d7189f0f05 | |||
| f19aa7831e | |||
| 601eeb7fbe | |||
| a8f20a407b | |||
| 872a7d9fa8 | |||
| 310b85ad83 | |||
| b8d94ba7eb | |||
| 4c112aa8ae | |||
| df6da4b48a | |||
| c3e8449979 | |||
| d8707bfe01 | |||
| f07940c11f | |||
| 889c3d32c9 | |||
| 1e502c5933 | |||
| f01e31f475 | |||
| 4285f32b94 | |||
| af5bcafa45 | |||
| 909870b321 | |||
| 2b5dd8b77e | |||
| 4d4e4a9706 | |||
| ac82e90dc2 | |||
| 8063141406 | |||
| 5c17e9599b | |||
| 2e54f2166d | |||
| a0bd2ba4a1 | |||
| 38102ac17f | |||
| 139c5869c9 | |||
| 79206420f9 | |||
| e046b972ca | |||
| ea4949b3a2 | |||
| 05d5f0b943 | |||
| 81df84dc37 | |||
| ff9bab99c7 | |||
| 301ea26a03 | |||
| bd7a03b0ca | |||
| 4e0619a269 | |||
| 8b13afeb23 | |||
| ce44feeb40 | |||
| 821e86b875 | |||
| 015e596eda | |||
| 09e535abf4 | |||
| 855f7f0f9a | |||
| 5fa3e3cb7f | |||
| 0bddc2dcac | |||
| 42a8e0e0f0 | |||
| 7b77e07a7d | |||
| db17d27823 | |||
| 362b800f25 | |||
| 29e26d659d | |||
| afa658cc00 | |||
| cde0d466dd | |||
| 4031b55630 | |||
| 86e07156d1 | |||
| 1e8df274ee | |||
| f0153cc4a6 | |||
| 3044c238fd | |||
| ead58390cd | |||
| 504d22ff37 | |||
| cc42f8667f | |||
| 6135b3ce7f | |||
| 3c8efa17d5 | |||
| dccae0aea0 | |||
| 2728236ced | |||
| 76ce1d6b21 | |||
| 94ddebaec0 | |||
| cec165176b | |||
| 99ad837441 | |||
| f8be132ba2 | |||
| 122f5431a6 | |||
| c2884954a4 | |||
| 3a0453c8c5 | |||
| 9d241ab175 | |||
| ee7eed8d3c | |||
| 1125452a8f | |||
| a3712c8f72 | |||
| e2022fab2d | |||
| bcea1be19b | |||
| 8d799203c5 | |||
| 980ce2f2af | |||
| c6bea3faa3 | |||
| 7707f55b25 | |||
| f087bb7182 | |||
| bf269c9abf | |||
| a8c7405f9d | |||
| 43c9232e7e | |||
| 8351c58d7b | |||
| aa86381b80 | |||
| 563840ca58 | |||
| b5b9b688c3 | |||
| 3731223087 | |||
| 72d770c0f3 | |||
| ee4b83fa99 | |||
| ee6e3a9876 | |||
| 17e375bc61 | |||
| a2c8c90a5e | |||
| b376014df8 | |||
| b9ee54f6ad | |||
| 6c7e1900a3 | |||
| 6f929f40f9 | |||
| b6a8930855 | |||
| 7a91b258de | |||
| 35bef76aeb | |||
| 780d0ad9fb | |||
| c0d5dd6dee | |||
| 3e87e625ba | |||
| 56f9403859 | |||
| 8259c79e9c | |||
| be1e2fe7e6 | |||
| 609ee5c70d | |||
| 207cab9a0f | |||
| c80b025ac1 | |||
| 8610917b86 | |||
| fae4bee871 | |||
| b9608498a2 | |||
| fe59c6b0c9 | |||
| b082b048d6 | |||
| 91712cee2a | |||
| 5adfbb2dee | |||
| ec32d09468 | |||
| 919990820e | |||
| 5cc31efa12 | |||
| 5f48b41693 | |||
| 9530eea287 | |||
| ebbf304c94 | |||
| 7c8ac0c2ff | |||
| eefad5e052 | |||
| 9a1e6e29d4 | |||
| 62ab450d98 | |||
| b4a5da4a74 | |||
| ed82480c89 | |||
| 82449c5edc | |||
| b165726bc9 | |||
| 11910d0f28 | |||
| f66e27b077 | |||
| f84570a6fc | |||
| 835beb607d | |||
| c4e2d3fb0f | |||
| eb3d8d9da5 | |||
| 151d548099 | |||
| c5cdc2760f | |||
| a663bf9f19 | |||
| a0f5af46a2 | |||
| 7ddd48d132 | |||
| 18074f15f5 | |||
| bba0424c6d | |||
| 282f6cfbb8 | |||
| ce10a43cc6 | |||
| 5476af5bb3 | |||
| b97b1b61b7 | |||
| 25d2cfd7b8 | |||
| 1b754387e0 | |||
| bcad40069f | |||
| 5aa9061006 | |||
| 873e8cec57 | |||
| f6f96c3aea | |||
| aeed672295 | |||
| 832fbe6d15 | |||
| 03deddf666 | |||
| d06413d1b4 | |||
| 8afa50d585 | |||
| 9f28f1f812 | |||
| 985388fd90 | |||
| e27e10082a | |||
| 4e510d96fc | |||
| c0ec02f062 | |||
| bd27a96bde | |||
| d6aeaf8e9d | |||
| 2b9bba4aa7 | |||
| 58b0991891 | |||
| 59cbbef327 | |||
| 7047c81a2b | |||
| 6e2ab47359 | |||
| f879332e1d | |||
| 6fcafecc61 | |||
| a5af93aef1 | |||
| 4b84fd2a67 | |||
| 924efc0cbd | |||
| 288457b5bd | |||
| d29fa86de6 | |||
| 97be227e3d | |||
| 909d6a54c3 | |||
| 228b6a80dc | |||
| 6936a5f96f | |||
| 740560a50a | |||
| 47c28f0f37 | |||
| 1c859cd7da | |||
| e4a97dd76d | |||
| 4fd1e5ea06 | |||
| 6039aeabde | |||
| 17a384f074 | |||
| 25e8f5ec6a | |||
| eac8cacd42 | |||
| 75193d76a3 | |||
| aa24fd341e | |||
| 81adade05b | |||
| e3808dc986 | |||
| d669b2a1fe | |||
| 2bd8dab240 | |||
| 2b423c2edd | |||
| 1a4faf4bdd | |||
| b70829aceb | |||
| bba771d376 | |||
| 75b18f8bd8 | |||
| 60da404900 | |||
| b75eebd0dc | |||
| 72cbd1167a | |||
| e4e51ebf5b | |||
| dd2096bf1b | |||
| 393a94a7a1 | |||
| ef0023ef39 | |||
| f0994fff75 | |||
| 31f41540c0 | |||
| 81fe13b9c0 | |||
| 332df13b29 | |||
| b3af6df0c5 | |||
| 9392e618c0 | |||
| fd361a39a1 | |||
| f41de59f39 | |||
| c701cf987b | |||
| f05e878600 | |||
| dc028db5ed | |||
| c59d7a7d27 | |||
| a3dd346a02 | |||
| dba8061f71 | |||
| 3da2d961fc | |||
| aa83dc7465 | |||
| 392821c081 | |||
| 7e5fc979cc | |||
| 7ebb555b94 | |||
| 3612a2f9e0 | |||
| 42b67825f8 | |||
| 30a636c840 | |||
| e5722c19a9 | |||
| 6b6a9ab0a9 | |||
| 6da74c6f4e | |||
| 0bafa37f66 | |||
| 6ba6b11f6b | |||
| 739653f37a | |||
| 213d70f2d1 | |||
| dda3c7636b | |||
| 3956578043 | |||
| d11f067392 | |||
| 9f9fe6a231 | |||
| 486a30cb93 | |||
| 01545dc295 | |||
| 165a3799f3 | |||
| 308f809d5d | |||
| 003dbdff02 | |||
| 99f8dbb042 | |||
| 4263ea9733 | |||
| c09b07a21b | |||
| 4e0160648b | |||
| ad367f681d | |||
| a5a70cd65b | |||
| 4ff37cfdad | |||
| 9a1abdefa1 | |||
| 37cc7e7b37 | |||
| 04cbb1e92c | |||
| 5033175808 | |||
| 689928708c | |||
| 98327e6fdf | |||
| 5aef0977c0 | |||
| e6738f1c80 | |||
| b55c1b8f56 | |||
| 3764a4cc9e | |||
| d6bbb9d8dc | |||
| a38e7a00e4 | |||
| 2ec84ae3cf | |||
| f03035e3f9 | |||
| 1d914b8f8a | |||
| ee947b36a2 | |||
| ba393f61e5 | |||
| 796c8e7bef | |||
| fe60de314d | |||
| d237db3302 | |||
| f665b452b0 | |||
| 17750691d6 | |||
| 89ba5b9d15 | |||
| cea44a3f8a | |||
| a99c9aff76 | |||
| 1827ab646c | |||
| db00f7ebec | |||
| 0b93c7b5dc | |||
| 97204f3a3c | |||
| 02a6db0a62 | |||
| 577af4d854 | |||
| 68155142c3 | |||
| 43897e1298 | |||
| bf2c520966 | |||
| ee1528f694 | |||
| 8bd7556c89 | |||
| facbb174f5 | |||
| 9d3ce5307c | |||
| 54f3e9e12d | |||
| e294fc79eb | |||
| a750aaf90a | |||
| be8e09eb9b | |||
| 016d26a6f7 | |||
| 539698c456 | |||
| bcc11b8f0c | |||
| c2a960162e | |||
| c42a3a5fb3 | |||
| 59d6289177 | |||
| 4f028d118d | |||
| b555e35016 | |||
| 26b4c3a2d9 | |||
| 2a5199f851 | |||
| 408dbc2169 | |||
| c9ffcfb1e8 | |||
| 3bd1eedcb8 | |||
| 8500ec7a00 | |||
| 223570a0b7 | |||
| de8c063731 | |||
| 0cffa30286 | |||
| 1d3a282c60 | |||
| 9b6cd955b5 | |||
| 8e1559ac61 | |||
| ce597576ba | |||
| d53a7a5fc4 | |||
| 35bb5cdc92 | |||
| 26e9cc21fd | |||
| 71fd448b7f | |||
| 93e18230f0 | |||
| d305741be2 | |||
| 5830c8d87a | |||
| 5161439536 | |||
| deb6ada6cc | |||
| e72a0546be | |||
| e27b43f03a | |||
| daf4f06a30 | |||
| e5ef93a26d | |||
| b158dff2c6 | |||
| 23bbbce749 | |||
| 898be82aab | |||
| dc9ed37de2 | |||
| b390e54801 | |||
| 9736d2169e | |||
| b507f459b3 | |||
| 51a7053d7e | |||
| 3ba40dd910 | |||
| 248f8e5e70 | |||
| 49b0911aaf | |||
| e4b40c9383 | |||
| 328ac93178 | |||
| d91f86aed5 | |||
| 8119cc06ad | |||
| 94c9d0e276 | |||
| e262dfa14a | |||
| 5e0b63347e | |||
| b7df3bad22 | |||
| 6a56c0c96f | |||
| fd8a94d77c | |||
| 7d38fac16d | |||
| 235ffb03a5 | |||
| fa2702209c | |||
| f9f9f98750 | |||
| 0c46947f4d | |||
| b5b57dfaba | |||
| 39e7812f8b | |||
| 025e8b3f9b | |||
| 35e3a4262b | |||
| 562c8154ff | |||
| e23244181a | |||
| 6aa6c32299 | |||
| fbdabf52e7 | |||
| f4c1f1bcd7 | |||
| 965c19d426 | |||
| 239a876fcf | |||
| d53165881f | |||
| 40733ea1fc | |||
| 66a16ee508 | |||
| b1a9a8ac8d | |||
| 06a2f9f336 | |||
| 978bc58c11 | |||
| a5577e80f1 | |||
| 9daf5a013c | |||
| 72e2cb8a64 | |||
| db819698af | |||
| 09e427ab97 | |||
| a6b3a7ea5a | |||
| 4d08339f79 | |||
| 2ba32a8c94 | |||
| ebedd5e181 | |||
| 357c355e26 | |||
| faca159721 | |||
| 3556528932 | |||
| 8513e46fdc | |||
| 323eced2a4 | |||
| 6a87539ca3 | |||
| fe725b6795 | |||
| 02862a770f | |||
| a7759ab8e9 | |||
| da1b2051dd | |||
| 4fdc596474 | |||
| d0c710b7e1 | |||
| 41ee9dcd99 | |||
| 506ce87f5f | |||
| 08e42ebfe5 | |||
| 699d27afd2 | |||
| 4a64ce0bed | |||
| b3b94d29b5 | |||
| 3a30516088 | |||
| 6f469737f3 | |||
| 183720d1e5 | |||
| b2dcc66bd0 | |||
| 5c67be30de | |||
| 4ad4e2c29c | |||
| d1f805d178 | |||
| 73071119fa | |||
| 97c52834f5 | |||
| 3e472e454a | |||
| 7ddab31337 | |||
| fd5b9be523 | |||
| f9dd870067 | |||
| 4908acd7ac | |||
| 87486f6825 | |||
| c721c14e27 | |||
| 3521af9792 | |||
| ff94dba348 | |||
| 31d0a45555 | |||
| 41c1473e04 | |||
| d5f12466b2 | |||
| bdd9ef6b40 | |||
| 9b6895ec68 | |||
| a3854561fc | |||
| a66df74ec9 | |||
| eb4b31e876 | |||
| 6015b9a1dc | |||
| 146d42bbe9 | |||
| 16b14bc424 | |||
| a37e4ca232 | |||
| 8103c16064 | |||
| 6ae41b0caa | |||
| ba81f31027 | |||
| 71c72e26e7 | |||
| 97828f465d | |||
| ec37803572 | |||
| b7a54eff7a | |||
| 9604ce297c | |||
| 5ad961d80e | |||
| 843ec2fef8 | |||
| 1b3e90b669 | |||
| 55aadb73f1 | |||
| e3d87c70c4 | |||
| 8b1205f79e | |||
| 291f5d247c | |||
| ad63825194 | |||
| b0e0cd107d | |||
| 5f60cd8d4d | |||
| d0e17ccab7 | |||
| 38a4643cf3 | |||
| 938adca022 | |||
| e2ec80134e | |||
| 903f166041 | |||
| a9bdbfda4e | |||
| 378349b870 | |||
| 190ce716ff | |||
| d2c3a87fa8 | |||
| 2d5acbbf45 | |||
| 4e973099f9 | |||
| ee4f43cc59 | |||
| 3e64b7400e | |||
| c44daa759c | |||
| 17c662b10f | |||
| 3cfbb69dd9 | |||
| 470668265b | |||
| b6ced30d70 | |||
| d3e0f1e14d | |||
| 910350ba3a | |||
| 8dcf30e776 | |||
| 30d4bcd6a1 | |||
| 66300cbe70 | |||
| 50ae719f24 | |||
| dccad778fb | |||
| f163e31cd2 | |||
| 5499079ada | |||
| 8d1277db1b | |||
| 34fcac25c2 | |||
| cb0516cae8 | |||
| 4fdad05252 | |||
| dc785b4fe1 | |||
| 8df7e1762a | |||
| 43d9b41648 | |||
| 880559f94a | |||
| 6f04ddce87 | |||
| 6eb065f7c9 | |||
| 17ebad9141 | |||
| 9bcc799b0b | |||
| f247410ae4 | |||
| 2f3bb2ec34 | |||
| 5c47170ef4 | |||
| 29d152b312 | |||
| aa48f0f5c6 | |||
| 05ea683fcf | |||
| 65163a2477 | |||
| 9dc4c46b99 | |||
| 69029e6f72 | |||
| faf8579b41 | |||
| ed6dff3b5e | |||
| 2dd2623257 | |||
| 82dfecf04c | |||
| bb5bb23025 | |||
| c73e9b3cb5 | |||
| c28ec0b1d8 | |||
| a587ac4b4c | |||
| 0f19b338b6 | |||
| 9453e806db | |||
| 1bd072bf0a | |||
| 9315fd6211 | |||
| 1decb3764f | |||
| 012312892a | |||
| c9f6a753ec | |||
| 9f6e9f791c | |||
| a297cdb79a | |||
| e0ed760cf9 | |||
| 1c2549c64f | |||
| 433bc9217d | |||
| 514e12580d | |||
| faf38ef8e3 | |||
| 48741a5364 | |||
| 03ff908de1 | |||
| 5eed9dae40 | |||
| 47988ec0da | |||
| b29dac3753 | |||
| 3e3e1a7cf2 | |||
| 79e6977bab | |||
| 0c4ee74254 | |||
| 45d9dbbfcf | |||
| 2428449ab4 | |||
| f863da105b | |||
| d63b2c3b12 | |||
| 15496663f3 | |||
| 340631eb9b | |||
| adcd835642 | |||
| ff5d2e6047 | |||
| bd569dad2f | |||
| 71ab3196ea | |||
| b051815b3c | |||
| 991b3356bb | |||
| 58ad37c056 | |||
| 65c091bb63 | |||
| 9b389332be | |||
| 1093001841 | |||
| a3db8e50f5 | |||
| db15e8684c | |||
| 00ac368bba | |||
| f2face9782 | |||
| 923d57b377 | |||
| 447325e5a1 | |||
| bf712e893e | |||
| 27f9a527bc | |||
| bde14012d9 | |||
| 12a32b9fb4 | |||
| 4ad081e0c6 | |||
| 936a3a7ece | |||
| 98f36936d0 | |||
| f6f012c42c | |||
| a3e6c09268 | |||
| 10cb46c9f9 | |||
| 95aa9cb9ab | |||
| 638a0ddae1 | |||
| d321833335 | |||
| b8cba0dc4c | |||
| bd8ccb4a05 | |||
| 895895da04 | |||
| 09d5df2856 | |||
| 668f225528 | |||
| 1cd71a6b50 | |||
| f041f79ae3 | |||
| ef3ac96b2c | |||
| 59f527e6de | |||
| 16a082b17f | |||
| a24d28b0e2 | |||
| 910f11f688 | |||
| e00de99e31 | |||
| f80af39e0e | |||
| 5bba3cb3eb | |||
| d4261d4ccf | |||
| 8b854e3abd | |||
| 4064155567 | |||
| 6243201f2d | |||
| c5a2944d68 | |||
| 1405b7a433 | |||
| be00670b7e | |||
| 6f2c02d283 | |||
| 309526e7b9 |
@@ -0,0 +1,19 @@
|
||||
**/.git
|
||||
**/.gitlab
|
||||
**/.cache
|
||||
|
||||
buildAllJars
|
||||
|
||||
**/_Misc Files
|
||||
*.bat
|
||||
*.md
|
||||
*.sh
|
||||
*.txt
|
||||
|
||||
coreSubProjects/*.md
|
||||
coreSubProjects/*.txt
|
||||
|
||||
**/.gitignore
|
||||
**/.gitattributes
|
||||
**/.gitlab-cy.yml
|
||||
**/.gitmodules
|
||||
@@ -0,0 +1,700 @@
|
||||
# DH Main
|
||||
root = true
|
||||
|
||||
# Note: please keep this and the core .editorconfig in sync
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
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
|
||||
@@ -1,26 +1,46 @@
|
||||
# eclipse
|
||||
bin
|
||||
*.launch
|
||||
.settings
|
||||
.metadata
|
||||
build/
|
||||
*.ipr
|
||||
run/
|
||||
*.iws
|
||||
out/
|
||||
*.iml
|
||||
.gradle/
|
||||
.gradle-cache/
|
||||
output/
|
||||
bin/
|
||||
libs/
|
||||
.architectury-transformer/
|
||||
|
||||
.classpath
|
||||
.project
|
||||
.idea/
|
||||
classes/
|
||||
.metadata
|
||||
.vscode
|
||||
.settings
|
||||
*.launch
|
||||
hs_err_pid*
|
||||
|
||||
# idea
|
||||
out
|
||||
*.ipr
|
||||
*.iws
|
||||
*.iml
|
||||
.idea
|
||||
**/src/generated/
|
||||
Merged/
|
||||
# Folder created by the buildAll scripts
|
||||
buildAllJars/
|
||||
|
||||
# gradle
|
||||
build
|
||||
.gradle
|
||||
relocate_natives/.venv/
|
||||
relocate_natives/__pycache__/
|
||||
relocate_natives/apple-codesign/
|
||||
|
||||
# other
|
||||
eclipse
|
||||
run
|
||||
# file from notepad++
|
||||
*.bak
|
||||
|
||||
# Files from Forge MDK
|
||||
logs
|
||||
forge*changelog.txt
|
||||
# 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
|
||||
|
||||
@@ -0,0 +1,97 @@
|
||||
# use Eclipse's JDK
|
||||
# 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:
|
||||
- build
|
||||
- api
|
||||
- pages
|
||||
|
||||
variables:
|
||||
# Pull core when building
|
||||
GIT_SUBMODULE_STRATEGY: recursive
|
||||
|
||||
|
||||
# These can be extended so code is a bit less duplicated
|
||||
.build_java:
|
||||
#image: eclipse-temurin:17
|
||||
cache:
|
||||
key: "gradleCache_$CI_JOB_NAME_SLUG"
|
||||
policy: pull-push
|
||||
paths:
|
||||
- .gradle
|
||||
- cache/
|
||||
allow_failure: true
|
||||
retry:
|
||||
max: 2
|
||||
when:
|
||||
- runner_system_failure
|
||||
- stuck_or_timeout_failure
|
||||
|
||||
|
||||
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.1", "1.21.3", "1.21.4", "1.21.5", "1.21.6", "1.21.8"]
|
||||
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/;
|
||||
- cp ./fabric/build/libs/* ./forge/build/libs/* ./neoforge/build/libs/* ./build/merged/* . || true
|
||||
artifacts:
|
||||
name: "NightlyBuild_${MC_VER}-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
|
||||
paths:
|
||||
- ./*.jar
|
||||
exclude:
|
||||
- ./*-all.jar
|
||||
- ./*-dev.jar
|
||||
- ./*-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/;
|
||||
- cp ./coreSubProjects/api/build/libs/merged/* .
|
||||
artifacts:
|
||||
name: "NightlyBuild_Api-${CI_COMMIT_SHORT_SHA}-${CI_COMMIT_TIMESTAMP}"
|
||||
paths:
|
||||
- ./*.jar
|
||||
exclude:
|
||||
- ./*-all.jar
|
||||
- ./*-dev.jar
|
||||
- ./*-sources.jar
|
||||
expire_in: 1 day
|
||||
when: always
|
||||
extends: .build_java
|
||||
|
||||
|
||||
# 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
|
||||
@@ -0,0 +1,37 @@
|
||||
## 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]"
|
||||
Or click the checkbox once the issue has been created.
|
||||
-->
|
||||
|
||||
1. [ ] Check the FAQ to see if your issue has already been reported and has a solution:
|
||||
[Problems-and-solutions](https://gitlab.com/distant-horizons-team/distant-horizons/-/wikis/1-user-guide/1-frequently-asked-questions/2-problems-and-solutions/Problems-and-Solutions)
|
||||
|
||||
2. [ ] Make sure you are not using any mods on the incompatible list:
|
||||
[Mod support FAQ](https://gitlab.com/distant-horizons-team/distant-horizons/-/wikis/1-user-guide/1-frequently-asked-questions/4-mod-support/Mod-Support)
|
||||
|
||||
3. [ ] Check the existing issues to verify that your bug hasn't already been submitted:
|
||||
[Issues](https://gitlab.com/distant-horizons-team/distant-horizons/-/issues)
|
||||
|
||||
4. [ ] Upload Minecraft's crash report and/or log. \
|
||||
Minecraft crash reports are located in: `.minecraft/crash-reports` \
|
||||
Minecraft logs are located in: `.minecraft/logs`
|
||||
|
||||
5. [ ] Upload your Distant Horizons Config. \
|
||||
The config is found in: `.minecraft/configs/DistantHorizons.toml`
|
||||
|
||||
6. [ ] Fill out the information below:
|
||||
|
||||
* **minecraft version**:
|
||||
|
||||
* **Distant Horizons version**:
|
||||
|
||||
* **Mod loader**:
|
||||
|
||||
* **Installed mods (list the smallest number of mods that you can use to re-create the bug)**:
|
||||
|
||||
* **Describe the bug**:
|
||||
|
||||
* **Steps to reproduce the bug**:
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
Before creating an issue, please select the appropriate template from the dropdown above.
|
||||
|
||||
The template will walk you through submitting a bug, feature, or improvement request.
|
||||
@@ -0,0 +1,5 @@
|
||||
- [ ] Check the existing [feature requests](https://gitlab.com/distant-horizons-team/distant-horizons/-/issues?sort=updated_desc&state=opened&label_name%5B%5D=Feature) to verify that your feature hasn't already been suggested.
|
||||
|
||||
1. **Describe the feature**:
|
||||
|
||||
2. **Describe why this feature should be added**:
|
||||
@@ -0,0 +1,3 @@
|
||||
1. Check the existing [improvement requests](https://gitlab.com/distant-horizons-team/distant-horizons/-/issues?sort=updated_desc&state=all&label_name%5B%5D=Improvement) to verify that your improvement hasn't already been suggested.
|
||||
|
||||
2. **Describe the improvement**:
|
||||
@@ -0,0 +1,3 @@
|
||||
[submodule "coreSubProjects"]
|
||||
path = coreSubProjects
|
||||
url = https://gitlab.com/jeseibel/distant-horizons-core.git
|
||||
@@ -0,0 +1,7 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Fabric Client & Server" type="CompoundRunConfigurationType">
|
||||
<toRun name="Fabric Client (:fabric)" type="Application" />
|
||||
<toRun name="Fabric Server (:fabric)" type="Application" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -0,0 +1,7 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Forge Client & Server" type="CompoundRunConfigurationType">
|
||||
<toRun name="Forge Client (gradle)" type="GradleRunConfiguration" />
|
||||
<toRun name="Forge Server (gradle)" type="GradleRunConfiguration" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -0,0 +1,24 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Forge Client (gradle)" type="GradleRunConfiguration" factoryName="Gradle">
|
||||
<ExternalSystemSettings>
|
||||
<option name="executionName" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="externalSystemIdString" value="GRADLE" />
|
||||
<option name="scriptParameters" value="" />
|
||||
<option name="taskDescriptions">
|
||||
<list />
|
||||
</option>
|
||||
<option name="taskNames">
|
||||
<list>
|
||||
<option value="forge:runClient" />
|
||||
</list>
|
||||
</option>
|
||||
<option name="vmOptions" />
|
||||
</ExternalSystemSettings>
|
||||
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
||||
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||
<DebugAllEnabled>false</DebugAllEnabled>
|
||||
<RunAsTest>false</RunAsTest>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -0,0 +1,24 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Forge Server (gradle)" type="GradleRunConfiguration" factoryName="Gradle">
|
||||
<ExternalSystemSettings>
|
||||
<option name="executionName" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="externalSystemIdString" value="GRADLE" />
|
||||
<option name="scriptParameters" value="" />
|
||||
<option name="taskDescriptions">
|
||||
<list />
|
||||
</option>
|
||||
<option name="taskNames">
|
||||
<list>
|
||||
<option value="forge:runServer" />
|
||||
</list>
|
||||
</option>
|
||||
<option name="vmOptions" />
|
||||
</ExternalSystemSettings>
|
||||
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
||||
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||
<DebugAllEnabled>false</DebugAllEnabled>
|
||||
<RunAsTest>false</RunAsTest>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -0,0 +1,7 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Neoforge Client & Server" type="CompoundRunConfigurationType">
|
||||
<toRun name="Neoforge Client (gradle)" type="GradleRunConfiguration" />
|
||||
<toRun name="Neoforge Server (gradle)" type="GradleRunConfiguration" />
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -0,0 +1,24 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Neoforge Client (gradle)" type="GradleRunConfiguration" factoryName="Gradle">
|
||||
<ExternalSystemSettings>
|
||||
<option name="executionName" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="externalSystemIdString" value="GRADLE" />
|
||||
<option name="scriptParameters" value="" />
|
||||
<option name="taskDescriptions">
|
||||
<list />
|
||||
</option>
|
||||
<option name="taskNames">
|
||||
<list>
|
||||
<option value="neoforge:runClient" />
|
||||
</list>
|
||||
</option>
|
||||
<option name="vmOptions" />
|
||||
</ExternalSystemSettings>
|
||||
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
||||
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||
<DebugAllEnabled>false</DebugAllEnabled>
|
||||
<RunAsTest>false</RunAsTest>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -0,0 +1,24 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="Neoforge Server (gradle)" type="GradleRunConfiguration" factoryName="Gradle">
|
||||
<ExternalSystemSettings>
|
||||
<option name="executionName" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="externalSystemIdString" value="GRADLE" />
|
||||
<option name="scriptParameters" value="" />
|
||||
<option name="taskDescriptions">
|
||||
<list />
|
||||
</option>
|
||||
<option name="taskNames">
|
||||
<list>
|
||||
<option value="neoforge:runServer" />
|
||||
</list>
|
||||
</option>
|
||||
<option name="vmOptions" />
|
||||
</ExternalSystemSettings>
|
||||
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
||||
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||
<DebugAllEnabled>false</DebugAllEnabled>
|
||||
<RunAsTest>false</RunAsTest>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -0,0 +1,24 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="distant-horizons [build]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
|
||||
<ExternalSystemSettings>
|
||||
<option name="executionName" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="externalSystemIdString" value="GRADLE" />
|
||||
<option name="scriptParameters" value="" />
|
||||
<option name="taskDescriptions">
|
||||
<list />
|
||||
</option>
|
||||
<option name="taskNames">
|
||||
<list>
|
||||
<option value="build" />
|
||||
</list>
|
||||
</option>
|
||||
<option name="vmOptions" />
|
||||
</ExternalSystemSettings>
|
||||
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
||||
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||
<DebugAllEnabled>false</DebugAllEnabled>
|
||||
<RunAsTest>false</RunAsTest>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -0,0 +1,24 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="distant-horizons [clean]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
|
||||
<ExternalSystemSettings>
|
||||
<option name="executionName" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="externalSystemIdString" value="GRADLE" />
|
||||
<option name="scriptParameters" value="" />
|
||||
<option name="taskDescriptions">
|
||||
<list />
|
||||
</option>
|
||||
<option name="taskNames">
|
||||
<list>
|
||||
<option value="clean" />
|
||||
</list>
|
||||
</option>
|
||||
<option name="vmOptions" />
|
||||
</ExternalSystemSettings>
|
||||
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
||||
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||
<DebugAllEnabled>false</DebugAllEnabled>
|
||||
<RunAsTest>false</RunAsTest>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -0,0 +1,24 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="distant-horizons [core:build]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
|
||||
<ExternalSystemSettings>
|
||||
<option name="executionName" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="externalSystemIdString" value="GRADLE" />
|
||||
<option name="scriptParameters" value="" />
|
||||
<option name="taskDescriptions">
|
||||
<list />
|
||||
</option>
|
||||
<option name="taskNames">
|
||||
<list>
|
||||
<option value="core:build" />
|
||||
</list>
|
||||
</option>
|
||||
<option name="vmOptions" />
|
||||
</ExternalSystemSettings>
|
||||
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
||||
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||
<DebugAllEnabled>false</DebugAllEnabled>
|
||||
<RunAsTest>false</RunAsTest>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -0,0 +1,24 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="distant-horizons [fabric:runClient]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
|
||||
<ExternalSystemSettings>
|
||||
<option name="executionName" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="externalSystemIdString" value="GRADLE" />
|
||||
<option name="scriptParameters" value="" />
|
||||
<option name="taskDescriptions">
|
||||
<list />
|
||||
</option>
|
||||
<option name="taskNames">
|
||||
<list>
|
||||
<option value="fabric:runClient" />
|
||||
</list>
|
||||
</option>
|
||||
<option name="vmOptions" />
|
||||
</ExternalSystemSettings>
|
||||
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
||||
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||
<DebugAllEnabled>false</DebugAllEnabled>
|
||||
<RunAsTest>false</RunAsTest>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -0,0 +1,24 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="distant-horizons [forge:runClient]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
|
||||
<ExternalSystemSettings>
|
||||
<option name="executionName" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="externalSystemIdString" value="GRADLE" />
|
||||
<option name="scriptParameters" value="" />
|
||||
<option name="taskDescriptions">
|
||||
<list />
|
||||
</option>
|
||||
<option name="taskNames">
|
||||
<list>
|
||||
<option value="forge:runClient" />
|
||||
</list>
|
||||
</option>
|
||||
<option name="vmOptions" />
|
||||
</ExternalSystemSettings>
|
||||
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
||||
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||
<DebugAllEnabled>false</DebugAllEnabled>
|
||||
<RunAsTest>false</RunAsTest>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -0,0 +1,24 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="distant-horizons [mergeJars]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
|
||||
<ExternalSystemSettings>
|
||||
<option name="executionName" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="externalSystemIdString" value="GRADLE" />
|
||||
<option name="scriptParameters" value="" />
|
||||
<option name="taskDescriptions">
|
||||
<list />
|
||||
</option>
|
||||
<option name="taskNames">
|
||||
<list>
|
||||
<option value="mergeJars" />
|
||||
</list>
|
||||
</option>
|
||||
<option name="vmOptions" />
|
||||
</ExternalSystemSettings>
|
||||
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
||||
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||
<DebugAllEnabled>false</DebugAllEnabled>
|
||||
<RunAsTest>false</RunAsTest>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -0,0 +1,24 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="distant-horizons [neoforge:runClient]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
|
||||
<ExternalSystemSettings>
|
||||
<option name="executionName" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="externalSystemIdString" value="GRADLE" />
|
||||
<option name="scriptParameters" value="" />
|
||||
<option name="taskDescriptions">
|
||||
<list />
|
||||
</option>
|
||||
<option name="taskNames">
|
||||
<list>
|
||||
<option value="neoforge:runClient" />
|
||||
</list>
|
||||
</option>
|
||||
<option name="vmOptions" />
|
||||
</ExternalSystemSettings>
|
||||
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
||||
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||
<DebugAllEnabled>false</DebugAllEnabled>
|
||||
<RunAsTest>false</RunAsTest>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -0,0 +1,24 @@
|
||||
<component name="ProjectRunConfigurationManager">
|
||||
<configuration default="false" name="distant-horizons [test]" type="GradleRunConfiguration" factoryName="Gradle" nameIsGenerated="true">
|
||||
<ExternalSystemSettings>
|
||||
<option name="executionName" />
|
||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
||||
<option name="externalSystemIdString" value="GRADLE" />
|
||||
<option name="scriptParameters" value="" />
|
||||
<option name="taskDescriptions">
|
||||
<list />
|
||||
</option>
|
||||
<option name="taskNames">
|
||||
<list>
|
||||
<option value="test" />
|
||||
</list>
|
||||
</option>
|
||||
<option name="vmOptions" />
|
||||
</ExternalSystemSettings>
|
||||
<ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>
|
||||
<ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>
|
||||
<DebugAllEnabled>false</DebugAllEnabled>
|
||||
<RunAsTest>false</RunAsTest>
|
||||
<method v="2" />
|
||||
</configuration>
|
||||
</component>
|
||||
@@ -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] =========="
|
||||
@@ -0,0 +1 @@
|
||||
Distant Horizons logos © 2024 by Pankakes are licensed under CC BY-SA 4.0
|
||||
@@ -0,0 +1,165 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
@@ -1,68 +1,210 @@
|
||||
# Distant Horizons
|
||||
# <img src="https://gitlab.com/distant-horizons-team/distant-horizons-core/-/raw/main/_Misc%20Files/logo%20files/new/SVG/Distant-Horizons.svg" height="128px">
|
||||
_See farther without turning your game into a slide show._
|
||||
|
||||
This mod adds a Level Of Detail (LOD) system to Minecraft.\
|
||||
This implementation renders simplified chunks outside the normal render distance\
|
||||
allowing for an increased view distance without harming performance.
|
||||
<br>
|
||||
|
||||
Or in other words: this mod lets you see farther without turning your game into a slide show.\
|
||||
If you want to see a quick demo, check out a video covering the mod here:
|
||||
# What is Distant Horizons?
|
||||
|
||||
[](https://www.youtube.com/watch?v=MDWcEvdUGUE)
|
||||
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.
|
||||
|
||||
Below is a video demonstrating the system:
|
||||
|
||||
Forge version: 1.16.5-36.1.0
|
||||
<a href="https://youtu.be/SxQdbtjGEsc" target="_blank"></a>
|
||||
|
||||
Notes:\
|
||||
This version has been confirmed to work in Eclipse and Retail Minecraft.\
|
||||
(Retail running forge version 1.16.5-36.1.0)
|
||||
<br>
|
||||
|
||||
## Minecraft and Library Versions
|
||||
|
||||
## source code installation
|
||||
### This branch supports the following versions of Minecraft:
|
||||
|
||||
See the Forge Documentation online for more detailed instructions:\
|
||||
http://mcforge.readthedocs.io/en/latest/gettingstarted/
|
||||
#### 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. Create a system variable called "JAVA_MC_HOME" with the location of the JDK 1.8.0_251 (This is needed for gradle to work correctly)
|
||||
2. replace JAVA_HOME with JAVA_MC_HOME in gradle.bat
|
||||
3. open a command line in the project folder
|
||||
#### 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
|
||||
|
||||
**If using Ecplise:**
|
||||
1. run the command: `./gradlew geneclipseruns`
|
||||
2. run the command: `./gradlew eclipse`
|
||||
3. Make sure eclipse has the JDK 1.8.0_251 installed. (This is needed so that eclipse can run minecraft)
|
||||
4. Import the project into eclipse
|
||||
#### 1.20.1, 1.20
|
||||
Fabric: 0.14.24\
|
||||
Fabric API: 0.90.4+1.20.1\
|
||||
Forge: 47.2.1\
|
||||
Parchment: 1.20.1:2023.09.03\
|
||||
Modmenu: 7.2.2
|
||||
|
||||
#### 1.19.4
|
||||
Fabric: 0.14.24\
|
||||
Fabric API: 0.87.1+1.19.4\
|
||||
Forge: 45.2.4\
|
||||
Parchment: 1.19.4:2023.06.26\
|
||||
Modmenu: 6.3.1
|
||||
|
||||
#### 1.19.2
|
||||
Fabric: 0.14.24\
|
||||
Fabric API: 0.76.1+1.19.2\
|
||||
Forge: 43.3.2\
|
||||
Parchment: 1.19.2:2022.11.27\
|
||||
Modmenu: 4.2.0-beta.2
|
||||
|
||||
#### 1.18.2
|
||||
Fabric: 0.14.24\
|
||||
Fabric API: 0.76.0+1.18.2\
|
||||
Forge: 40.2.10\
|
||||
Parchment: 1.18.2:2022.11.06\
|
||||
Modmenu: 3.2.5
|
||||
|
||||
#### 1.17.1, 1.17
|
||||
Fabric: 0.14.24\
|
||||
Fabric API: 0.46.1+1.17\
|
||||
Forge: 37.1.1\
|
||||
Parchment: 1.17.1:2021.12.12\
|
||||
Modmenu: 2.0.14
|
||||
|
||||
#### 1.16.5, 1.16.4
|
||||
Fabric: 0.14.24\
|
||||
Fabric API: 0.42.0+1.16\
|
||||
Forge: 36.2.39\
|
||||
Parchment: 1.16.5:2022.03.06\
|
||||
Modmenu: 1.16.22
|
||||
|
||||
### Versions no longer supported
|
||||
- 1.18.1, 1.18
|
||||
- 1.19.1, 1.19
|
||||
- 1.19.3
|
||||
|
||||
<br>
|
||||
|
||||
### Plugin and Library versions
|
||||
|
||||
Gradle: 8.5\
|
||||
Fabric loom: 1.4-SNAPSHOT\
|
||||
Architectury loom (Forge gradle replacement): 1.4-SNAPSHOT\
|
||||
Sponge vanilla gradle: 0.2.1-SNAPSHOT\
|
||||
Java Preprocessor plugin: Manifold Preprocessor
|
||||
|
||||
<br>
|
||||
|
||||
## Source Code Installation
|
||||
|
||||
### Prerequisites
|
||||
|
||||
* A Java Development Kit (JDK) for Java 17 (recommended) or newer. <br>
|
||||
Visit https://www.oracle.com/java/technologies/downloads/ for installers.
|
||||
* Git or someway to clone git projects. <br>
|
||||
Visit https://git-scm.com/ for installers.
|
||||
* (Not required) Any Java IDE with plugins that support Manifold, for example IntelliJ IDEA.
|
||||
|
||||
**If using IntelliJ:**
|
||||
1. open IDEA and import the build.gradle
|
||||
2. run the command: `./gradlew genIntellijRuns`
|
||||
3. refresh the Gradle project in IDEA if required
|
||||
1. Install the Manifold plugin
|
||||
2. Open IDEA and import the build.gradle
|
||||
3. Refresh the Gradle project in IDEA if required
|
||||
|
||||
**If using Eclipse: (Note that Eclipse doesn't support Manifold's preprocessor!)**
|
||||
1. Run the command: `./gradlew geneclipseruns`
|
||||
2. Run the command: `./gradlew eclipse`
|
||||
3. Make sure eclipse has the JDK 17 installed. (This is needed so that eclipse can run minecraft)
|
||||
4. Import the project into eclipse
|
||||
|
||||
<br>
|
||||
|
||||
## 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 IntelliJ, you will also need to do a gradle sync if it didn't happen automatically.
|
||||
|
||||
<br>
|
||||
|
||||
## Compiling
|
||||
|
||||
1. open a command line in the project folder
|
||||
2. run the command: `./gradlew build`
|
||||
3. the compiled jar file will be in the folder `build\libs`
|
||||
Prerequisites:
|
||||
- JDK 17 or newer
|
||||
|
||||
From the File Explorer:
|
||||
1. Download and extract the project zip
|
||||
2. Download the core from https://gitlab.com/distant-horizons-team/distant-horizons-core and extract into a folder called `coreSubProjects`
|
||||
3. Open a terminal emulator in the project folder (On Windows you can type `cmd` in the title bar)
|
||||
4. Run the commands: `./gradlew assemble` (You may need to use a `.\` on Windows)
|
||||
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/distant-horizons-team/distant-horizons.git`
|
||||
2. `cd distant-horizons`
|
||||
3. `./gradlew assemble`
|
||||
4. `./gradlew mergeJars`
|
||||
5. The compiled jar file will be in the folder `Merged`
|
||||
|
||||
Run tests with: `./gradlew test`
|
||||
|
||||
>Note: You can add the argument `-PmcVer=?` to tell gradle to build a selected MC version instead of having to modify the `gradle.properties` file.\
|
||||
> For example: `./gradlew assemble -PmcVer=1.18.2`
|
||||
|
||||
<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
|
||||
|
||||
`./gradlew --refresh-dependencies` to refresh local dependencies.
|
||||
|
||||
`./gradlew clean` to reset everything (this does not affect your code) and then start the process again.
|
||||
`./gradlew clean` to delete any compiled code.
|
||||
|
||||
<br>
|
||||
|
||||
## Note to self
|
||||
|
||||
The Minecraft source code is NOT added to your workspace in an editable way. Minecraft is treated like a normal Library. Sources are there for documentation and research purposes only.
|
||||
|
||||
Source code uses Mojang mappings.
|
||||
Source code uses Mojang mappings & [Parchment](https://parchmentmc.org/) mappings.
|
||||
|
||||
The source code can be 'created' with the `./eclipse` command and can be found in the following path:\
|
||||
`minecraft-lod-mod\build\fg_cache\mcp\ VERSION \joined\ RANDOM_STRING \patch\output.jar`
|
||||
To generate the source code run `./gradlew genSources` <br>
|
||||
If your IDE fails to auto-detect the source jars when browsing Minecraft classes; manually select the JAR file ending with -sources.jar when prompted by your IDE. <br>
|
||||
(In IntelliJ it's at the top where it says "choose sources" when browsing a Minecraft class)
|
||||
|
||||
<br>
|
||||
|
||||
## Other Useful commands
|
||||
|
||||
Run the standalone jar: `./gradlew run` <br>
|
||||
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)
|
||||
|
||||
<br>
|
||||
|
||||
## Open Source Acknowledgements
|
||||
|
||||
XZ for Java (data compression)\
|
||||
https://tukaani.org/xz/java.html
|
||||
Forgix (To merge multiple mod versions into one jar) [_Formerly_ [_DHJarMerger_](https://github.com/Ran-helo/DHJarMerger)]\
|
||||
https://github.com/PacifistMC/Forgix
|
||||
|
||||
LZ4 for Java (data compression)\
|
||||
https://github.com/lz4/lz4-java
|
||||
|
||||
NightConfig for JSON & TOML (config handling)\
|
||||
https://github.com/TheElectronWill/night-config
|
||||
|
||||
SVG Salamander for SVG support (not being used atm)\
|
||||
https://github.com/blackears/svgSalamander
|
||||
|
||||
sqlite-jdbc\
|
||||
https://github.com/xerial/sqlite-jdbc
|
||||
|
||||
@@ -1,390 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<profiles version="21">
|
||||
<profile kind="CodeFormatterProfile" name="Eclipse (James' Edit)" version="21">
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_ellipsis" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_declarations" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_for_statment" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_block_boundaries" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_for_parameter" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_package" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_while" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_annotation_type_member_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_javadoc_comments" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indentation.size" value="4"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_enum_constant_declaration" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.align_with_spaces" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation" value="2"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_before_code_block" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_switch_case_expressions" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_package" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_local_declarations" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_enum_constant" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_root_tags" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_or_operator_multicatch" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.enabling_tag" value="@formatter:on"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.count_line_length_from_starting_position" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_record_components" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_method_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_parameter" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_multiplicative_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_then_statement_on_same_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_explicitconstructorcall_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_prefix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_brace_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_method" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameterized_type_references" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_logical_operator" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_parenthesized_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_annotation_declaration_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_record_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_enum_constant" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_multiplicative_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_and_in_type_parameter" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_assignment_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_for" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.preserve_white_space_between_code_and_line_comments" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_local_variable" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_abstract_method" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_enum_constant_declaration_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.align_variable_declarations_on_columns" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_union_type_in_multicatch" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_method_body" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_else_statement_on_same_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_catch_clause" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_parameterized_type_reference" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_explicit_constructor_call" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiplicative_operator" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_anonymous_type_declaration_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_switch_case_expressions" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_shift_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_annotation_declaration_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block" value="next_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_code_block" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_bitwise_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.put_empty_statement_on_new_line" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_constructor_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_parameters" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_loops" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_block_comment" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_simple_for_body_on_same_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_at_end_of_file_if_missing" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_unary_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.format_line_comment_starting_on_first_column" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_annotation" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_ellipsis" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_try_resources" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_assert" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_enum_constant" value="49"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_and_in_type_parameter" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.text_block_indentation" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.align_type_members_on_columns" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assignment" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_module_statements" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_type_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_names_descriptions" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_if_then_body_block_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_first_class_body_declaration" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_closing_brace_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.format_guardian_clause_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_if" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.align_assignment_statements_on_columns" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_block_in_case" value="next_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression_chain" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_header" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_annotations" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_allocation_expression" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assertion_message_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_switch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_method_declaration" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.align_fields_grouping_blank_lines" value="2147483647"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.new_lines_at_javadoc_boundaries" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_bitwise_operator" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_annotation_type_declaration" value="next_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_resources_in_try" value="80"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_selector_in_method_invocation" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.never_indent_block_comments_on_first_column" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_synchronized" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_allocation_expression" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_source_code" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_field" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_method" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superclass_in_type_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_throw" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_not_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_type_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_brace_in_array_initializer" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_parenthesized_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_html" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_at_in_annotation_type_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_delcaration" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_compact_if" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_empty_lines" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_type_arguments" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_unary_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_annotation" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_declarations" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_package" value="49"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_switch" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_else_in_if_statement" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_assignment_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_label" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_declaration_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_cast" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_case" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_while_in_do_statement" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_record_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_opening_brace_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_breaks_compare_to_cases" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_bitwise_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_try" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_lambda_arrow" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_tag_description" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_imple_if_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_constructor" value="next_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_brackets_in_array_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_string_concatenation" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon_in_for" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_multiple_fields" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_enum_constant_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_prefix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_array_initializer" value="end_of_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_shift_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_method_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_catch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_shift_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_braces_in_array_initializer" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_local_declarations" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_simple_do_while_body_on_same_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_annotation_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_record_components" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_outer_expressions_when_nested" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_paren_in_cast" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_synchronized" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation_type_member_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_for_loop_header" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_additive_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_simple_getter_setter_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_while" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_string_concatenation" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_lambda_arrow" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.join_lines_in_comments" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_record_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_relational_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_multiple_field_declarations" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_import_groups" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_at_in_annotation_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_logical_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_method_invocation" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_imports" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_before_root_tags" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_record_declaration" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_declaration_throws" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_switch_statement" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_postfix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_increments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_type_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_arrow_in_switch_default" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_inits" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.disabling_tag" value="@formatter:off"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_enum_constants" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_imports" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_end_of_method_body" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_if_while_statement" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_brace_in_block" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_parenthesized_expression_in_return" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_case" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_field" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_type_declarations" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_for" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_catch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_switch" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_anonymous_type_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.never_indent_line_comments_on_first_column" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_for_inits" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_block" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_anonymous_type_declaration" value="next_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_wildcard" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_method_invocation_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_switch" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.align_tags_descriptions_grouped" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.line_length" value="80"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.use_on_off_tags" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_method_body_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_brackets_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_loop_body_block_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_enum_constant" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_method_declaration" value="next_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_type_declaration_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_additive_operator" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_multiple_field_declarations" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_constructor" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_relational_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_superinterfaces" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_record_declaration_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_default" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_constructor_declaration" value="next_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_lambda_body" value="next_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.compact_else_if" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_catch" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_invocation_arguments" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_method_invocation" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_throws_clause_in_constructor_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_catch_in_try_statement" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_try" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_parameter" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.clear_blank_lines_in_javadoc_comment" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_relational_operator" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_expressions_in_array_initializer" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_empty_lines_to_preserve" value="99"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_case" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_additive_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_if" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_string_concatenation" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_line_comments" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_record_declaration" value="next_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_labeled_statement" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_after_code_block" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_type_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_conditional_expression" value="80"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_after_annotation_on_type" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_type" value="49"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_block" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_local_variable" value="49"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_declaration" value="next_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_arrow_in_switch_default" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.insert_new_line_between_different_tags" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_additive_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_method_invocation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_while" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.join_wrapped_lines" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_between_empty_parens_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_field" value="49"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_conditional_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_switchstatements_compare_to_cases" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_synchronized" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_shift_operator" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.use_tabs_only_for_leading_indentations" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_try_clause" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_code_block_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_constructor_declaration_throws" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_record_components" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.tabulation.size" value="4"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_bitwise_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_colon_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_try" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_semicolon_in_try_resources" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.continuation_indentation_for_array_initializer" value="2"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_question_in_wildcard" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_record_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_enum_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_assignment_operator" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_labeled_statement" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_switch" value="next_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_superinterfaces" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_closing_angle_bracket_in_type_parameters" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_lambda_body_block_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_annotations_on_method" value="49"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_record_constructor_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_record_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_empty_array_initializer_on_one_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_assertion_message" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_new_chunk" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_bracket_in_array_allocation_expression" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_constructor_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_parameterized_type_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_assert" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_member_type" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_logical_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_arguments_in_qualified_allocation_expression" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_superinterfaces_in_record_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_if" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_semicolon" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_relational_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_postfix_operator" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_angle_bracket_in_type_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_cast" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.format_block_comments" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.alignment_for_parameters_in_method_declaration" value="16"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_method_declaration_throws" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_after_last_class_body_declaration" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_statements_compare_to_body" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_simple_while_body_on_same_line" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_logical_operator" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_between_statement_group_in_switch" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_bracket_in_array_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_comma_in_annotation" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_enum_constant_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.parentheses_positions_in_lambda_declaration" value="common_lines"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_colon_in_case" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_bracket_in_array_reference" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.keep_enum_declaration_on_one_line" value="one_line_never"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_method_declaration" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_enum_constant" value="next_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.brace_position_for_type_declaration" value="next_line"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_multiplicative_operator" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.blank_lines_before_package" value="1"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_for" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_for_increments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_enum_constant" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_explicitconstructorcall_arguments" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_paren_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.indent_body_declarations_compare_to_enum_constant_header" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_brace_in_constructor_declaration" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_comma_in_constructor_declaration_throws" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_closing_angle_bracket_in_type_parameters" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_question_in_conditional" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.comment.indent_parameter_description" value="false"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.number_of_blank_lines_at_beginning_of_code_block" value="0"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_new_line_before_finally_in_try_statement" value="insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.tabulation.char" value="tab"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.wrap_before_string_concatenation" value="true"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.lineSplit" value="1200"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_after_opening_paren_in_annotation" value="do not insert"/>
|
||||
<setting id="org.eclipse.jdt.core.formatter.insert_space_before_opening_paren_in_switch" value="insert"/>
|
||||
</profile>
|
||||
</profiles>
|
||||
@@ -1,50 +0,0 @@
|
||||
<code_scheme name="Eclipse (James' Edit)" version="173">
|
||||
<option name="RIGHT_MARGIN" value="1200" />
|
||||
<JavaCodeStyleSettings>
|
||||
<option name="JD_ALIGN_PARAM_COMMENTS" value="false" />
|
||||
<option name="JD_ALIGN_EXCEPTION_COMMENTS" value="false" />
|
||||
<option name="JD_ADD_BLANK_AFTER_DESCRIPTION" value="false" />
|
||||
<option name="JD_P_AT_EMPTY_LINES" value="false" />
|
||||
<option name="JD_KEEP_INVALID_TAGS" value="false" />
|
||||
<option name="JD_DO_NOT_WRAP_ONE_LINE_COMMENTS" value="true" />
|
||||
<option name="JD_KEEP_EMPTY_PARAMETER" value="false" />
|
||||
<option name="JD_KEEP_EMPTY_EXCEPTION" value="false" />
|
||||
<option name="JD_KEEP_EMPTY_RETURN" value="false" />
|
||||
</JavaCodeStyleSettings>
|
||||
<codeStyleSettings language="JAVA">
|
||||
<option name="KEEP_CONTROL_STATEMENT_IN_ONE_LINE" value="false" />
|
||||
<option name="KEEP_BLANK_LINES_IN_DECLARATIONS" value="10" />
|
||||
<option name="KEEP_BLANK_LINES_IN_CODE" value="10" />
|
||||
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="10" />
|
||||
<option name="BLANK_LINES_BEFORE_PACKAGE" value="1" />
|
||||
<option name="BRACE_STYLE" value="2" />
|
||||
<option name="CLASS_BRACE_STYLE" value="2" />
|
||||
<option name="METHOD_BRACE_STYLE" value="2" />
|
||||
<option name="ELSE_ON_NEW_LINE" value="true" />
|
||||
<option name="WHILE_ON_NEW_LINE" value="true" />
|
||||
<option name="CATCH_ON_NEW_LINE" value="true" />
|
||||
<option name="FINALLY_ON_NEW_LINE" value="true" />
|
||||
<option name="INDENT_CASE_FROM_SWITCH" value="false" />
|
||||
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
|
||||
<option name="ALIGN_MULTILINE_RESOURCES" value="false" />
|
||||
<option name="SPACE_WITHIN_ARRAY_INITIALIZER_BRACES" value="true" />
|
||||
<option name="SPACE_BEFORE_ARRAY_INITIALIZER_LBRACE" value="true" />
|
||||
<option name="CALL_PARAMETERS_WRAP" value="1" />
|
||||
<option name="METHOD_PARAMETERS_WRAP" value="1" />
|
||||
<option name="RESOURCE_LIST_WRAP" value="5" />
|
||||
<option name="EXTENDS_LIST_WRAP" value="1" />
|
||||
<option name="THROWS_LIST_WRAP" value="1" />
|
||||
<option name="EXTENDS_KEYWORD_WRAP" value="1" />
|
||||
<option name="THROWS_KEYWORD_WRAP" value="1" />
|
||||
<option name="METHOD_CALL_CHAIN_WRAP" value="1" />
|
||||
<option name="TERNARY_OPERATION_WRAP" value="5" />
|
||||
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
|
||||
<option name="METHOD_ANNOTATION_WRAP" value="0" />
|
||||
<option name="CLASS_ANNOTATION_WRAP" value="0" />
|
||||
<option name="FIELD_ANNOTATION_WRAP" value="0" />
|
||||
<indentOptions>
|
||||
<option name="USE_TAB_CHARACTER" value="true" />
|
||||
<option name="KEEP_INDENTS_ON_EMPTY_LINES" value="true" />
|
||||
</indentOptions>
|
||||
</codeStyleSettings>
|
||||
</code_scheme>
|
||||
|
Before Width: | Height: | Size: 113 KiB |
|
Before Width: | Height: | Size: 83 KiB |
|
Before Width: | Height: | Size: 81 KiB |
|
Before Width: | Height: | Size: 191 KiB |
|
Before Width: | Height: | Size: 172 KiB |
|
Before Width: | Height: | Size: 194 KiB |
|
Before Width: | Height: | Size: 174 KiB |
@@ -1,234 +1,698 @@
|
||||
buildscript {
|
||||
repositories {
|
||||
maven { url = 'https://files.minecraftforge.net' }
|
||||
mavenCentral()
|
||||
// potential replacement in case of problems:
|
||||
// https://dist.creeper.host/Sponge/maven
|
||||
maven { url = 'https://repo.spongepowered.org/maven/' }
|
||||
// used to download and compile dependencies from git repos
|
||||
maven { url 'https://jitpack.io' }
|
||||
}
|
||||
dependencies {
|
||||
classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '3.+', changing: true
|
||||
classpath group: 'org.spongepowered', name: 'mixingradle', version: '0.7-SNAPSHOT'
|
||||
classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.2'
|
||||
}
|
||||
import com.github.jengelman.gradle.plugins.shadow.transformers.Transformer
|
||||
import com.github.jengelman.gradle.plugins.shadow.transformers.TransformerContext
|
||||
import org.apache.tools.zip.ZipEntry
|
||||
|
||||
import javax.annotation.Nonnull
|
||||
import org.apache.tools.zip.ZipOutputStream
|
||||
|
||||
|
||||
plugins {
|
||||
id "java"
|
||||
|
||||
// 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.3.4"
|
||||
|
||||
// Manifold preprocessor
|
||||
id "systems.manifold.manifold-gradle-plugin" version "0.0.2-alpha"
|
||||
|
||||
// Architectury is used here only as a replacement for forge's own loom
|
||||
id "dev.architectury.loom" version "1.10-SNAPSHOT" apply false
|
||||
}
|
||||
apply plugin: 'net.minecraftforge.gradle'
|
||||
apply plugin: 'org.spongepowered.mixin'
|
||||
// Only edit below this line, the above code adds and enables the necessary things for Forge to be setup.
|
||||
apply plugin: 'eclipse'
|
||||
apply plugin: 'maven-publish'
|
||||
apply plugin: 'com.github.johnrengelman.shadow'
|
||||
|
||||
version = 'a1.5.0'
|
||||
group = 'com.seibel.lod'
|
||||
archivesBaseName = 'Distant-Horizons_1.16.5'
|
||||
|
||||
|
||||
sourceCompatibility = targetCompatibility = compileJava.sourceCompatibility = compileJava.targetCompatibility = '1.8' // Need this here so eclipse task generates correctly.
|
||||
/**
|
||||
* Creates the list of preprocessors to use.
|
||||
*
|
||||
* @param mcVers array of all MC versions
|
||||
* @param mcIndex array index of the currently active MC version
|
||||
*/
|
||||
def writeBuildGradlePredefine(List<String> mcVers, int mcIndex)
|
||||
{
|
||||
// Build the list of preprocessors to use
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
println('Java: ' + System.getProperty('java.version') + ' JVM: ' + System.getProperty('java.vm.version') + '(' + System.getProperty('java.vendor') + ') Arch: ' + System.getProperty('os.arch'))
|
||||
minecraft {
|
||||
// The mappings can be changed at any time, and must be in the following format.
|
||||
// snapshot_YYYYMMDD Snapshot are built nightly.
|
||||
// stable_# Stables are built at the discretion of the MCP team.
|
||||
// Use non-default mappings at your own risk. they may not always work.
|
||||
// Simply re-run your setup task after changing the mappings to update your workspace.
|
||||
mappings channel: 'official', version: '1.16.5'
|
||||
|
||||
// makeObfSourceJar = false // an Srg named sources jar is made by default. uncomment this to disable.
|
||||
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");
|
||||
}
|
||||
|
||||
accessTransformer = file('src/main/resources/META-INF/accesstransformer.cfg')
|
||||
|
||||
// Default run configurations.
|
||||
// These can be tweaked, removed, or duplicated as needed.
|
||||
runs {
|
||||
client {
|
||||
workingDirectory project.file('run')
|
||||
arg "-mixin.config=lod.mixins.json"
|
||||
// Check if this is a development build
|
||||
if (mod_version.toLowerCase().contains("dev"))
|
||||
{
|
||||
// WARNING: only use this for logging, we don't want to have confusion
|
||||
// when a method doesn't work correctly in the release build.
|
||||
sb.append("DEV_BUILD=\n");
|
||||
}
|
||||
|
||||
// Recommended logging data for a userdev environment
|
||||
// The markers can be changed as needed.
|
||||
// "SCAN": For mods scan.
|
||||
// "REGISTRIES": For firing of registry events.
|
||||
// "REGISTRYDUMP": For getting the contents of all registries.
|
||||
property 'forge.logging.markers', 'REGISTRIES'
|
||||
new File(projectDir, "build.properties").text = sb.toString()
|
||||
}
|
||||
|
||||
// Recommended logging level for the console
|
||||
// You can set various levels here.
|
||||
// Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels
|
||||
property 'forge.logging.console.level', 'debug'
|
||||
|
||||
mods {
|
||||
examplemod {
|
||||
source sourceSets.main
|
||||
}
|
||||
}
|
||||
// Transfers the values set in settings.gradle to the rest of the project
|
||||
project.gradle.ext.getProperties().each { prop ->
|
||||
rootProject.ext.set(prop.key, prop.value)
|
||||
//println "Added prop [key:" + prop.key + ", value:" + prop.value + "]"
|
||||
}
|
||||
// Sets up manifold stuff
|
||||
writeBuildGradlePredefine(rootProject.mcVers, rootProject.mcIndex)
|
||||
|
||||
// Sets up the version string (the name we use for our jar)
|
||||
rootProject.versionStr = rootProject.mod_version + "-" + rootProject.minecraft_version // + "-" + new Date().format("yyyy_MM_dd_HH_mm")
|
||||
|
||||
class NativeTransformer implements Transformer {
|
||||
private final HashMap<String, String> replacements = new HashMap()
|
||||
private final HashMap<String, byte[]> rewrittenFiles = new HashMap()
|
||||
private var nativeRelocator
|
||||
|
||||
public File rootDir
|
||||
|
||||
void relocateNative(String target, String replacement) {
|
||||
if (replacement.length() > target.length()) {
|
||||
throw new GradleException("Length of value \"${replacement}\" exceeds the length of \"${target}\": ${replacement.length()} > ${target.length()}")
|
||||
}
|
||||
|
||||
server {
|
||||
workingDirectory project.file('run')
|
||||
arg "-mixin.config=lod.mixins.json"
|
||||
|
||||
// Recommended logging data for a userdev environment
|
||||
// The markers can be changed as needed.
|
||||
// "SCAN": For mods scan.
|
||||
// "REGISTRIES": For firing of registry events.
|
||||
// "REGISTRYDUMP": For getting the contents of all registries.
|
||||
property 'forge.logging.markers', 'REGISTRIES'
|
||||
replacements.put(target, replacement)
|
||||
}
|
||||
|
||||
// Recommended logging level for the console
|
||||
// You can set various levels here.
|
||||
// Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels
|
||||
property 'forge.logging.console.level', 'debug'
|
||||
@Override
|
||||
boolean canTransformResource(@Nonnull FileTreeElement element) {
|
||||
return replacements.keySet().stream().anyMatch {
|
||||
element.name.startsWith(it as String)
|
||||
}
|
||||
}
|
||||
|
||||
mods {
|
||||
examplemod {
|
||||
source sourceSets.main
|
||||
}
|
||||
}
|
||||
@Override
|
||||
void transform(@Nonnull TransformerContext context) {
|
||||
byte[] content = context.is.readAllBytes()
|
||||
|
||||
if (nativeRelocator == null) {
|
||||
nativeRelocator = new NativeRelocator(rootDir.toPath().resolve("relocate_natives"))
|
||||
}
|
||||
|
||||
data {
|
||||
workingDirectory project.file('run')
|
||||
try {
|
||||
Map.Entry<String, String> pathReplacement = replacements.entrySet().stream().filter {
|
||||
context.path.startsWith(it.key as String)
|
||||
}.findFirst().orElseThrow()
|
||||
|
||||
// Recommended logging data for a userdev environment
|
||||
// The markers can be changed as needed.
|
||||
// "SCAN": For mods scan.
|
||||
// "REGISTRIES": For firing of registry events.
|
||||
// "REGISTRYDUMP": For getting the contents of all registries.
|
||||
property 'forge.logging.markers', 'REGISTRIES'
|
||||
String path = context.path.replace(pathReplacement.key as String, pathReplacement.value as String)
|
||||
content = nativeRelocator.processBinary(path, content, replacements)
|
||||
|
||||
// Recommended logging level for the console
|
||||
// You can set various levels here.
|
||||
// Please read: https://stackoverflow.com/questions/2031163/when-to-use-the-different-log-levels
|
||||
property 'forge.logging.console.level', 'debug'
|
||||
rewrittenFiles.put(path, content)
|
||||
}
|
||||
catch (Throwable e) {
|
||||
throw new GradleException("Failed to relocate", e)
|
||||
}
|
||||
}
|
||||
|
||||
// Specify the modid for data generation, where to output the resulting resource, and where to look for existing resources.
|
||||
args '--mod', 'lod', '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/')
|
||||
@Override
|
||||
boolean hasTransformedResource() { return !rewrittenFiles.isEmpty() }
|
||||
|
||||
mods {
|
||||
examplemod {
|
||||
source sourceSets.main
|
||||
}
|
||||
}
|
||||
@Override
|
||||
void modifyOutputStream(@Nonnull ZipOutputStream os, boolean preserveFileTimestamps) {
|
||||
for (Map.Entry<String, byte[]> rewrittenFile : rewrittenFiles.entrySet()) {
|
||||
os.putNextEntry(new ZipEntry(rewrittenFile.key))
|
||||
os.write(rewrittenFile.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Include resources generated by data generators.
|
||||
sourceSets.main.resources { srcDir 'src/generated/resources' }
|
||||
|
||||
// this is required so that we can use
|
||||
// jitpack in the dependencies section below
|
||||
repositories {
|
||||
mavenCentral()
|
||||
// used to download and compile dependencies from git repos
|
||||
maven { url 'https://jitpack.io' }
|
||||
}
|
||||
|
||||
configurations {
|
||||
shadowMe
|
||||
compileOnly.extendsFrom(embed)
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// Specify the version of Minecraft to use, If this is any group other then 'net.minecraft' it is assumed
|
||||
// that the dep is a ForgeGradle 'patcher' dependency. And it's patches will be applied.
|
||||
// The userdev artifact is a special name and will get all sorts of transformations applied to it.
|
||||
minecraft 'net.minecraftforge:forge:1.16.5-36.1.0'
|
||||
subprojects { p ->
|
||||
// Does the same as "p == project(":common") || p == project(":fabric") || p == project(":quilt") || p == project(":forge") || p == project("WhateverWeAddLaterOn")"
|
||||
// Useful later on so we dont have duplicated code
|
||||
def isMinecraftSubProject = p != project(":core") && p != project(":api")
|
||||
|
||||
|
||||
compile 'org.tukaani:xz:1.9'
|
||||
shadowMe 'org.tukaani:xz:1.9'
|
||||
compile 'org.apache.commons:commons-compress:1.21'
|
||||
shadowMe 'org.apache.commons:commons-compress:1.21'
|
||||
|
||||
// these were added to hopefully allow for cloning
|
||||
// configuredFeatures to allow for safe
|
||||
// multi threaded feature generation. Sadly I couldn't find
|
||||
// a way to duplicate lambda functions (which features use)
|
||||
// so for now I'm not sure what to do.
|
||||
//implementation 'io.github.kostaskougios:cloning:1.10.3'
|
||||
//
|
||||
//implementation ('com.esotericsoftware:kryo:5.1.1') {
|
||||
// exclude group: "org.objenesis"
|
||||
//}
|
||||
//implementation 'org.objenesis:objenesis:3.2'
|
||||
// Apply plugins
|
||||
apply plugin: "java"
|
||||
apply plugin: "com.github.johnrengelman.shadow"
|
||||
if (isMinecraftSubProject)
|
||||
apply plugin: "systems.manifold.manifold-gradle-plugin"
|
||||
|
||||
// Apply forge's loom
|
||||
if ((findProject(":forge") && p == project(":forge")) ||
|
||||
(findProject(":neoforge") && p == project(":neoforge"))
|
||||
)
|
||||
{
|
||||
apply plugin: "dev.architectury.loom"
|
||||
}
|
||||
|
||||
|
||||
// You may put jars on which you depend on in ./libs or you may define them like so..
|
||||
// compile "some.group:artifact:version:classifier"
|
||||
// compile "some.group:artifact:version"
|
||||
// Set the manifold version (may not be required tough)
|
||||
manifold {
|
||||
manifoldVersion = rootProject.manifold_version
|
||||
}
|
||||
|
||||
|
||||
// Real examples
|
||||
// compile 'com.mod-buildcraft:buildcraft:6.0.8:dev' // adds buildcraft to the dev env
|
||||
// compile 'com.googlecode.efficient-java-matrix-library:ejml:0.24' // adds ejml to the dev env
|
||||
// set up custom configurations (configurations are a way to handle dependencies)
|
||||
configurations {
|
||||
// extends the shadowJar configuration
|
||||
shadowMe
|
||||
// have implemented dependencies automatically embedded in the final jar
|
||||
implementation.extendsFrom(shadowMe)
|
||||
|
||||
// The 'provided' configuration is for optional dependencies that exist at compile-time but might not at runtime.
|
||||
// provided 'com.mod-buildcraft:buildcraft:6.0.8:dev'
|
||||
// Configuration fpr core & api
|
||||
coreProjects
|
||||
shadowMe.extendsFrom(coreProjects)
|
||||
|
||||
// These dependencies get remapped to your current MCP mappings
|
||||
// deobf 'com.mod-buildcraft:buildcraft:6.0.8:dev'
|
||||
|
||||
// For more info...
|
||||
// http://www.gradle.org/docs/current/userguide/artifact_dependencies_tutorial.html
|
||||
// http://www.gradle.org/docs/current/userguide/dependency_management.html
|
||||
// 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)
|
||||
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
duplicatesStrategy = DuplicatesStrategy.INCLUDE
|
||||
configurations = [project.configurations.getByName("shadowMe")]
|
||||
relocate 'org.tukaani', 'shaded.tukaani'
|
||||
relocate 'org.apache.commons.compress', 'shaded.apache.commons.compress'
|
||||
classifier = ''
|
||||
}
|
||||
if (isMinecraftSubProject && p != project(":common")) {
|
||||
// Shadow common
|
||||
common
|
||||
shadowCommon // Don't use shadow from the shadow plugin because we don't want IDEA to index this.
|
||||
compileClasspath.extendsFrom common
|
||||
runtimeClasspath.extendsFrom common
|
||||
if (findProject(":forge"))
|
||||
developmentForge.extendsFrom common
|
||||
if (findProject(":neoforge"))
|
||||
developmentNeoForge.extendsFrom common
|
||||
compileClasspath.extendsFrom coreProjects
|
||||
runtimeClasspath.extendsFrom coreProjects
|
||||
if (findProject(":forge"))
|
||||
developmentForge.extendsFrom coreProjects
|
||||
if (findProject(":neoforge"))
|
||||
developmentNeoForge.extendsFrom coreProjects
|
||||
|
||||
// TODO remove unused fabricLike
|
||||
if (findProject(":fabricLike") && p != project(":fabricLike")) {
|
||||
// Shadow fabricLike
|
||||
fabricLike
|
||||
shadowFabricLike
|
||||
compileClasspath.extendsFrom fabricLike
|
||||
runtimeClasspath.extendsFrom fabricLike
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
dependencies {
|
||||
//=====================//
|
||||
// shared dependencies //
|
||||
//=====================//
|
||||
|
||||
// Manifold
|
||||
if (isMinecraftSubProject) {
|
||||
annotationProcessor("systems.manifold:manifold-preprocessor:${rootProject.manifold_version}")
|
||||
}
|
||||
|
||||
// Log4j
|
||||
if (p == project(":core"))
|
||||
{
|
||||
// the standalone core jar needs logging shaded otherwise it won't run
|
||||
forgeShadowMe("org.apache.logging.log4j:log4j-api:${rootProject.log4j_version}")
|
||||
forgeShadowMe("org.apache.logging.log4j:log4j-core:${rootProject.log4j_version}")
|
||||
}
|
||||
else
|
||||
{
|
||||
// When running in MC, MC already includes logging
|
||||
implementation("org.apache.logging.log4j:log4j-api:${rootProject.log4j_version}")
|
||||
implementation("org.apache.logging.log4j:log4j-core:${rootProject.log4j_version}")
|
||||
}
|
||||
|
||||
|
||||
// JOML
|
||||
if (project.hasProperty("embed_joml") && embed_joml == "true")
|
||||
forgeShadowMe("org.joml:joml:${rootProject.joml_version}")
|
||||
else
|
||||
implementation("org.joml:joml:${rootProject.joml_version}")
|
||||
|
||||
// JUnit tests
|
||||
implementation("org.junit.jupiter:junit-jupiter:5.8.2")
|
||||
implementation("org.junit.jupiter:junit-jupiter-engine:5.8.2")
|
||||
implementation("junit:junit:4.13")
|
||||
|
||||
// FastUtil
|
||||
// Note: MC 1.16 uses 8.2.1, and versions after use 8.5.12
|
||||
// We cannot relocate this library since we call some MC classes that reference it
|
||||
implementation("it.unimi.dsi:fastutil:${rootProject.fastutil_version}")
|
||||
|
||||
//forgeShadowMe("com.github.luben:zstd-jni:1.5.7-3")
|
||||
//forgeShadowMe("org.apache.commons:commons-compress:1.27.1")
|
||||
|
||||
// Compression
|
||||
forgeShadowMe("org.lz4:lz4-java:${rootProject.lz4_version}") // LZ4
|
||||
forgeShadowMe("org.tukaani:xz:${rootProject.xz_version}") // LZMA
|
||||
|
||||
// Sqlite Database
|
||||
forgeShadowMe("org.xerial:sqlite-jdbc:${rootProject.sqlite_jdbc_version}")
|
||||
|
||||
// NightConfig (includes Toml & Json)
|
||||
forgeShadowMe("com.electronwill.night-config:toml:${rootProject.nightconfig_version}")
|
||||
forgeShadowMe("com.electronwill.night-config:json:${rootProject.nightconfig_version}")
|
||||
|
||||
// SVG (not needed atm)
|
||||
// forgeShadowMe("com.formdev:svgSalamander:${rootProject.svgSalamander_version}")
|
||||
|
||||
// Netty
|
||||
implementation("io.netty:netty-buffer:${rootProject.netty_version}")
|
||||
|
||||
// Remember, for lwjgl dependencies that arent included in Minecraft, you need to also need to add it to the ShadowJar thing
|
||||
forgeShadowMe("org.lwjgl:lwjgl-jawt:${rootProject.lwjgl_version}") {
|
||||
exclude group: "org.lwjgl", module: "lwjgl" // This module is imported by Minecraft so exclude it
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==========================//
|
||||
// conditional dependencies //
|
||||
//==========================//
|
||||
|
||||
|
||||
// Add core
|
||||
if (isMinecraftSubProject) {
|
||||
coreProjects(project(":core")) {
|
||||
// Remove Junit test libraries
|
||||
exclude group: "org.junit.jupiter", module: "junit-jupiter"
|
||||
exclude group: "org.junit.jupiter", module: "junit-jupiter-engine"
|
||||
exclude group: "junit", module: "junit"
|
||||
// Removed dependencies
|
||||
transitive false
|
||||
}
|
||||
}
|
||||
|
||||
// Add the api
|
||||
if (p != project(":api")) {
|
||||
coreProjects(project(":api")) {
|
||||
// Remove Junit test libraries
|
||||
exclude group: "org.junit.jupiter", module: "junit-jupiter"
|
||||
exclude group: "org.junit.jupiter", module: "junit-jupiter-engine"
|
||||
exclude group: "junit", module: "junit"
|
||||
// Removed dependencies
|
||||
transitive false
|
||||
}
|
||||
}
|
||||
|
||||
// Add common
|
||||
if (isMinecraftSubProject && p != project(":common")) {
|
||||
// Common
|
||||
common(project(":common")) { transitive false }
|
||||
shadowCommon(project(":common")) { transitive false }
|
||||
|
||||
// FabricLike
|
||||
if (findProject(":fabricLike") && p != project(":fabricLike")) {
|
||||
fabricLike(project(path: ":fabricLike")) { transitive false }
|
||||
shadowFabricLike(project(path: ":fabricLike")) { transitive false }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
reobf {
|
||||
shadowJar {
|
||||
dependsOn tasks.createMcpToSrg
|
||||
mappings = tasks.createMcpToSrg.outputs.files.singleFile
|
||||
configurations = [project.configurations.shadowMe]
|
||||
if (isMinecraftSubProject && p != project(":common")) {
|
||||
configurations.push(project.configurations.shadowCommon) // Shadow the common subproject
|
||||
relocate "com.seibel.distanthorizons.common", "loaderCommon.${p.name}.com.seibel.distanthorizons.common" // Move the loader files to a different location
|
||||
|
||||
if (findProject(":fabricLike") && p != project(":fabricLike")) {
|
||||
configurations.push(project.configurations.shadowFabricLike) // Shadow the fabricLike subproject
|
||||
relocate "com.seibel.distanthorizons.fabriclike", "loaderCommon.${p.name}.com.seibel.distanthorizons.fabriclike" // Move the loader files to a different location
|
||||
}
|
||||
}
|
||||
def librariesLocation = "DistantHorizons.libraries"
|
||||
|
||||
// LWJGL
|
||||
// Only ever shadow the dependencies we use otherwise some stuff would break when running on an external client
|
||||
relocate "org.lwjgl.system.jawt", "${librariesLocation}.lwjgl.system.jawt"
|
||||
|
||||
// Compression (LZ4)
|
||||
relocate "net.jpountz", "${librariesLocation}.jpountz"
|
||||
|
||||
// Logging
|
||||
relocate "org.slf4j", "${librariesLocation}.slf4j"
|
||||
|
||||
// Sqlite Database
|
||||
// librariesLocation isn't used because it's too long for replacing paths in native libraries
|
||||
// Allowing strings larger than the original string would require shifting the entire binary's contents
|
||||
relocate "org.sqlite", "dh_sqlite", {
|
||||
exclude "org/sqlite/native/**"
|
||||
}
|
||||
relocate "jdbc:sqlite", "jdbc:dh_sqlite"
|
||||
|
||||
transform(NativeTransformer) {
|
||||
rootDir = project.rootDir
|
||||
relocateNative "org/sqlite", "dh_sqlite"
|
||||
relocateNative "org_sqlite", "dh_1sqlite"
|
||||
}
|
||||
|
||||
|
||||
// JOML
|
||||
if (project.hasProperty("embed_joml") && embed_joml == "true")
|
||||
relocate "org.joml", "${librariesLocation}.joml"
|
||||
|
||||
// NightConfig (includes Toml & Json)
|
||||
relocate "com.electronwill.nightconfig", "${librariesLocation}.electronwill.nightconfig"
|
||||
|
||||
// SVG (not needed atm)
|
||||
// relocate "com.kitfox.svg", "${librariesLocation}.kitfox.svg"
|
||||
|
||||
// Netty
|
||||
// Don't relocate, it causes problems with using MC's FriendlyByteBufs
|
||||
// relocate "io.netty", "${librariesLocation}.netty"
|
||||
|
||||
mergeServiceFiles()
|
||||
}
|
||||
}
|
||||
// Using jar.finalizedBy(shadowJar) causes issues so we do this scuffed bypass
|
||||
jar.dependsOn(shadowJar)
|
||||
|
||||
artifacts {
|
||||
archives tasks.shadowJar
|
||||
}
|
||||
|
||||
// Example for how to get properties into the manifest for reading by the runtime..
|
||||
jar {
|
||||
manifest {
|
||||
attributes([
|
||||
"Specification-Title": "LOD",
|
||||
"Specification-Version": "1", // We are version 1 of ourselves
|
||||
"Implementation-Title": project.name,
|
||||
"Implementation-Version": "1",
|
||||
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"),
|
||||
"MixinConfigs": "lod.mixins.json",
|
||||
])
|
||||
}
|
||||
}
|
||||
// Example configuration to allow publishing using the maven-publish task
|
||||
// This is the preferred method to reobfuscate your jar file
|
||||
jar.finalizedBy('reobfJar')
|
||||
// However if you are in a multi-project build, dev time needs unobfed jar files, so you can delay the obfuscation until publishing by doing
|
||||
//publish.dependsOn('reobfJar')
|
||||
// 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",
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
mavenJava(MavenPublication) {
|
||||
artifact jar
|
||||
// Properties for each of the loaders
|
||||
"fabric.mod.json",
|
||||
"quilt.mod.json",
|
||||
"META-INF/mods.toml",
|
||||
"META-INF/neoforge.mods.toml",
|
||||
|
||||
// The mixins for each of the loaders
|
||||
"DistantHorizons."+ p.name +".fabricLike.mixins.json"
|
||||
]
|
||||
def intoTargets = ["$buildDir/resources/main/"] // Location of the built resources folder
|
||||
|
||||
// Fix forge version numbering system as it is weird
|
||||
// For whatever reason forge uses [1.18, 1.18.1, 1.18.2) instead of the standard ["1.18", "1.18.1", "1.18.2"]
|
||||
def compatible_forgemc_versions = "${compatible_minecraft_versions}".replaceAll("\"", "").replaceAll("]", ",)")
|
||||
// println compatible_forgemc_versions
|
||||
|
||||
// Quilt's custom contributors system
|
||||
// This has to be like
|
||||
// "Person": "Developer", "Another person": "Developer"
|
||||
def quilt_contributors = []
|
||||
def mod_author_list = mod_authors.replaceAll("\"", "").replace("[", "").replace("]", "").split(",")
|
||||
for (dev in mod_author_list) {
|
||||
quilt_contributors.push("\"${dev.strip()}\": \"Developer\"")
|
||||
}
|
||||
quilt_contributors.reverse()
|
||||
//println quilt_contributors.join(", ")
|
||||
|
||||
// TODO: Find something we can use so we can basically re-map only when the jar is shadowed and relocated
|
||||
// println p.tasks.findByName('shadowJar')
|
||||
|
||||
|
||||
// These "hasProperty"'s are so that they can be passed through the cli (ie in the CI)
|
||||
try {
|
||||
if (infoGitCommit == "null")
|
||||
infoGitCommit = 'git rev-parse --verify HEAD'.execute().text.trim()
|
||||
if (infoGitBranch == "null")
|
||||
infoGitBranch = 'git symbolic-ref --short HEAD'.execute().text.trim()
|
||||
} catch (Exception e) {
|
||||
infoGitCommit = infoGitBranch = "Git not found"
|
||||
println "Git or Git project not found"
|
||||
}
|
||||
|
||||
// The left side is what gets replaced in the mod info and the right side is where to get it from in the gradle.properties
|
||||
def replaceProperties = [
|
||||
version : mod_version,
|
||||
mod_name : mod_readable_name,
|
||||
group : maven_group,
|
||||
authors : mod_authors,
|
||||
description : mod_description,
|
||||
homepage : mod_homepage,
|
||||
source : mod_source,
|
||||
issues : mod_issues,
|
||||
discord : mod_discord,
|
||||
minecraft_version : minecraft_version,
|
||||
compatible_minecraft_versions: compatible_minecraft_versions,
|
||||
compatible_forgemc_versions : compatible_forgemc_versions,
|
||||
java_version : java_version,
|
||||
quilt_contributors : "{"+quilt_contributors.join(", ")+"}",
|
||||
|
||||
info_git_commit : infoGitBranch,
|
||||
info_git_branch : infoGitCommit,
|
||||
info_build_source : infoBuildSource,
|
||||
|
||||
fabric_incompatibility_list : fabric_incompatibility_list,
|
||||
fabric_recommend_list : fabric_recommend_list,
|
||||
|
||||
neoforge_version_range : neoforge_version_range,
|
||||
]
|
||||
|
||||
// replace any properties in the sub-projects with the values defined here
|
||||
inputs.properties replaceProperties
|
||||
replaceProperties.put "project", project
|
||||
filesMatching(resourceTargets) {
|
||||
expand replaceProperties
|
||||
}
|
||||
|
||||
intoTargets.each { target ->
|
||||
if (file(target).exists()) {
|
||||
copy {
|
||||
from(sourceSets.main.resources) {
|
||||
include resourceTargets
|
||||
expand replaceProperties
|
||||
}
|
||||
into target
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
// ==================== Delete un-needed files ====================
|
||||
exclude "DistantHorizons.fabricLike.mixins.json" // This isnt required atm, but we will be using it later
|
||||
|
||||
// exclude "*.distanthorizons.accesswidener"
|
||||
//// include "${accessWidenerVersion}.distanthorizons.accesswidener"
|
||||
|
||||
// Jank solution to remove all unused accesswideners
|
||||
// The line above would work..., except that (neo)forge (well, mainly architectury) requires the original accesswidener file, meaning we require this jank solution to keep it
|
||||
exclude { file ->
|
||||
if (file.name.contains(".distanthorizons.accesswidener") && file.name != "${accessWidenerVersion}.distanthorizons.accesswidener") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Adds the standalone jar's entrypoint
|
||||
jar {
|
||||
from "LICENSE.txt"
|
||||
manifest {
|
||||
attributes(
|
||||
'Implementation-Title': rootProject.mod_name,
|
||||
'Implementation-Version': rootProject.mod_version,
|
||||
'Multi-Release': true, // needed for logging in the standalone core jar
|
||||
'Main-Class': 'com.seibel.distanthorizons.core.jar.JarMain', // When changing the main of the jar change this line
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// this can be un-commented if we ever wanted to make DH modular (AKA use a module-info.java file) again
|
||||
/*
|
||||
// Tells gradle where to look for other modules
|
||||
// Why isn't the classpath added to the modules path by default?
|
||||
if (p == project(":core")) {
|
||||
compileJava {
|
||||
inputs.property('moduleName', 'dhApi')
|
||||
doFirst {
|
||||
options.compilerArgs = [
|
||||
'--module-path', classpath.asPath
|
||||
]
|
||||
classpath = files()
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
allprojects { p ->
|
||||
// Does the same as "p == project(":common") || p == project(":fabric") || p == project(":quilt") || p == project(":forge") || p == project("WhateverWeAddLaterOn")"
|
||||
// Useful later on so we dont have duplicated code
|
||||
def isMinecraftSubProject = p != project(":core") && p != project(":api")
|
||||
|
||||
|
||||
apply plugin: "java"
|
||||
apply plugin: "maven-publish"
|
||||
|
||||
// Sets the name of the jar, the version will contain the name of the project if it isn't the root project
|
||||
archivesBaseName = rootProject.mod_name
|
||||
version = (project == rootProject ? "" : 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 {
|
||||
// Mojang overrides (added to fix downloading the wrong LWJGL libs on M1 Mac's and potentially other arm64 based machines)
|
||||
maven { url "https://libraries.minecraft.net/" }
|
||||
|
||||
// The central repo
|
||||
mavenCentral()
|
||||
|
||||
// Used for Google's Collect library
|
||||
maven { url "https://repo.enonic.com/public/" }
|
||||
|
||||
// For parchment mappings
|
||||
// versions can be found here: https://ldtteam.jfrog.io/ui/native/parchmentmc-public/org/parchmentmc/data/
|
||||
maven { url "https://maven.parchmentmc.org" }
|
||||
|
||||
// For Architectury API
|
||||
maven { url "https://maven.architectury.dev" }
|
||||
|
||||
// For Git repositories
|
||||
maven { url "https://jitpack.io" }
|
||||
|
||||
// For Manifold Preprocessor
|
||||
maven { url "https://oss.sonatype.org/content/repositories/snapshots/" }
|
||||
|
||||
// Required for importing Modrinth mods
|
||||
maven {
|
||||
url "file:///${project.projectDir}/mcmodsrepo"
|
||||
name = "Modrinth"
|
||||
url = "https://api.modrinth.com/maven"
|
||||
content {
|
||||
includeGroup "maven.modrinth"
|
||||
}
|
||||
}
|
||||
|
||||
// Required for importing CursedForge mods
|
||||
maven {
|
||||
url "https://www.cursemaven.com"
|
||||
content {
|
||||
includeGroup "curse.maven"
|
||||
}
|
||||
}
|
||||
|
||||
// VanillaGradle and Mixins in common
|
||||
maven { url "https://repo.spongepowered.org/maven/" }
|
||||
|
||||
// Canvas mod
|
||||
maven { url "https://maven.vram.io/" }
|
||||
// ModMenu mod
|
||||
maven { url "https://maven.terraformersmc.com/" }
|
||||
|
||||
// neoforge
|
||||
maven { url "https://maven.neoforged.net/releases/" }
|
||||
|
||||
// These 3 are for importing mods that arnt on CursedForge, Modrinth, GitHub, GitLab or anywhere opensource
|
||||
flatDir {
|
||||
dirs "${rootDir}/mods/fabric"
|
||||
content {
|
||||
includeGroup "fabric-mod"
|
||||
}
|
||||
}
|
||||
flatDir {
|
||||
dirs "${rootDir}/mods/quilt"
|
||||
content {
|
||||
includeGroup "quilt-mod"
|
||||
}
|
||||
}
|
||||
flatDir {
|
||||
dirs "${rootDir}/mods/forge"
|
||||
content {
|
||||
includeGroup "forge-mod"
|
||||
}
|
||||
}
|
||||
// TODO: If neoforged is ever needed, should we use that, or call it a forge mod?
|
||||
}
|
||||
|
||||
// Adds some dependencies that are in vanilla but not in core
|
||||
if (p == project(":core")) {
|
||||
OperatingSystem os = org.gradle.nativeplatform.platform.internal.DefaultNativePlatform.currentOperatingSystem;
|
||||
|
||||
// Set the OS lwjgl is using to the current os
|
||||
project.ext.lwjglNatives = "natives-" + os.toFamilyName()
|
||||
|
||||
dependencies { // All of these dependencies are in Vanilla Minecraft, but we need to depend on it as we arent importing Minecraft in the core
|
||||
// Imports most of lwjgl's libraries (well, only the ones that we need)
|
||||
implementation platform("org.lwjgl:lwjgl-bom:${rootProject.lwjgl_version}") // TODO: Use Minecraft's version for lwjgl_version (which changes in nearly every version) instead of a hard defined version for all versions
|
||||
|
||||
// REMEMBER: Dont shadow stuff here, these are just the libs that are included in Minecraft so that the core can use
|
||||
implementation "org.lwjgl:lwjgl"
|
||||
implementation "org.lwjgl:lwjgl-assimp"
|
||||
implementation "org.lwjgl:lwjgl-glfw"
|
||||
implementation "org.lwjgl:lwjgl-openal"
|
||||
implementation "org.lwjgl:lwjgl-opengl"
|
||||
implementation "org.lwjgl:lwjgl-stb"
|
||||
implementation "org.lwjgl:lwjgl-tinyfd"
|
||||
runtimeOnly "org.lwjgl:lwjgl::$lwjglNatives"
|
||||
runtimeOnly "org.lwjgl:lwjgl-assimp::$lwjglNatives"
|
||||
runtimeOnly "org.lwjgl:lwjgl-glfw::$lwjglNatives"
|
||||
runtimeOnly "org.lwjgl:lwjgl-openal::$lwjglNatives"
|
||||
runtimeOnly "org.lwjgl:lwjgl-opengl::$lwjglNatives"
|
||||
runtimeOnly "org.lwjgl:lwjgl-stb::$lwjglNatives"
|
||||
runtimeOnly "org.lwjgl:lwjgl-tinyfd::$lwjglNatives"
|
||||
implementation "org.joml:joml:${rootProject.joml_version}"
|
||||
|
||||
|
||||
// Some other dependencies
|
||||
implementation("org.jetbrains:annotations:16.0.2")
|
||||
implementation("com.google.code.findbugs:jsr305:3.0.2")
|
||||
implementation("com.google.common:google-collect:0.5")
|
||||
implementation("com.google.guava:guava:31.1-jre")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mixin {
|
||||
add sourceSets.main, "lod.refmap.json"
|
||||
}
|
||||
|
||||
task copyCommonLoaderResources(type: Copy) {
|
||||
from project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener")
|
||||
into(file(p.file("build/resources/main")))
|
||||
rename "${accessWidenerVersion}.distanthorizons.accesswidener", "distanthorizons.accesswidener"
|
||||
|
||||
|
||||
// Move the fabricLike mixin to its different places for each subproject
|
||||
if (findProject(":fabricLike")) {
|
||||
from project(":fabricLike").file("src/main/resources/DistantHorizons.fabricLike.mixins.json")
|
||||
into(file(p.file("build/resources/main")))
|
||||
rename "DistantHorizons.fabricLike.mixins.json", "DistantHorizons." + p.name + ".fabricLike.mixins.json"
|
||||
}
|
||||
}
|
||||
|
||||
task copyCoreResources(type: Copy) {
|
||||
from fileTree(project(":core").file("src/main/resources"))
|
||||
into p.file("build/resources/main")
|
||||
}
|
||||
|
||||
tasks.withType(JavaCompile) {
|
||||
if (isMinecraftSubProject) {
|
||||
options.release = rootProject.java_version as Integer
|
||||
} else {
|
||||
options.release = 8; // Core & Api should use Java 8 no matter what
|
||||
//options.release = rootProject.java_version as Integer // But if you want to test some stuff, then this can be enabled
|
||||
}
|
||||
options.encoding = "UTF-8"
|
||||
}
|
||||
|
||||
java {
|
||||
withSourcesJar()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "==================== Note: All build jars will be in the folder called 'buildAllJars' ===================="
|
||||
mkdir -p buildAllJars
|
||||
rm -rf buildAllJars/*
|
||||
|
||||
# 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, 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
|
||||
if [ $? != 0 ]; then continue; fi
|
||||
|
||||
echo "====================Building $version ===================="
|
||||
sh gradlew build -PmcVer=$version
|
||||
if [ $? != 0 ]; then continue; fi
|
||||
|
||||
echo "==================== Merging $version ===================="
|
||||
sh gradlew mergeJars -PmcVer=$version
|
||||
if [ $? != 0 ]; then continue; fi
|
||||
|
||||
echo "==================== Moving jar ===================="
|
||||
mv build/merged/*.jar buildAllJars/
|
||||
done
|
||||
@@ -0,0 +1,29 @@
|
||||
@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
|
||||
del 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 Clean out the folders, build it, and merge it
|
||||
echo ==================== Cleaning workspace to build !version! ====================
|
||||
call .\gradlew.bat clean
|
||||
|
||||
echo ==================== Building !version! ====================
|
||||
call .\gradlew.bat build -PmcVer="!version!"
|
||||
|
||||
echo ==================== Merging !version! ====================
|
||||
call .\gradlew.bat mergeJars -PmcVer="!version!"
|
||||
|
||||
echo ==================== Moving jar ====================
|
||||
move build\merged\*.jar buildAllJars\
|
||||
)
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,211 @@
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
class NativeRelocator
|
||||
{
|
||||
private final Path rootDirectory;
|
||||
private final Path cacheRoot;
|
||||
|
||||
/**
|
||||
* Initializes the NativeRelocator by preparing the environment if necessary.
|
||||
* Executes the appropriate preparation script based on the OS.
|
||||
*/
|
||||
NativeRelocator(Path rootDirectory)
|
||||
{
|
||||
this.rootDirectory = rootDirectory;
|
||||
this.cacheRoot = this.rootDirectory.resolve("cache");
|
||||
}
|
||||
|
||||
private void prepare() throws Exception
|
||||
{
|
||||
if (this.rootDirectory.resolve(".venv").toFile().exists())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ProcessBuilder processBuilder = new ProcessBuilder();
|
||||
processBuilder.directory(this.rootDirectory.toFile());
|
||||
|
||||
String os = System.getProperty("os.name").toLowerCase();
|
||||
if (os.contains("win"))
|
||||
{
|
||||
processBuilder.command("powershell", "-ExecutionPolicy", "Bypass", "./prepare.ps1");
|
||||
}
|
||||
else if (os.contains("nix") || os.contains("nux") || os.contains("mac"))
|
||||
{
|
||||
processBuilder.command("./prepare.sh");
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new IllegalStateException("Unsupported operating system: " + os);
|
||||
}
|
||||
|
||||
Process process = processBuilder.start();
|
||||
CompletableFuture<Void> outputFuture = readOutputStreams(process);
|
||||
|
||||
int exitCode = process.waitFor();
|
||||
outputFuture.get();
|
||||
|
||||
if (exitCode != 0)
|
||||
{
|
||||
throw new Exception("Prepare failed: " + exitCode);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads and prints the output and error streams of a process asynchronously.
|
||||
*
|
||||
* @param process The process whose streams should be read.
|
||||
* @return A CompletableFuture that completes once all output has been processed.
|
||||
*/
|
||||
private static CompletableFuture<Void> readOutputStreams(Process process)
|
||||
{
|
||||
return CompletableFuture.runAsync(() -> {
|
||||
try
|
||||
{
|
||||
while (process.isAlive() || process.getInputStream().available() > 0 || process.getErrorStream().available() > 0)
|
||||
{
|
||||
if (process.getInputStream().available() > 0)
|
||||
{
|
||||
byte[] data = new byte[process.getInputStream().available()];
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
process.getInputStream().read(data);
|
||||
System.out.write(data);
|
||||
}
|
||||
if (process.getErrorStream().available() > 0)
|
||||
{
|
||||
byte[] data = new byte[process.getErrorStream().available()];
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
process.getErrorStream().read(data);
|
||||
System.err.write(data);
|
||||
}
|
||||
|
||||
//noinspection BusyWait
|
||||
Thread.sleep(100);
|
||||
}
|
||||
}
|
||||
catch (Throwable ignored)
|
||||
{
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces occurrences of a target string in a byte array, ensuring null termination.
|
||||
*
|
||||
* @param byteArray The byte array where replacements should occur.
|
||||
* @param target The string to replace.
|
||||
* @param replacement The replacement string (must not be longer than the target).
|
||||
* @throws IllegalArgumentException if the replacement is longer than the target.
|
||||
*/
|
||||
private void replaceInNullTerminatedStrings(byte[] byteArray, String target, String replacement)
|
||||
{
|
||||
if (target.length() < replacement.length())
|
||||
{
|
||||
throw new IllegalArgumentException("Replacement must be the same length or shorter than the target.");
|
||||
}
|
||||
|
||||
byte[] targetBytes = target.getBytes(StandardCharsets.US_ASCII);
|
||||
byte[] replacementBytes = replacement.getBytes(StandardCharsets.US_ASCII);
|
||||
|
||||
byte nullByte = 0;
|
||||
|
||||
for (int endPos = 0; endPos < byteArray.length - targetBytes.length - 1; endPos++)
|
||||
{
|
||||
int startPos = endPos;
|
||||
int targetPos = 0;
|
||||
while (targetPos < targetBytes.length && byteArray[endPos] == targetBytes[targetPos])
|
||||
{
|
||||
targetPos++;
|
||||
endPos++;
|
||||
}
|
||||
|
||||
if (targetPos == targetBytes.length)
|
||||
{
|
||||
System.arraycopy(replacementBytes, 0, byteArray, startPos, replacementBytes.length);
|
||||
|
||||
startPos = startPos + replacementBytes.length;
|
||||
while (byteArray[endPos] != nullByte)
|
||||
{
|
||||
byteArray[startPos] = byteArray[endPos];
|
||||
endPos++;
|
||||
startPos++;
|
||||
}
|
||||
byteArray[startPos] = nullByte;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs an external script to fix a modified binary and returns the processed content.
|
||||
*
|
||||
* @param outputFilePath Path to store the processed binary.
|
||||
* @param content The original binary content.
|
||||
* @return The modified binary content.
|
||||
* @throws Exception if the process execution fails.
|
||||
*/
|
||||
public byte[] fixModifiedBinary(Path outputFilePath, byte[] content) throws Exception
|
||||
{
|
||||
ProcessBuilder processBuilder = new ProcessBuilder();
|
||||
processBuilder.directory(this.rootDirectory.toFile());
|
||||
|
||||
processBuilder.command(
|
||||
this.rootDirectory.resolve(".venv/Scripts").toFile().exists()
|
||||
? this.rootDirectory.resolve(".venv/Scripts/python.exe").toString()
|
||||
: this.rootDirectory.resolve(".venv/bin/python").toString(),
|
||||
"./fix_modified_binary.py",
|
||||
outputFilePath.toString()
|
||||
);
|
||||
|
||||
Process process = processBuilder.start();
|
||||
CompletableFuture<Void> outputFuture = readOutputStreams(process);
|
||||
|
||||
process.getOutputStream().write(content);
|
||||
process.getOutputStream().close();
|
||||
|
||||
int exitCode = process.waitFor();
|
||||
outputFuture.get();
|
||||
|
||||
if (exitCode != 0)
|
||||
{
|
||||
throw new Exception("Process failed: " + exitCode);
|
||||
}
|
||||
|
||||
return Files.readAllBytes(outputFilePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes a binary file, applying string replacements and fixing modifications.
|
||||
*
|
||||
* @param outputPath The output file path relative to the cache directory.
|
||||
* @param content The binary content to process.
|
||||
* @param replacements A map of string replacements to apply.
|
||||
* @return The modified binary content.
|
||||
* @throws Exception if processing fails.
|
||||
*/
|
||||
public byte[] processBinary(String outputPath, byte[] content, Map<String, String> replacements) throws Exception
|
||||
{
|
||||
Path outputFilePath = this.cacheRoot.resolve(outputPath);
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
outputFilePath.getParent().toFile().mkdirs();
|
||||
|
||||
if (outputFilePath.toFile().exists())
|
||||
{
|
||||
return Files.readAllBytes(outputFilePath);
|
||||
}
|
||||
|
||||
System.out.println("Relocating to " + outputPath + "...");
|
||||
this.prepare();
|
||||
|
||||
for (Map.Entry<String, String> replacement : replacements.entrySet())
|
||||
{
|
||||
this.replaceInNullTerminatedStrings(content, replacement.getKey(), replacement.getValue());
|
||||
}
|
||||
|
||||
return this.fixModifiedBinary(outputFilePath, content);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
|
||||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to make participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
||||
level of experience, education, socio-economic status, nationality, personal
|
||||
appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies within all project spaces, and it also applies when
|
||||
an individual is representing the project or its community in public spaces.
|
||||
Examples of representing a project or community include using an official
|
||||
project e-mail address, posting via an official social media account, or acting
|
||||
as an appointed representative at an online or offline event. Representation of
|
||||
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`. 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.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see
|
||||
https://www.contributor-covenant.org/faq
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
|
||||
// temporary fix for broken spongepowered version
|
||||
buildscript {
|
||||
configurations.configureEach {
|
||||
resolutionStrategy {
|
||||
force 'org.spongepowered:vanillagradle:0.2.1-20240507.024226-82'
|
||||
// newer versions can be found by going to the link:
|
||||
// https://repo.spongepowered.org/#browse/browse:maven-public:org%2Fspongepowered%2Fvanillagradle%2F0.2.1-SNAPSHOT
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
plugins {
|
||||
id "org.spongepowered.gradle.vanilla" version "0.2.1-SNAPSHOT"
|
||||
}
|
||||
|
||||
minecraft {
|
||||
accessWideners(project(":common").file("src/main/resources/${accessWidenerVersion}.distanthorizons.accesswidener"))
|
||||
version(rootProject.minecraft_version)
|
||||
}
|
||||
|
||||
dependencies {
|
||||
// So mixins can be written in common
|
||||
compileOnly group:'org.spongepowered', name:'mixin', version:'0.8.5'
|
||||
}
|
||||
|
||||
|
||||
publishing {
|
||||
publications {
|
||||
mavenCommon(MavenPublication) {
|
||||
artifactId = rootProject.mod_readable_name
|
||||
from components.java
|
||||
}
|
||||
}
|
||||
|
||||
// See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing.
|
||||
repositories {
|
||||
// Add repositories to publish to here.
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,299 @@
|
||||
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.commands.CommandInitializer;
|
||||
import com.seibel.distanthorizons.common.wrappers.DependencySetup;
|
||||
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftServerWrapper;
|
||||
import com.seibel.distanthorizons.core.api.internal.ClientApi;
|
||||
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.jar.updater.SelfUpdater;
|
||||
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 CommandInitializer commandInitializer;
|
||||
|
||||
|
||||
|
||||
//==================//
|
||||
// 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 + " client, firing DhApiBeforeDhInitEvent...");
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDhInitEvent.class, null);
|
||||
|
||||
this.startup();
|
||||
this.logBuildInfo();
|
||||
|
||||
this.createClientProxy().registerEvents();
|
||||
this.createServerProxy(false).registerEvents();
|
||||
|
||||
this.initializeModCompat();
|
||||
|
||||
// Client uses config for auto-updater, so it's initialized here instead of post-init stage
|
||||
this.initConfig();
|
||||
logModIncompatibilityWarnings(); // needs to be called after config loading
|
||||
|
||||
LOGGER.info(ModInfo.READABLE_NAME + " client Initialized.");
|
||||
|
||||
this.subscribeClientStartedEvent(this::postInit);
|
||||
}
|
||||
|
||||
public void onInitializeServer()
|
||||
{
|
||||
DependencySetup.createServerBindings();
|
||||
|
||||
LOGGER.info("Initializing " + ModInfo.READABLE_NAME + " server, firing DhApiBeforeDhInitEvent event...");
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiBeforeDhInitEvent.class, null);
|
||||
|
||||
this.startup();
|
||||
this.logBuildInfo();
|
||||
|
||||
// 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();
|
||||
|
||||
this.initializeModCompat();
|
||||
|
||||
LOGGER.info(ModInfo.READABLE_NAME + " server Initialized, adding event subscribers...");
|
||||
|
||||
this.subscribeRegisterCommandsEvent(dispatcher -> { this.commandInitializer = new CommandInitializer(dispatcher); });
|
||||
|
||||
this.subscribeServerStartingEvent(server ->
|
||||
{
|
||||
MinecraftServerWrapper.INSTANCE.dedicatedServer = (DedicatedServer)server;
|
||||
|
||||
this.initConfig();
|
||||
this.postInit();
|
||||
this.commandInitializer.initCommands();
|
||||
|
||||
this.checkForUpdates();
|
||||
|
||||
LOGGER.info(ModInfo.READABLE_NAME + " server Initialized at " + server.getServerDirectory());
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
//===========================//
|
||||
// inner initializer methods //
|
||||
//===========================//
|
||||
|
||||
private void startup()
|
||||
{
|
||||
DependencySetup.createSharedBindings();
|
||||
SharedApi.init();
|
||||
this.createInitialBindings();
|
||||
}
|
||||
|
||||
private void logBuildInfo()
|
||||
{
|
||||
LOGGER.info(ModInfo.READABLE_NAME + ", Version: " + ModInfo.VERSION);
|
||||
|
||||
// if the build is stable the branch/commit/etc shouldn't be needed
|
||||
if (ModInfo.IS_DEV_BUILD)
|
||||
{
|
||||
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, ModInfo.CONFIG_FILE_VERSION);
|
||||
Config.completeDelayedSetup();
|
||||
}
|
||||
|
||||
private void checkForUpdates()
|
||||
{
|
||||
if (Config.Client.Advanced.AutoUpdater.enableAutoUpdater.get())
|
||||
{
|
||||
if (Config.Client.Advanced.AutoUpdater.enableSilentUpdates.get())
|
||||
{
|
||||
LOGGER.info("Silent updates are not allowed for dedicated servers; force disabling.");
|
||||
Config.Client.Advanced.AutoUpdater.enableSilentUpdates.set(false);
|
||||
}
|
||||
|
||||
SelfUpdater.onStart();
|
||||
}
|
||||
}
|
||||
|
||||
private void postInit()
|
||||
{
|
||||
LOGGER.info("Running Delayed setup...");
|
||||
this.runDelayedSetup();
|
||||
LOGGER.info("Delayed setup complete, firing DhApiAfterDhInitEvent event...");
|
||||
|
||||
// should be fired after all delayed setup so singletons and config can be accessed
|
||||
ApiEventInjector.INSTANCE.fireAllEvents(DhApiAfterDhInitEvent.class, null);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==================================//
|
||||
// mod partial compatibility checks //
|
||||
//==================================//
|
||||
|
||||
/**
|
||||
* Some mods will work with a few tweaks
|
||||
* or will partially work but have some known issues we can't solve.
|
||||
* This method will log (and display to chat if enabled)
|
||||
* these warnings and potential fixes.
|
||||
*/
|
||||
private static void logModIncompatibilityWarnings()
|
||||
{
|
||||
boolean showChatWarnings = Config.Common.Logging.Warning.showModCompatibilityWarningsOnStartup.get();
|
||||
IModChecker modChecker = SingletonInjector.INSTANCE.get(IModChecker.class);
|
||||
|
||||
String startingString = "Partially Incompatible Distant Horizons mod detected: ";
|
||||
|
||||
|
||||
|
||||
// Alex's caves
|
||||
if (modChecker.isModLoaded("alexscaves"))
|
||||
{
|
||||
// There've been a few reports about this mod breaking DH at a few different points in time
|
||||
// the fixes for said breakage changes depending on the version so unfortunately
|
||||
// all we can do is log a warning so the user can handle it.
|
||||
|
||||
if (showChatWarnings)
|
||||
{
|
||||
String message =
|
||||
// orange text
|
||||
"\u00A76" + "Distant Horizons: Alex's Cave detected." + "\u00A7r\n" +
|
||||
"You may have to change Alex's config for DH to render. ";
|
||||
ClientApi.INSTANCE.showChatMessageNextFrame(message);
|
||||
}
|
||||
|
||||
LOGGER.warn(startingString + "[Alex's Caves] may require some config changes in order to render Distant Horizons correctly.");
|
||||
}
|
||||
|
||||
// William Wythers' Overhauled Overworld (WWOO)
|
||||
if (modChecker.isModLoaded("wwoo"))
|
||||
{
|
||||
// WWOO has a bug with it's world gen that can't be fixed by DH or WWOO
|
||||
// (at least that is what James learned after talking with WWOO)
|
||||
// WWOO will cause grid lines to appear in the world when DH generates the chunks
|
||||
// this might be due to how WWOO uses features for everything when generating
|
||||
// and said features don't always get to the edge of said chunks.
|
||||
|
||||
String wwooWarning = "LODs generated by DH may have grid lines between sections. Disabling either WWOO or DH's distant generator will fix the problem.";
|
||||
|
||||
if (showChatWarnings)
|
||||
{
|
||||
String message =
|
||||
// orange text
|
||||
"\u00A76" + "Distant Horizons: WWOO detected." + "\u00A7r\n" +
|
||||
wwooWarning;
|
||||
ClientApi.INSTANCE.showChatMessageNextFrame(message);
|
||||
}
|
||||
|
||||
LOGGER.warn(startingString + "[WWOO] "+ wwooWarning);
|
||||
}
|
||||
|
||||
// Chunky
|
||||
boolean chunkyPresent = false;
|
||||
try
|
||||
{
|
||||
Class.forName("org.popcraft.chunky.api.ChunkyAPI");
|
||||
chunkyPresent = true;
|
||||
}
|
||||
catch (ClassNotFoundException ignore) { }
|
||||
|
||||
if (chunkyPresent)
|
||||
{
|
||||
// Chunky can generate chunks faster than DH can process them,
|
||||
// causing holes in the LODs.
|
||||
// Generally it's better and faster to use DH's world generator.
|
||||
|
||||
String chunkyWarning = "Chunky can cause DH LODs to have holes " +
|
||||
"since Chunky can generate chunks faster than DH can process them. \n" +
|
||||
"Using DH's distant generator instead of chunky or increasing DH's CPU thread count can resolve the issue.";
|
||||
|
||||
if (showChatWarnings)
|
||||
{
|
||||
String message =
|
||||
// orange text
|
||||
"\u00A76" + "Distant Horizons: Chunky detected." + "\u00A7r\n" +
|
||||
chunkyWarning;
|
||||
ClientApi.INSTANCE.showChatMessageNextFrame(message);
|
||||
}
|
||||
|
||||
LOGGER.warn(startingString + "[Chunky] "+ chunkyWarning);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// helper classes //
|
||||
//================//
|
||||
|
||||
public interface IEventProxy
|
||||
{
|
||||
void registerEvents();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
package com.seibel.distanthorizons.common;
|
||||
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.logging.ConfigBasedLogger;
|
||||
import com.seibel.distanthorizons.core.network.event.internal.IncompatibleMessageInternalEvent;
|
||||
import com.seibel.distanthorizons.core.network.event.internal.ProtocolErrorInternalEvent;
|
||||
import com.seibel.distanthorizons.core.network.messages.MessageRegistry;
|
||||
import com.seibel.distanthorizons.core.network.messages.AbstractNetworkMessage;
|
||||
import com.seibel.distanthorizons.core.network.messages.base.CloseReasonMessage;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
|
||||
import com.seibel.distanthorizons.coreapi.ModInfo;
|
||||
import io.netty.buffer.ByteBufUtil;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.apache.logging.log4j.LogManager;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Objects;
|
||||
|
||||
public abstract class AbstractPluginPacketSender implements IPluginPacketSender
|
||||
{
|
||||
private static final ConfigBasedLogger LOGGER = new ConfigBasedLogger(LogManager.getLogger(),
|
||||
() -> Config.Common.Logging.logNetworkEvent.get());
|
||||
|
||||
#if MC_VER >= MC_1_21_1
|
||||
public static final ResourceLocation WRAPPER_PACKET_RESOURCE = ResourceLocation.fromNamespaceAndPath(ModInfo.RESOURCE_NAMESPACE, ModInfo.WRAPPER_PACKET_PATH);
|
||||
#else
|
||||
public static final ResourceLocation WRAPPER_PACKET_RESOURCE = new ResourceLocation(ModInfo.RESOURCE_NAMESPACE, ModInfo.WRAPPER_PACKET_PATH);
|
||||
#endif
|
||||
|
||||
// "Forge byte" is an unused packet ID. We have our own system which works with all mod loaders,
|
||||
// so we're just accounting for it by reading the protocol version as a byte instead of a short in Forge, to keep cross-loader compatibility
|
||||
private final boolean forgeByteInProtocolVersion;
|
||||
|
||||
|
||||
public AbstractPluginPacketSender() { this(false); }
|
||||
public AbstractPluginPacketSender(boolean forgeByteInProtocolVersion)
|
||||
{
|
||||
this.forgeByteInProtocolVersion = forgeByteInProtocolVersion;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void sendToClient(IServerPlayerWrapper serverPlayer, AbstractNetworkMessage message)
|
||||
{
|
||||
this.sendToClient((ServerPlayer) serverPlayer.getWrappedMcObject(), message);
|
||||
}
|
||||
public abstract void sendToClient(ServerPlayer serverPlayer, AbstractNetworkMessage message);
|
||||
|
||||
@Override
|
||||
public abstract void sendToServer(AbstractNetworkMessage message);
|
||||
|
||||
public AbstractNetworkMessage decodeMessage(FriendlyByteBuf in)
|
||||
{
|
||||
AbstractNetworkMessage message = null;
|
||||
|
||||
try
|
||||
{
|
||||
in.markReaderIndex();
|
||||
|
||||
int protocolVersion = this.forgeByteInProtocolVersion ? in.readByte() : in.readShort();
|
||||
if (protocolVersion != ModInfo.PROTOCOL_VERSION)
|
||||
{
|
||||
return new IncompatibleMessageInternalEvent(protocolVersion);
|
||||
}
|
||||
|
||||
message = MessageRegistry.INSTANCE.createMessage(in.readUnsignedShort());
|
||||
message.decode(in);
|
||||
|
||||
if (in.isReadable())
|
||||
{
|
||||
throw new IOException("Buffer has not been fully read");
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
in.resetReaderIndex();
|
||||
|
||||
LOGGER.error("Failed to decode message", e);
|
||||
LOGGER.error("Buffer: ["+in+"]");
|
||||
LOGGER.error("Buffer contents: ["+ByteBufUtil.hexDump(in)+"]");
|
||||
|
||||
return new ProtocolErrorInternalEvent(e, message, true);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Prevent connection crashing if not entire buffer has been read
|
||||
in.readerIndex(in.writerIndex());
|
||||
}
|
||||
}
|
||||
|
||||
public void encodeMessage(FriendlyByteBuf out, AbstractNetworkMessage message)
|
||||
{
|
||||
// This is intentionally unhandled, because errors related to this are unlikely to appear in wild
|
||||
Objects.requireNonNull(message);
|
||||
|
||||
if (this.forgeByteInProtocolVersion)
|
||||
{
|
||||
out.writeByte(ModInfo.PROTOCOL_VERSION);
|
||||
}
|
||||
else
|
||||
{
|
||||
out.writeShort(ModInfo.PROTOCOL_VERSION);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
out.markWriterIndex();
|
||||
out.writeShort(MessageRegistry.INSTANCE.getMessageId(message));
|
||||
message.encode(out);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.error("Failed to encode message", e);
|
||||
LOGGER.error("Message: ["+message+"]");
|
||||
|
||||
message.getSession().tryHandleMessage(new ProtocolErrorInternalEvent(e, message, false));
|
||||
|
||||
// Encode close reason message instead
|
||||
out.resetWriterIndex();
|
||||
message = new CloseReasonMessage("Internal error on other side");
|
||||
out.writeShort(MessageRegistry.INSTANCE.getMessageId(message));
|
||||
message.encode(out);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.seibel.distanthorizons.common;
|
||||
|
||||
#if MC_VER >= MC_1_20_6
|
||||
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.network.messages.AbstractNetworkMessage;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IPluginPacketSender;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public record CommonPacketPayload(@Nullable AbstractNetworkMessage message) implements CustomPacketPayload
|
||||
{
|
||||
public static final Type<CommonPacketPayload> TYPE = new Type<>(AbstractPluginPacketSender.WRAPPER_PACKET_RESOURCE);
|
||||
private static final AbstractPluginPacketSender PACKET_SENDER = (AbstractPluginPacketSender) SingletonInjector.INSTANCE.get(IPluginPacketSender.class);
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public Type<? extends CustomPacketPayload> type() { return TYPE; }
|
||||
|
||||
|
||||
public static class Codec implements StreamCodec<FriendlyByteBuf, CommonPacketPayload>
|
||||
{
|
||||
@NotNull
|
||||
@Override
|
||||
public CommonPacketPayload decode(@NotNull FriendlyByteBuf in)
|
||||
{ return new CommonPacketPayload(PACKET_SENDER.decodeMessage(in)); }
|
||||
|
||||
@Override
|
||||
public void encode(@NotNull FriendlyByteBuf out, CommonPacketPayload payload)
|
||||
{ PACKET_SENDER.encodeMessage(out, payload.message()); }
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,102 @@
|
||||
package com.seibel.distanthorizons.common.commands;
|
||||
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.seibel.distanthorizons.common.wrappers.misc.ServerPlayerWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IServerPlayerWrapper;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
|
||||
#if MC_VER >= MC_1_19_2
|
||||
import net.minecraft.network.chat.Component;
|
||||
|
||||
import java.util.Objects;
|
||||
#else // < 1.19.2
|
||||
import net.minecraft.network.chat.TranslatableComponent;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Abstract class providing common functionality for DH's commands.
|
||||
*/
|
||||
public abstract class AbstractCommand
|
||||
{
|
||||
public abstract LiteralArgumentBuilder<CommandSourceStack> buildCommand();
|
||||
|
||||
|
||||
/**
|
||||
* Sends a success response to the player with the given text.
|
||||
*
|
||||
* @param commandContext The command context to send the response to.
|
||||
* @param text The text to display in the success message.
|
||||
* @return 1, indicating that the command was successful.
|
||||
*/
|
||||
protected int sendSuccessResponse(CommandContext<CommandSourceStack> commandContext, String text, boolean notifyAdmins)
|
||||
{
|
||||
#if MC_VER >= MC_1_20_1
|
||||
commandContext.getSource().sendSuccess(() -> Component.literal(text), notifyAdmins);
|
||||
#elif MC_VER >= MC_1_19_2
|
||||
commandContext.getSource().sendSuccess(Component.literal(text), notifyAdmins);
|
||||
#else
|
||||
commandContext.getSource().sendSuccess(new TranslatableComponent(text), notifyAdmins);
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a failure response to the player with the given text.
|
||||
*
|
||||
* @param commandContext The command context to send the response to.
|
||||
* @param text The text to display in the failure message.
|
||||
* @return 1, indicating that the command was successful.
|
||||
*/
|
||||
protected int sendFailureResponse(CommandContext<CommandSourceStack> commandContext, String text)
|
||||
{
|
||||
#if MC_VER >= MC_1_20_1
|
||||
commandContext.getSource().sendFailure(Component.literal(text));
|
||||
#elif MC_VER >= MC_1_19_2
|
||||
commandContext.getSource().sendFailure(Component.literal(text));
|
||||
#else
|
||||
commandContext.getSource().sendFailure(new TranslatableComponent(text));
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the server player from a command context.
|
||||
*
|
||||
* @param commandContext The command context to get the server player from.
|
||||
* @return The server player wrapper for the player who sent the command.
|
||||
*/
|
||||
protected IServerPlayerWrapper getSourcePlayer(CommandContext<CommandSourceStack> commandContext) #if MC_VER < MC_1_19_2 throws CommandSyntaxException #endif
|
||||
{
|
||||
#if MC_VER >= MC_1_19_2
|
||||
return ServerPlayerWrapper.getWrapper(Objects.requireNonNull(commandContext.getSource().getPlayer()));
|
||||
#else
|
||||
return ServerPlayerWrapper.getWrapper(commandContext.getSource().getPlayerOrException());
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the source of a command is a player.
|
||||
*
|
||||
* @param source The source of the command to check.
|
||||
* @return True if the source is a player, false otherwise.
|
||||
*/
|
||||
protected boolean isPlayerSource(CommandSourceStack source)
|
||||
{
|
||||
#if MC_VER >= MC_1_19_2
|
||||
return source.isPlayer();
|
||||
#else
|
||||
try
|
||||
{
|
||||
source.getPlayerOrException();
|
||||
return true;
|
||||
}
|
||||
catch (CommandSyntaxException e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.seibel.distanthorizons.common.commands;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
|
||||
import static com.seibel.distanthorizons.core.network.messages.MessageRegistry.DEBUG_CODEC_CRASH_MESSAGE;
|
||||
import static net.minecraft.commands.Commands.literal;
|
||||
|
||||
/**
|
||||
* Initializes commands of the mod.
|
||||
*/
|
||||
public class CommandInitializer
|
||||
{
|
||||
private final CommandDispatcher<CommandSourceStack> commandDispatcher;
|
||||
|
||||
/**
|
||||
* Constructs a new instance of this class.
|
||||
*
|
||||
* @param commandDispatcher The dispatcher to use for registering commands.
|
||||
*/
|
||||
public CommandInitializer(CommandDispatcher<CommandSourceStack> commandDispatcher)
|
||||
{
|
||||
this.commandDispatcher = commandDispatcher;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Initializes all available commands.
|
||||
*/
|
||||
public void initCommands()
|
||||
{
|
||||
LiteralArgumentBuilder<CommandSourceStack> builder = literal("dh")
|
||||
.requires(source -> source.hasPermission(4));
|
||||
|
||||
builder.then(new ConfigCommand().buildCommand());
|
||||
builder.then(new DebugCommand().buildCommand());
|
||||
builder.then(new PregenCommand().buildCommand());
|
||||
|
||||
if (DEBUG_CODEC_CRASH_MESSAGE)
|
||||
{
|
||||
builder.then(new CrashCommand().buildCommand());
|
||||
}
|
||||
|
||||
this.commandDispatcher.register(builder);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,154 @@
|
||||
package com.seibel.distanthorizons.common.commands;
|
||||
|
||||
import com.mojang.brigadier.arguments.*;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.seibel.distanthorizons.core.config.ConfigBase;
|
||||
import com.seibel.distanthorizons.core.config.types.AbstractConfigType;
|
||||
import com.seibel.distanthorizons.core.config.types.ConfigEntry;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.function.ToIntBiFunction;
|
||||
|
||||
import static com.mojang.brigadier.arguments.DoubleArgumentType.doubleArg;
|
||||
import static com.mojang.brigadier.arguments.IntegerArgumentType.integer;
|
||||
import static net.minecraft.commands.Commands.argument;
|
||||
import static net.minecraft.commands.Commands.literal;
|
||||
|
||||
/**
|
||||
* Command for managing config.
|
||||
*/
|
||||
public class ConfigCommand extends AbstractCommand
|
||||
{
|
||||
private static final List<CommandArgumentData<?>> commandArguments = Arrays.asList(
|
||||
new CommandArgumentData<>(Integer.class, configEntry -> integer(configEntry.getMin(), configEntry.getMax()), IntegerArgumentType::getInteger),
|
||||
new CommandArgumentData<>(Double.class, configEntry -> doubleArg(configEntry.getMin(), configEntry.getMax()), DoubleArgumentType::getDouble),
|
||||
new CommandArgumentData<>(Boolean.class, BoolArgumentType::bool, BoolArgumentType::getBool),
|
||||
new CommandArgumentData<>(String.class, StringArgumentType::string, StringArgumentType::getString)
|
||||
);
|
||||
|
||||
/**
|
||||
* Builds a command tree.
|
||||
*/
|
||||
@Override
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public LiteralArgumentBuilder<CommandSourceStack> buildCommand()
|
||||
{
|
||||
LiteralArgumentBuilder<CommandSourceStack> builder = literal("config");
|
||||
HashSet<String> addedCommands = new HashSet<>();
|
||||
|
||||
for (AbstractConfigType<?, ?> type : ConfigBase.INSTANCE.entries)
|
||||
{
|
||||
// Skip non-config entries
|
||||
if (!(type instanceof ConfigEntry))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//noinspection PatternVariableCanBeUsed
|
||||
ConfigEntry configEntry = (ConfigEntry) type;
|
||||
if (configEntry.getChatCommandName() == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!addedCommands.add(configEntry.getChatCommandName()))
|
||||
{
|
||||
throw new IllegalStateException("Duplicate command name: " + configEntry.getChatCommandName());
|
||||
}
|
||||
|
||||
LiteralArgumentBuilder<CommandSourceStack> subcommand = literal(configEntry.getChatCommandName())
|
||||
.executes(commandContext -> this.sendSuccessResponse(commandContext,
|
||||
"\n" +
|
||||
"Description of §l" + configEntry.getChatCommandName() + "§r:\n" +
|
||||
"§o" + configEntry.getComment().trim() + "§r\n" +
|
||||
"§7Config file name: §f" + configEntry.name + "§7, category: §f" + configEntry.category + "\n" +
|
||||
"\n" +
|
||||
"Current value of " + configEntry.getChatCommandName() + " is §n" + configEntry.get() + "§r",
|
||||
false
|
||||
));
|
||||
|
||||
ToIntBiFunction<CommandContext<CommandSourceStack>, Object> updateConfigValue = (commandContext, value) -> {
|
||||
configEntry.set(value);
|
||||
return this.sendSuccessResponse(commandContext, "Changed the value of [" + configEntry.getChatCommandName() + "] to [" + value + "]", true);
|
||||
};
|
||||
|
||||
// Enum type needs a special case since enums aren't represented by existing argument type
|
||||
// and need literals for each individual value
|
||||
if (Enum.class.isAssignableFrom(configEntry.getType()))
|
||||
{
|
||||
for (Object choice : configEntry.getType().getEnumConstants())
|
||||
{
|
||||
subcommand.then(
|
||||
literal(choice.toString())
|
||||
.executes(c -> updateConfigValue.applyAsInt(c, choice))
|
||||
);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
boolean setterAdded = false;
|
||||
for (CommandArgumentData<?> commandArgumentData : commandArguments)
|
||||
{
|
||||
if (!commandArgumentData.argumentClass.isAssignableFrom(configEntry.getType()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
subcommand.then(argument("value", commandArgumentData.getArgumentType(configEntry))
|
||||
.executes(c -> updateConfigValue.applyAsInt(c, commandArgumentData.getValue(c, "value"))));
|
||||
|
||||
setterAdded = true;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!setterAdded)
|
||||
{
|
||||
throw new RuntimeException("Config type of " + type.getName() + " is not supported: " + configEntry.getType().getSimpleName());
|
||||
}
|
||||
}
|
||||
|
||||
builder.then(subcommand);
|
||||
}
|
||||
|
||||
return builder;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static class CommandArgumentData<T>
|
||||
{
|
||||
public final Class<T> argumentClass;
|
||||
public final Function<ConfigEntry<T>, ArgumentType<T>> argumentTypeFunction;
|
||||
private final BiFunction<CommandContext<CommandSourceStack>, String, T> valueGetter;
|
||||
|
||||
public CommandArgumentData(Class<T> argumentClass, Supplier<ArgumentType<T>> argumentTypeSupplier, BiFunction<CommandContext<CommandSourceStack>, String, T> valueGetter)
|
||||
{
|
||||
this(argumentClass, configEntry -> argumentTypeSupplier.get(), valueGetter);
|
||||
}
|
||||
public CommandArgumentData(Class<T> argumentClass, Function<ConfigEntry<T>, ArgumentType<T>> argumentTypeFunction, BiFunction<CommandContext<CommandSourceStack>, String, T> valueGetter)
|
||||
{
|
||||
this.argumentClass = argumentClass;
|
||||
this.argumentTypeFunction = argumentTypeFunction;
|
||||
this.valueGetter = valueGetter;
|
||||
}
|
||||
|
||||
public ArgumentType<T> getArgumentType(ConfigEntry<T> configEntry)
|
||||
{
|
||||
return this.argumentTypeFunction.apply(configEntry);
|
||||
}
|
||||
|
||||
public T getValue(CommandContext<CommandSourceStack> commandContext, String argumentName)
|
||||
{
|
||||
return this.valueGetter.apply(commandContext, argumentName);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.seibel.distanthorizons.common.commands;
|
||||
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.seibel.distanthorizons.core.api.internal.SharedApi;
|
||||
import com.seibel.distanthorizons.core.multiplayer.server.ServerPlayerState;
|
||||
import com.seibel.distanthorizons.core.network.messages.base.CodecCrashMessage;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
|
||||
import static net.minecraft.commands.Commands.literal;
|
||||
|
||||
public class CrashCommand extends AbstractCommand
|
||||
{
|
||||
@Override
|
||||
public LiteralArgumentBuilder<CommandSourceStack> buildCommand()
|
||||
{
|
||||
return literal("crash")
|
||||
.requires(this::isPlayerSource)
|
||||
.then(literal("encode")
|
||||
.executes(c -> {
|
||||
assert SharedApi.getIDhServerWorld() != null;
|
||||
|
||||
ServerPlayerState serverPlayerState = SharedApi.getIDhServerWorld().getServerPlayerStateManager()
|
||||
.getConnectedPlayer(this.getSourcePlayer(c));
|
||||
if (serverPlayerState != null)
|
||||
{
|
||||
serverPlayerState.networkSession.sendMessage(new CodecCrashMessage(CodecCrashMessage.ECrashPhase.ENCODE));
|
||||
}
|
||||
return 1;
|
||||
}))
|
||||
.then(literal("decode")
|
||||
.executes(c -> {
|
||||
assert SharedApi.getIDhServerWorld() != null;
|
||||
|
||||
ServerPlayerState serverPlayerState = SharedApi.getIDhServerWorld().getServerPlayerStateManager()
|
||||
.getConnectedPlayer(this.getSourcePlayer(c));
|
||||
if (serverPlayerState != null)
|
||||
{
|
||||
serverPlayerState.networkSession.sendMessage(new CodecCrashMessage(CodecCrashMessage.ECrashPhase.DECODE));
|
||||
}
|
||||
return 1;
|
||||
}));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.seibel.distanthorizons.common.commands;
|
||||
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.seibel.distanthorizons.core.logging.f3.F3Screen;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static net.minecraft.commands.Commands.literal;
|
||||
|
||||
public class DebugCommand extends AbstractCommand
|
||||
{
|
||||
@Override
|
||||
public LiteralArgumentBuilder<CommandSourceStack> buildCommand()
|
||||
{
|
||||
return literal("debug")
|
||||
.executes(c -> {
|
||||
List<String> lines = new ArrayList<>();
|
||||
F3Screen.addStringToDisplay(lines);
|
||||
return this.sendSuccessResponse(c, String.join("\n", lines), false);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package com.seibel.distanthorizons.common.commands;
|
||||
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
|
||||
import com.seibel.distanthorizons.core.generation.PregenManager;
|
||||
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos2D;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.arguments.DimensionArgument;
|
||||
import net.minecraft.commands.arguments.coordinates.ColumnPosArgument;
|
||||
import net.minecraft.server.level.ColumnPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
import static com.mojang.brigadier.arguments.IntegerArgumentType.getInteger;
|
||||
import static com.mojang.brigadier.arguments.IntegerArgumentType.integer;
|
||||
import static net.minecraft.commands.Commands.argument;
|
||||
import static net.minecraft.commands.Commands.literal;
|
||||
|
||||
public class PregenCommand extends AbstractCommand
|
||||
{
|
||||
private final PregenManager pregenManager = new PregenManager();
|
||||
|
||||
@Override
|
||||
public LiteralArgumentBuilder<CommandSourceStack> buildCommand()
|
||||
{
|
||||
LiteralArgumentBuilder<CommandSourceStack> statusCommand = literal("status")
|
||||
.executes(this::pregenStatus);
|
||||
|
||||
LiteralArgumentBuilder<CommandSourceStack> startCommand = literal("start")
|
||||
.then(argument("dimension", DimensionArgument.dimension())
|
||||
.then(argument("origin", ColumnPosArgument.columnPos())
|
||||
.then(argument("chunkRadius", integer(32))
|
||||
.executes(this::pregenStart))));
|
||||
|
||||
LiteralArgumentBuilder<CommandSourceStack> stopCommand = literal("stop")
|
||||
.executes(this::pregenStop);
|
||||
|
||||
return literal("pregen")
|
||||
.then(statusCommand)
|
||||
.then(startCommand)
|
||||
.then(stopCommand);
|
||||
}
|
||||
|
||||
|
||||
private int pregenStatus(CommandContext<CommandSourceStack> c)
|
||||
{
|
||||
String statusString = this.pregenManager.getStatusString();
|
||||
//noinspection ReplaceNullCheck
|
||||
if (statusString != null)
|
||||
{
|
||||
return this.sendSuccessResponse(c, statusString, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.sendSuccessResponse(c, "Pregen is not running", false);
|
||||
}
|
||||
}
|
||||
|
||||
private int pregenStart(CommandContext<CommandSourceStack> c) throws CommandSyntaxException
|
||||
{
|
||||
this.sendSuccessResponse(c, "Starting pregen. Progress will be in the server console.", true);
|
||||
|
||||
ServerLevel level = DimensionArgument.getDimension(c, "dimension");
|
||||
ColumnPos origin = ColumnPosArgument.getColumnPos(c, "origin");
|
||||
int chunkRadius = getInteger(c, "chunkRadius");
|
||||
|
||||
CompletableFuture<Void> future = this.pregenManager.startPregen(
|
||||
ServerLevelWrapper.getWrapper(level),
|
||||
new DhBlockPos2D(#if MC_VER >= MC_1_19_2 origin.x(), origin.z() #else origin.x, origin.z #endif),
|
||||
chunkRadius
|
||||
);
|
||||
|
||||
future.whenComplete((result, throwable) -> {
|
||||
if (throwable instanceof CancellationException)
|
||||
{
|
||||
this.sendSuccessResponse(c, "Pregen is cancelled", true);
|
||||
return;
|
||||
}
|
||||
else if (throwable != null)
|
||||
{
|
||||
this.sendFailureResponse(c, "Pregen failed: " + throwable.getMessage() + "\n Check the logs for more details.");
|
||||
return;
|
||||
}
|
||||
|
||||
this.sendSuccessResponse(c, "Pregen is complete", true);
|
||||
});
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
private int pregenStop(CommandContext<CommandSourceStack> c)
|
||||
{
|
||||
CompletableFuture<Void> runningPregen = this.pregenManager.getRunningPregen();
|
||||
if (runningPregen == null)
|
||||
{
|
||||
return this.sendFailureResponse(c, "Pregen is not running");
|
||||
}
|
||||
|
||||
runningPregen.cancel(true);
|
||||
return 1;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package com.seibel.distanthorizons.common.commonMixins;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.world.ServerLevelWrapper;
|
||||
import com.seibel.distanthorizons.core.api.internal.ServerApi;
|
||||
import com.seibel.distanthorizons.core.api.internal.SharedApi;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.chunk.ChunkAccess;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
public class MixinChunkMapCommon
|
||||
{
|
||||
|
||||
public static void onChunkSave(ServerLevel level, ChunkAccess chunk, CallbackInfoReturnable<Boolean> ci)
|
||||
{
|
||||
// is this position already being updated?
|
||||
if (SharedApi.isChunkAtChunkPosAlreadyUpdating(chunk.getPos().x, chunk.getPos().z))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// is this chunk being saved to disk?
|
||||
boolean savingChunkToDisk = ci.getReturnValue();
|
||||
// true means a chunk was saved to disk
|
||||
if (!savingChunkToDisk)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO are the following validations necessary since we are checking above if
|
||||
// the callback return value should state if the chunk was actually saved or not?
|
||||
// Do we trust it to always be correct?
|
||||
|
||||
|
||||
|
||||
// corrupt/incomplete chunk validation //
|
||||
|
||||
// MC has a tendency to try saving incomplete or corrupted chunks (which show up as empty or black chunks)
|
||||
// this logic should prevent that from happening
|
||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||
if (chunk.isUnsaved() || chunk.getUpgradeData() != null || !chunk.isLightCorrect())
|
||||
{
|
||||
return;
|
||||
}
|
||||
#else
|
||||
if (chunk.isUnsaved() || chunk.isUpgrading() || !chunk.isLightCorrect())
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// biome validation //
|
||||
|
||||
// some chunks may be missing their biomes, which cause issues when attempting to save them
|
||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||
if (chunk.getBiomes() == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#else
|
||||
try
|
||||
{
|
||||
// this will throw an exception if the biomes aren't set up
|
||||
chunk.getNoiseBiome(0,0,0);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// submit the update event
|
||||
ServerApi.INSTANCE.serverChunkSaveEvent(
|
||||
new ChunkWrapper(chunk, ServerLevelWrapper.getWrapper(level)),
|
||||
ServerLevelWrapper.getWrapper(level)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.util;
|
||||
|
||||
/**
|
||||
* 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 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,78 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.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.MinecraftGLWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.minecraft.MinecraftServerWrapper;
|
||||
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.IMinecraftGLWrapper;
|
||||
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, MinecraftServerWrapper.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(IMinecraftGLWrapper.class, MinecraftGLWrapper.INSTANCE);
|
||||
SingletonInjector.INSTANCE.bind(IConfigGui.class, ClassicConfigGUI.CONFIG_CORE_INTERFACE);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class DependencySetupDoneCheck
|
||||
{
|
||||
// TODO move to DependencySetup
|
||||
public static boolean isDone = false;
|
||||
/**
|
||||
* This is used so we can override some MC logic when running
|
||||
* in DH's world generator.
|
||||
* Specifically so we can redirect threads to run on DH threads instead
|
||||
* of MC threads.
|
||||
*/
|
||||
public static Supplier<Boolean> getIsCurrentThreadDistantGeneratorThread = (() -> { return false; });
|
||||
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers;
|
||||
|
||||
import java.nio.FloatBuffer;
|
||||
|
||||
import com.seibel.distanthorizons.core.enums.EDhDirection;
|
||||
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos;
|
||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||
import com.seibel.distanthorizons.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
|
||||
{
|
||||
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
|
||||
#elif MC_VER < MC_1_21_6 org.joml.Matrix4f
|
||||
#else org.joml.Matrix4fc
|
||||
#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
|
||||
#elif MC_VER < MC_1_21_6 org.joml.Matrix4f
|
||||
#else org.joml.Matrix4fc
|
||||
#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.getX(), wrappedPos.getY(), wrappedPos.getZ()); }
|
||||
public static ChunkPos Convert(DhChunkPos wrappedPos) { return new ChunkPos(wrappedPos.getX(), wrappedPos.getZ()); }
|
||||
|
||||
public static Direction Convert(EDhDirection lodDirection) { return directions[lodDirection.ordinal()]; }
|
||||
public static EDhDirection Convert(Direction direction) { return lodDirections[direction.ordinal()]; }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers;
|
||||
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.IVersionConstants;
|
||||
|
||||
/**
|
||||
* @author James Seibel
|
||||
* @version 12-11-2021
|
||||
*/
|
||||
public class VersionConstants implements IVersionConstants
|
||||
{
|
||||
public static final VersionConstants INSTANCE = new VersionConstants();
|
||||
|
||||
|
||||
private VersionConstants()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getMinecraftVersion()
|
||||
{
|
||||
// these values are hard-coded to prevent an issue with Forge (specifically 1.18.2) where
|
||||
// it can't load client classes when running as a dedicated server,
|
||||
// which was how we were dynamically accessing the MC version string
|
||||
|
||||
#if MC_VER == MC_1_16_5
|
||||
return "1.16.5";
|
||||
|
||||
#elif MC_VER == MC_1_17_1
|
||||
return "1.17.1";
|
||||
|
||||
#elif MC_VER == MC_1_18_2
|
||||
return "1.18.2";
|
||||
|
||||
#elif MC_VER == MC_1_19_2
|
||||
return "1.19.2";
|
||||
#elif MC_VER == MC_1_19_4
|
||||
return "1.19.4";
|
||||
|
||||
#elif MC_VER == MC_1_20_1
|
||||
return "1.20.1";
|
||||
#elif MC_VER == MC_1_20_2
|
||||
return "1.20.2";
|
||||
#elif MC_VER == MC_1_20_4
|
||||
return "1.20.4";
|
||||
#elif MC_VER == MC_1_20_6
|
||||
return "1.20.6";
|
||||
|
||||
#elif MC_VER == MC_1_21_1
|
||||
return "1.21.1";
|
||||
#elif MC_VER == MC_1_21_3
|
||||
return "1.21.3";
|
||||
#elif MC_VER == MC_1_21_4
|
||||
return "1.21.4";
|
||||
#elif MC_VER == MC_1_21_5
|
||||
return "1.21.5";
|
||||
#elif MC_VER == MC_1_21_6
|
||||
return "1.21.6";
|
||||
#elif MC_VER == MC_1_21_8
|
||||
return "1.21.8";
|
||||
#else
|
||||
ERROR MC version constant missing
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,357 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.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.
|
||||
*/
|
||||
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 IDhApiBiomeWrapper getBiomeWrapper(String resourceLocationString, IDhApiLevelWrapper levelWrapper) throws IOException, ClassCastException
|
||||
{
|
||||
if (!(levelWrapper instanceof ILevelWrapper))
|
||||
{
|
||||
throw new ClassCastException("levelWrapper must be returned by DH and of type ["+ILevelWrapper.class.getName()+"].");
|
||||
}
|
||||
|
||||
return BiomeWrapper.deserialize(resourceLocationString, (ILevelWrapper)levelWrapper);
|
||||
}
|
||||
@Override
|
||||
public IDhApiBlockStateWrapper getDefaultBlockStateWrapper(String resourceLocationString, IDhApiLevelWrapper levelWrapper) throws IOException, ClassCastException
|
||||
{
|
||||
if (!(levelWrapper instanceof ILevelWrapper))
|
||||
{
|
||||
throw new ClassCastException("Invalid ["+IDhApiLevelWrapper.class.getSimpleName()+"] value given. Level wrapper object must be one given by the DH API (it can't be a custom implementation), specifically of type ["+ILevelWrapper.class.getName()+"].");
|
||||
}
|
||||
|
||||
return BlockStateWrapper.deserialize(resourceLocationString, (ILevelWrapper)levelWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
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); }
|
||||
@Override
|
||||
public HashSet<IBlockStateWrapper> getRendererIgnoredCaveBlocks(ILevelWrapper levelWrapper) { return BlockStateWrapper.getRendererIgnoredCaveBlocks(levelWrapper); }
|
||||
|
||||
@Override
|
||||
public void resetRendererIgnoredCaveBlocks() { BlockStateWrapper.clearRendererIgnoredCaveBlocks(); }
|
||||
@Override
|
||||
public void resetRendererIgnoredBlocksSet() { BlockStateWrapper.clearRendererIgnoredBlocks(); }
|
||||
|
||||
|
||||
/**
|
||||
* 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_XX_X
|
||||
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];
|
||||
|
||||
|
||||
// level wrapper
|
||||
ILevelWrapper levelWrapper = level.isClientSide()
|
||||
? ClientLevelWrapper.getWrapper((ClientLevel)level)
|
||||
: ServerLevelWrapper.getWrapper((ServerLevel)level);
|
||||
|
||||
|
||||
return new ChunkWrapper(chunk, levelWrapper);
|
||||
}
|
||||
// incorrect number of parameters from the API
|
||||
else
|
||||
{
|
||||
throw new ClassCastException(createChunkWrapperErrorMessage(objectArray));
|
||||
}
|
||||
//#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_XX_X
|
||||
expectedClassNames = new String[]
|
||||
{
|
||||
ChunkAccess.class.getName(),
|
||||
"[ServerLevel] or [ClientLevel]" // Classes are not referenced by names to avoid exception when one of them is missing
|
||||
};
|
||||
//#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("Invalid ["+IDhApiLevelWrapper.class.getSimpleName()+"] value given. Level wrapper object must be one given by the DH API (it can't be a custom implementation), specifically of type ["+ILevelWrapper.class.getName()+"].");
|
||||
}
|
||||
ILevelWrapper coreLevelWrapper = (ILevelWrapper) levelWrapper;
|
||||
|
||||
|
||||
|
||||
#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);
|
||||
#else
|
||||
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);
|
||||
#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() };
|
||||
#else
|
||||
expectedClassNames = new String[] { Holder.class.getName()+"<"+Biome.class.getName()+">" };
|
||||
#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("Invalid ["+IDhApiLevelWrapper.class.getSimpleName()+"] value given. Level wrapper object must be one given by the DH API (it can't be a custom implementation), specifically of type ["+ILevelWrapper.class.getName()+"].");
|
||||
}
|
||||
ILevelWrapper coreLevelWrapper = (ILevelWrapper) levelWrapper;
|
||||
|
||||
|
||||
|
||||
//#if MC_VER <= MC_1_XX_X
|
||||
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);
|
||||
//#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() };
|
||||
#else
|
||||
expectedClassNames = new String[] { Holder.class.getName()+"<"+Biome.class.getName()+">" };
|
||||
#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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,394 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers.block;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
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+"]");
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// 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());
|
||||
#elif MC_VER < MC_1_21_3
|
||||
resourceLocation = registryAccess.registryOrThrow(Registries.BIOME).getKey(this.biome.value());
|
||||
#else
|
||||
resourceLocation = registryAccess.lookupOrThrow(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
|
||||
{
|
||||
try
|
||||
{
|
||||
Level level = (Level) levelWrapper.getWrappedMcObject();
|
||||
net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
|
||||
|
||||
BiomeDeserializeResult deserializeResult = deserializeBiome(resourceLocationString, registryAccess);
|
||||
|
||||
|
||||
|
||||
if (!deserializeResult.success)
|
||||
{
|
||||
if (!brokenResourceLocationStrings.contains(resourceLocationString))
|
||||
{
|
||||
brokenResourceLocationStrings.add(resourceLocationString);
|
||||
LOGGER.warn("Unable to deserialize biome from string: [" + resourceLocationString + "]");
|
||||
}
|
||||
return EMPTY_WRAPPER;
|
||||
}
|
||||
|
||||
|
||||
foundWrapper = (BiomeWrapper) getBiomeWrapper(deserializeResult.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);
|
||||
}
|
||||
}
|
||||
|
||||
public static BiomeDeserializeResult deserializeBiome(String resourceLocationString, net.minecraft.core.RegistryAccess registryAccess) throws IOException
|
||||
{
|
||||
// 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_1
|
||||
resourceLocation = new ResourceLocation(resourceLocationString.substring(0, separatorIndex), resourceLocationString.substring(separatorIndex + 1));
|
||||
#else
|
||||
resourceLocation = ResourceLocation.fromNamespaceAndPath(resourceLocationString.substring(0, separatorIndex), resourceLocationString.substring(separatorIndex + 1));
|
||||
#endif
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new IOException("No Resource Location found for the string: [" + resourceLocationString + "] Error: [" + e.getMessage() + "].");
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
#elif MC_VER < MC_1_21_3
|
||||
Biome unwrappedBiome = registryAccess.registryOrThrow(Registries.BIOME).get(resourceLocation);
|
||||
success = (unwrappedBiome != null);
|
||||
Holder<Biome> biome = new Holder.Direct<>(unwrappedBiome);
|
||||
#else
|
||||
Holder<Biome> biome;
|
||||
Optional<Holder.Reference<Biome>> optionalBiomeHolder = registryAccess.lookupOrThrow(Registries.BIOME).get(resourceLocation);
|
||||
if (optionalBiomeHolder.isPresent())
|
||||
{
|
||||
Biome unwrappedBiome = optionalBiomeHolder.get().value();
|
||||
success = (unwrappedBiome != null);
|
||||
biome = new Holder.Direct<>(unwrappedBiome);
|
||||
}
|
||||
else
|
||||
{
|
||||
success = false;
|
||||
biome = null;
|
||||
}
|
||||
#endif
|
||||
|
||||
return new BiomeDeserializeResult(success, biome);
|
||||
}
|
||||
|
||||
|
||||
//================//
|
||||
// helper classes //
|
||||
//================//
|
||||
|
||||
public static class BiomeDeserializeResult
|
||||
{
|
||||
public final boolean success;
|
||||
|
||||
#if MC_VER < MC_1_18_2
|
||||
public final Biome biome;
|
||||
#else
|
||||
public final Holder<Biome> biome;
|
||||
#endif
|
||||
|
||||
public BiomeDeserializeResult(boolean success, #if MC_VER < MC_1_18_2 Biome #else Holder<Biome> #endif biome)
|
||||
{
|
||||
this.success = success;
|
||||
this.biome = biome;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,864 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers.block;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.rendering.EDhApiBlockMaterial;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.config.types.ConfigEntry;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.util.ColorUtil;
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
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.BeaconBeamBlock;
|
||||
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.awt.*;
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
#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.world.level.Level;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.world.level.EmptyBlockGetter;
|
||||
import net.minecraft.core.Holder;
|
||||
#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";
|
||||
|
||||
public static HashSet<IBlockStateWrapper> rendererIgnoredBlocks = null;
|
||||
public static HashSet<IBlockStateWrapper> rendererIgnoredCaveBlocks = null;
|
||||
|
||||
/** keep track of broken blocks so we don't log every time */
|
||||
private static final HashSet<ResourceLocation> BROKEN_RESOURCE_LOCATIONS = new HashSet<>();
|
||||
|
||||
|
||||
|
||||
// properties //
|
||||
|
||||
@Nullable
|
||||
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;
|
||||
/** Should be between {@link LodUtil#BLOCK_FULLY_OPAQUE} and {@link LodUtil#BLOCK_FULLY_OPAQUE} */
|
||||
private final int opacity;
|
||||
/** used by the Iris shader mod to determine how each LOD should be rendered */
|
||||
private byte blockMaterialId = 0;
|
||||
|
||||
private final boolean isBeaconBlock;
|
||||
private final boolean isBeaconBaseBlock;
|
||||
private final boolean allowsBeaconBeamPassage;
|
||||
/** null if this block can't tint beacons */
|
||||
private final Color beaconTintColor;
|
||||
private final Color mapColor;
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Can be faster than {@link BlockStateWrapper#fromBlockState(BlockState, ILevelWrapper)}
|
||||
* in cases where the same block state is expected to be referenced multiple times.
|
||||
*/
|
||||
public static BlockStateWrapper fromBlockState(BlockState blockState, ILevelWrapper levelWrapper, IBlockStateWrapper guess)
|
||||
{
|
||||
BlockState guessBlockState = (guess == null || guess.isAir()) ? null : (BlockState) guess.getWrappedMcObject();
|
||||
BlockState inputBlockState = (blockState == null || blockState.isAir()) ? null : blockState;
|
||||
|
||||
if (guess instanceof BlockStateWrapper
|
||||
&& guessBlockState == inputBlockState)
|
||||
{
|
||||
return (BlockStateWrapper) guess;
|
||||
}
|
||||
else
|
||||
{
|
||||
return fromBlockState(blockState, levelWrapper);
|
||||
}
|
||||
}
|
||||
|
||||
private BlockStateWrapper(BlockState blockState, ILevelWrapper levelWrapper)
|
||||
{
|
||||
this.blockState = blockState;
|
||||
this.serialString = this.serialize(levelWrapper);
|
||||
this.hashCode = Objects.hash(this.serialString);
|
||||
this.blockMaterialId = this.calculateEDhApiBlockMaterialId().index;
|
||||
this.opacity = this.calculateOpacity();
|
||||
|
||||
String lowercaseSerial = this.serialString.toLowerCase();
|
||||
|
||||
|
||||
// beacon blocks
|
||||
boolean isBeaconBaseBlock = false;
|
||||
for (int i = 0; i < LodUtil.BEACON_BASE_BLOCK_NAME_LIST.size(); i++)
|
||||
{
|
||||
String baseBlockName = LodUtil.BEACON_BASE_BLOCK_NAME_LIST.get(i);
|
||||
if (lowercaseSerial.contains(baseBlockName))
|
||||
{
|
||||
isBeaconBaseBlock = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
this.isBeaconBaseBlock = isBeaconBaseBlock;
|
||||
this.isBeaconBlock = lowercaseSerial.contains("minecraft:beacon");
|
||||
|
||||
// beacon tint color
|
||||
Color beaconTintColor = null;
|
||||
if (this.blockState != null
|
||||
// beacon blocks also show up here, but since they block the beacon beam we don't want their color
|
||||
&& !this.isBeaconBlock)
|
||||
{
|
||||
Block block = this.blockState.getBlock();
|
||||
if (block instanceof BeaconBeamBlock)
|
||||
{
|
||||
int colorInt;
|
||||
#if MC_VER <= MC_1_19_4
|
||||
colorInt = ((BeaconBeamBlock) block).getColor().getMaterialColor().col;
|
||||
#else
|
||||
colorInt = ((BeaconBeamBlock) block).getColor().getMapColor().col;
|
||||
#endif
|
||||
|
||||
beaconTintColor = ColorUtil.toColorObjRGB(colorInt);
|
||||
}
|
||||
}
|
||||
this.beaconTintColor = beaconTintColor;
|
||||
|
||||
|
||||
// allow/deny beacon beam passage
|
||||
boolean allowsBeaconBeamPassage;
|
||||
if (this.blockState != null)
|
||||
{
|
||||
// get block properties (defaults to the values used by air)
|
||||
boolean canOcclude = this.getCanOcclude();
|
||||
boolean propagatesSkyLightDown = this.getPropagatesSkyLightDown();
|
||||
|
||||
if (lowercaseSerial.contains("minecraft:bedrock"))
|
||||
{
|
||||
// bedrock is a special case fully opaque block that does allow beacons through
|
||||
allowsBeaconBeamPassage = true;
|
||||
}
|
||||
else if (propagatesSkyLightDown || !canOcclude)
|
||||
{
|
||||
// stairs, cake, fences, etc.
|
||||
allowsBeaconBeamPassage = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// non-opaque blocks (glass, mob spawners, etc.)
|
||||
// all allow beacons through
|
||||
allowsBeaconBeamPassage = (this.opacity != LodUtil.BLOCK_FULLY_OPAQUE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// air allows beacons through
|
||||
allowsBeaconBeamPassage = true;
|
||||
}
|
||||
this.allowsBeaconBeamPassage = allowsBeaconBeamPassage;
|
||||
|
||||
|
||||
int mcColor = 0;
|
||||
if (this.blockState != null)
|
||||
{
|
||||
#if MC_VER < MC_1_20_1
|
||||
mcColor = this.blockState.getMaterial().getColor().col;
|
||||
#else
|
||||
mcColor = this.blockState.getMapColor(EmptyBlockGetter.INSTANCE, BlockPos.ZERO).col;
|
||||
#endif
|
||||
this.mapColor = ColorUtil.toColorObjRGB(mcColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.mapColor = new Color(0,0,0,0);
|
||||
}
|
||||
|
||||
//LOGGER.trace("Created BlockStateWrapper ["+this.serialString+"] for ["+blockState+"] with material ID ["+this.EDhApiBlockMaterialId+"]");
|
||||
}
|
||||
|
||||
|
||||
|
||||
//====================//
|
||||
// LodBuilder 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;
|
||||
}
|
||||
|
||||
HashSet<String> baseIgnoredBlock = new HashSet<>();
|
||||
baseIgnoredBlock.add(AIR_STRING);
|
||||
rendererIgnoredBlocks = getBlockWrappers(Config.Client.Advanced.Graphics.Culling.ignoredRenderBlockCsv, baseIgnoredBlock, levelWrapper);
|
||||
return rendererIgnoredBlocks;
|
||||
}
|
||||
/**
|
||||
* Requires a {@link ILevelWrapper} since {@link BlockStateWrapper#deserialize(String,ILevelWrapper)} also requires one.
|
||||
* This way the method won't accidentally be called before the deserialization can be completed.
|
||||
*/
|
||||
public static HashSet<IBlockStateWrapper> getRendererIgnoredCaveBlocks(ILevelWrapper levelWrapper)
|
||||
{
|
||||
// use the cached version if possible
|
||||
if (rendererIgnoredCaveBlocks != null)
|
||||
{
|
||||
return rendererIgnoredCaveBlocks;
|
||||
}
|
||||
|
||||
HashSet<String> baseIgnoredBlock = new HashSet<>();
|
||||
baseIgnoredBlock.add(AIR_STRING);
|
||||
rendererIgnoredCaveBlocks = getBlockWrappers(Config.Client.Advanced.Graphics.Culling.ignoredRenderCaveBlockCsv, baseIgnoredBlock, levelWrapper);
|
||||
return rendererIgnoredCaveBlocks;
|
||||
}
|
||||
|
||||
public static void clearRendererIgnoredBlocks() { rendererIgnoredBlocks = null; }
|
||||
public static void clearRendererIgnoredCaveBlocks() { rendererIgnoredCaveBlocks = null; }
|
||||
|
||||
|
||||
|
||||
// lod builder helpers //
|
||||
|
||||
private static HashSet<IBlockStateWrapper> getBlockWrappers(ConfigEntry<String> config, HashSet<String> baseResourceLocations, ILevelWrapper levelWrapper)
|
||||
{
|
||||
// get the base blocks
|
||||
HashSet<String> blockStringList = new HashSet<>();
|
||||
if (baseResourceLocations != null)
|
||||
{
|
||||
blockStringList.addAll(baseResourceLocations);
|
||||
}
|
||||
|
||||
// get the config blocks
|
||||
String ignoreBlockCsv = config.get();
|
||||
if (ignoreBlockCsv != null)
|
||||
{
|
||||
blockStringList.addAll(Arrays.asList(ignoreBlockCsv.split(",")));
|
||||
}
|
||||
|
||||
return getBlockWrappers(blockStringList, levelWrapper);
|
||||
}
|
||||
private static HashSet<IBlockStateWrapper> getBlockWrappers(HashSet<String> blockResourceLocationSet, ILevelWrapper levelWrapper)
|
||||
{
|
||||
// deserialize each of the given resource locations
|
||||
HashSet<IBlockStateWrapper> blockStateWrappers = new HashSet<>();
|
||||
for (String blockResourceLocation : blockResourceLocationSet)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (blockResourceLocation == null)
|
||||
{
|
||||
// shouldn't happen, but just in case
|
||||
continue;
|
||||
}
|
||||
String cleanedResourceLocation = blockResourceLocation.trim();
|
||||
if (cleanedResourceLocation.length() == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
BlockStateWrapper defaultBlockStateToIgnore = (BlockStateWrapper) deserialize(cleanedResourceLocation, levelWrapper);
|
||||
blockStateWrappers.add(defaultBlockStateToIgnore);
|
||||
|
||||
if (defaultBlockStateToIgnore != AIR)
|
||||
{
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// air is a special case so it must be handled separately
|
||||
blockStateWrappers.add(AIR);
|
||||
}
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
LOGGER.warn("Unable to deserialize block with the resource location: ["+blockResourceLocation+"]. Error: "+e.getMessage(), e);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.warn("Unexpected error deserializing block with the resource location: ["+blockResourceLocation+"]. Error: "+e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
return blockStateWrappers;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=================//
|
||||
// wrapper methods //
|
||||
//=================//
|
||||
|
||||
@Override
|
||||
public int getOpacity() { return this.opacity; }
|
||||
private int calculateOpacity()
|
||||
{
|
||||
// get block properties (defaults to the values used by air)
|
||||
boolean canOcclude = this.getCanOcclude();
|
||||
boolean propagatesSkyLightDown = this.getPropagatesSkyLightDown();
|
||||
|
||||
|
||||
|
||||
// this method isn't perfect, but works well enough for our use case
|
||||
int opacity;
|
||||
if (this.isAir())
|
||||
{
|
||||
opacity = LodUtil.BLOCK_FULLY_TRANSPARENT;
|
||||
}
|
||||
else if (this.isLiquid() && !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 = LodUtil.BLOCK_FULLY_TRANSPARENT + 1;
|
||||
}
|
||||
else if (propagatesSkyLightDown && !canOcclude)
|
||||
{
|
||||
// probably glass or some other fully transparent block
|
||||
|
||||
// !canOcclude is required to ignore stairs and slabs since
|
||||
// propagateSkyLightDown is true for them, but they're solid and don't actually let light through
|
||||
|
||||
opacity = LodUtil.BLOCK_FULLY_TRANSPARENT;
|
||||
}
|
||||
else
|
||||
{
|
||||
// default for all other blocks
|
||||
opacity = LodUtil.BLOCK_FULLY_OPAQUE;
|
||||
}
|
||||
|
||||
|
||||
return opacity;
|
||||
}
|
||||
private boolean getCanOcclude()
|
||||
{
|
||||
// defaults to the value used by air
|
||||
boolean canOcclude = false;
|
||||
if (this.blockState != null)
|
||||
{
|
||||
canOcclude = this.blockState.canOcclude();
|
||||
}
|
||||
|
||||
return canOcclude;
|
||||
}
|
||||
private boolean getPropagatesSkyLightDown()
|
||||
{
|
||||
// defaults to the value used by air
|
||||
boolean propagatesSkyLightDown = true;
|
||||
if (this.blockState != null)
|
||||
{
|
||||
#if MC_VER < MC_1_21_3
|
||||
propagatesSkyLightDown = this.blockState.propagatesSkylightDown(EmptyBlockGetter.INSTANCE, BlockPos.ZERO);
|
||||
#else
|
||||
propagatesSkyLightDown = this.blockState.propagatesSkylightDown();
|
||||
#endif
|
||||
}
|
||||
|
||||
return propagatesSkyLightDown;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@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 (this.isAir())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
#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 boolean isBeaconBlock() { return this.isBeaconBlock; }
|
||||
@Override
|
||||
public boolean isBeaconBaseBlock() { return this.isBeaconBaseBlock; }
|
||||
@Override
|
||||
public boolean isBeaconTintBlock() { return this.beaconTintColor != null; }
|
||||
@Override
|
||||
public boolean allowsBeaconBeamPassage() { return this.allowsBeaconBeamPassage; }
|
||||
|
||||
@Override
|
||||
public Color getMapColor() { return this.mapColor; }
|
||||
@Override
|
||||
public Color getBeaconTintColor() { return this.beaconTintColor; }
|
||||
|
||||
@Override
|
||||
public byte getMaterialId() { return this.blockMaterialId; }
|
||||
|
||||
@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());
|
||||
#elif MC_VER < MC_1_21_3
|
||||
resourceLocation = registryAccess.registryOrThrow(Registries.BLOCK).getKey(this.blockState.getBlock());
|
||||
#else
|
||||
resourceLocation = registryAccess.lookupOrThrow(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_1
|
||||
resourceLocation = new ResourceLocation(resourceStateString.substring(0, separatorIndex), resourceStateString.substring(separatorIndex + 1));
|
||||
#else
|
||||
resourceLocation = ResourceLocation.fromNamespaceAndPath(resourceStateString.substring(0, separatorIndex), resourceStateString.substring(separatorIndex + 1));
|
||||
#endif
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
throw new IOException("No Resource Location found for the string: [" + resourceStateString + "] Error: [" + e.getMessage() + "].");
|
||||
}
|
||||
|
||||
|
||||
|
||||
// attempt to get the BlockState from all possible BlockStates
|
||||
try
|
||||
{
|
||||
|
||||
#if MC_VER > MC_1_17_1
|
||||
LodUtil.assertTrue(levelWrapper != null && levelWrapper.getWrappedMcObject() != null);
|
||||
Level level = (Level)levelWrapper.getWrappedMcObject();
|
||||
#endif
|
||||
|
||||
Block block;
|
||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||
block = Registry.BLOCK.get(resourceLocation);
|
||||
#elif MC_VER == MC_1_18_2 || MC_VER == MC_1_19_2
|
||||
net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
|
||||
block = registryAccess.registryOrThrow(Registry.BLOCK_REGISTRY).get(resourceLocation);
|
||||
#elif MC_VER < MC_1_21_3
|
||||
net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
|
||||
block = registryAccess.registryOrThrow(Registries.BLOCK).get(resourceLocation);
|
||||
#else
|
||||
net.minecraft.core.RegistryAccess registryAccess = level.registryAccess();
|
||||
Optional<Holder.Reference<Block>> optionalBlockHolder = registryAccess.lookupOrThrow(Registries.BLOCK).get(resourceLocation);
|
||||
block = optionalBlockHolder.isPresent() ? optionalBlockHolder.get().value() : null;
|
||||
#endif
|
||||
|
||||
|
||||
if (block == null)
|
||||
{
|
||||
// shouldn't normally happen, but here to make the compiler happy
|
||||
if (!BROKEN_RESOURCE_LOCATIONS.contains(resourceLocation))
|
||||
{
|
||||
BROKEN_RESOURCE_LOCATIONS.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 (!BROKEN_RESOURCE_LOCATIONS.contains(resourceLocation))
|
||||
{
|
||||
BROKEN_RESOURCE_LOCATIONS.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 EDhApiBlockMaterial calculateEDhApiBlockMaterialId()
|
||||
{
|
||||
if (this.blockState == null)
|
||||
{
|
||||
return EDhApiBlockMaterial.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 EDhApiBlockMaterial.LEAVES;
|
||||
}
|
||||
else if (this.blockState.is(Blocks.LAVA))
|
||||
{
|
||||
return EDhApiBlockMaterial.LAVA;
|
||||
}
|
||||
else if (this.isLiquid() || this.blockState.is(Blocks.WATER))
|
||||
{
|
||||
return EDhApiBlockMaterial.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 EDhApiBlockMaterial.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 EDhApiBlockMaterial.METAL;
|
||||
}
|
||||
else if (serialString.contains("grass_block"))
|
||||
{
|
||||
return EDhApiBlockMaterial.GRASS;
|
||||
}
|
||||
else if (
|
||||
serialString.contains("dirt")
|
||||
|| serialString.contains("gravel")
|
||||
|| serialString.contains("mud")
|
||||
|| serialString.contains("podzol")
|
||||
|| serialString.contains("mycelium")
|
||||
)
|
||||
{
|
||||
return EDhApiBlockMaterial.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 EDhApiBlockMaterial.DEEPSLATE;
|
||||
}
|
||||
#endif
|
||||
else if (this.serialString.contains("snow"))
|
||||
{
|
||||
return EDhApiBlockMaterial.SNOW;
|
||||
}
|
||||
else if (serialString.contains("sand"))
|
||||
{
|
||||
return EDhApiBlockMaterial.SAND;
|
||||
}
|
||||
else if (serialString.contains("terracotta"))
|
||||
{
|
||||
return EDhApiBlockMaterial.TERRACOTTA;
|
||||
}
|
||||
else if (this.blockState.is(BlockTags.BASE_STONE_NETHER))
|
||||
{
|
||||
return EDhApiBlockMaterial.NETHER_STONE;
|
||||
}
|
||||
else if (serialString.contains("stone")
|
||||
|| serialString.contains("ore"))
|
||||
{
|
||||
return EDhApiBlockMaterial.STONE;
|
||||
}
|
||||
else if (this.blockState.getLightEmission() > 0)
|
||||
{
|
||||
return EDhApiBlockMaterial.ILLUMINATED;
|
||||
}
|
||||
else
|
||||
{
|
||||
return EDhApiBlockMaterial.UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,542 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers.block;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos;
|
||||
import com.seibel.distanthorizons.core.util.ColorUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.renderer.block.model.BakedQuad;
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.level.LevelReader;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.FlowerBlock;
|
||||
import net.minecraft.world.level.block.LeavesBlock;
|
||||
import net.minecraft.world.level.block.RotatedPillarBlock;
|
||||
#if MC_VER >= MC_1_19_2
|
||||
import net.minecraft.util.RandomSource;
|
||||
#else
|
||||
import java.util.Random;
|
||||
#endif
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
#if MC_VER < MC_1_21_5
|
||||
#else
|
||||
import net.minecraft.client.renderer.block.model.BlockModelPart;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* This stores and calculates the colors
|
||||
* the given {@link BlockState} should have based
|
||||
* on the given {@link IClientLevelWrapper}.
|
||||
*
|
||||
* @see ColorUtil
|
||||
*/
|
||||
public class ClientBlockStateColorCache
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
|
||||
private static final HashSet<BlockState> BLOCK_STATES_THAT_NEED_LEVEL = new HashSet<>();
|
||||
private static final HashSet<BlockState> BROKEN_BLOCK_STATES = new HashSet<>();
|
||||
|
||||
/**
|
||||
* Methods using MC's "RandomSource" object aren't thread safe <br>
|
||||
* so we need to put locks around that logic. <br>
|
||||
* specifically:
|
||||
* <code>
|
||||
* getBlockModel(this.blockState).getQuads(this.blockState, direction, RANDOM)
|
||||
* </code>
|
||||
*/
|
||||
private static final ReentrantLock RESOLVE_LOCK = new ReentrantLock();
|
||||
|
||||
|
||||
/** This is the order each direction on a block is processed when attempting to get the texture/color */
|
||||
private static final Direction[] COLOR_RESOLUTION_DIRECTION_ORDER = { Direction.UP, Direction.NORTH, Direction.EAST, Direction.WEST, Direction.SOUTH, Direction.DOWN };
|
||||
|
||||
private static final int FLOWER_COLOR_SCALE = 5;
|
||||
|
||||
|
||||
|
||||
#if MC_VER < MC_1_19_2
|
||||
private static final Random RANDOM = new Random(0);
|
||||
#else
|
||||
/** Note: this object isn't thread safe and must be put in a lock */
|
||||
private static final RandomSource RANDOM = RandomSource.create();
|
||||
#endif
|
||||
|
||||
private final IClientLevelWrapper clientLevelWrapper;
|
||||
private final BlockState blockState;
|
||||
private final LevelReader level;
|
||||
|
||||
private boolean isColorResolved = false;
|
||||
private int baseColor = 0;
|
||||
private boolean needShade = true;
|
||||
private boolean needPostTinting = false;
|
||||
private int tintIndex = 0;
|
||||
|
||||
|
||||
|
||||
//===========//
|
||||
// constants //
|
||||
//===========//
|
||||
|
||||
private static final int MIN_SRGB_BITS = 0x39000000; // 2^(-13)
|
||||
private static final int MAX_SRGB_BITS = 0x3f7fffff; // 1.0 - f32::EPSILON
|
||||
private static final float MIN_SRGB_BOUND = Float.intBitsToFloat(MIN_SRGB_BITS);
|
||||
private static final float MAX_SRGB_BOUND = Float.intBitsToFloat(MAX_SRGB_BITS);
|
||||
|
||||
private static final int[] linearToSrgbTable = new int[]
|
||||
{
|
||||
0x0073000d, 0x007a000d, 0x0080000d, 0x0087000d, 0x008d000d, 0x0094000d, 0x009a000d, 0x00a1000d,
|
||||
0x00a7001a, 0x00b4001a, 0x00c1001a, 0x00ce001a, 0x00da001a, 0x00e7001a, 0x00f4001a, 0x0101001a,
|
||||
0x010e0033, 0x01280033, 0x01410033, 0x015b0033, 0x01750033, 0x018f0033, 0x01a80033, 0x01c20033,
|
||||
0x01dc0067, 0x020f0067, 0x02430067, 0x02760067, 0x02aa0067, 0x02dd0067, 0x03110067, 0x03440067,
|
||||
0x037800ce, 0x03df00ce, 0x044600ce, 0x04ad00ce, 0x051400ce, 0x057b00c5, 0x05dd00bc, 0x063b00b5,
|
||||
0x06970158, 0x07420142, 0x07e30130, 0x087b0120, 0x090b0112, 0x09940106, 0x0a1700fc, 0x0a9500f2,
|
||||
0x0b0f01cb, 0x0bf401ae, 0x0ccb0195, 0x0d950180, 0x0e56016e, 0x0f0d015e, 0x0fbc0150, 0x10630143,
|
||||
0x11070264, 0x1238023e, 0x1357021d, 0x14660201, 0x156601e9, 0x165a01d3, 0x174401c0, 0x182401af,
|
||||
0x18fe0331, 0x1a9602fe, 0x1c1502d2, 0x1d7e02ad, 0x1ed4028d, 0x201a0270, 0x21520256, 0x227d0240,
|
||||
0x239f0443, 0x25c003fe, 0x27bf03c4, 0x29a10392, 0x2b6a0367, 0x2d1d0341, 0x2ebe031f, 0x304d0300,
|
||||
0x31d105b0, 0x34a80555, 0x37520507, 0x39d504c5, 0x3c37048b, 0x3e7c0458, 0x40a8042a, 0x42bd0401,
|
||||
0x44c20798, 0x488e071e, 0x4c1c06b6, 0x4f76065d, 0x52a50610, 0x55ac05cc, 0x5892058f, 0x5b590559,
|
||||
0x5e0c0a23, 0x631c0980, 0x67db08f6, 0x6c55087f, 0x70940818, 0x74a007bd, 0x787d076c, 0x7c330723,
|
||||
};
|
||||
|
||||
private static final float[] srgbToLinearTable = new float[]
|
||||
{
|
||||
0.0f, 0.000303527f, 0.000607054f, 0.00091058103f, 0.001214108f, 0.001517635f, 0.0018211621f, 0.002124689f,
|
||||
0.002428216f, 0.002731743f, 0.00303527f, 0.0033465356f, 0.003676507f, 0.004024717f, 0.004391442f,
|
||||
0.0047769533f, 0.005181517f, 0.0056053917f, 0.0060488326f, 0.006512091f, 0.00699541f, 0.0074990317f,
|
||||
0.008023192f, 0.008568125f, 0.009134057f, 0.009721218f, 0.010329823f, 0.010960094f, 0.011612245f,
|
||||
0.012286487f, 0.012983031f, 0.013702081f, 0.014443844f, 0.015208514f, 0.015996292f, 0.016807375f,
|
||||
0.017641952f, 0.018500218f, 0.019382361f, 0.020288562f, 0.02121901f, 0.022173883f, 0.023153365f,
|
||||
0.02415763f, 0.025186857f, 0.026241222f, 0.027320892f, 0.028426038f, 0.029556843f, 0.03071345f, 0.03189604f,
|
||||
0.033104774f, 0.03433981f, 0.035601325f, 0.036889452f, 0.038204376f, 0.039546248f, 0.04091521f, 0.042311423f,
|
||||
0.043735042f, 0.045186214f, 0.046665095f, 0.048171833f, 0.049706575f, 0.051269468f, 0.052860655f, 0.05448028f,
|
||||
0.056128494f, 0.057805434f, 0.05951124f, 0.06124607f, 0.06301003f, 0.06480328f, 0.06662595f, 0.06847818f,
|
||||
0.07036011f, 0.07227186f, 0.07421358f, 0.07618539f, 0.07818743f, 0.08021983f, 0.082282715f, 0.084376216f,
|
||||
0.086500466f, 0.088655606f, 0.09084173f, 0.09305898f, 0.095307484f, 0.09758736f, 0.09989874f, 0.10224175f,
|
||||
0.10461649f, 0.10702311f, 0.10946172f, 0.111932434f, 0.11443538f, 0.116970696f, 0.11953845f, 0.12213881f,
|
||||
0.12477186f, 0.12743773f, 0.13013652f, 0.13286836f, 0.13563336f, 0.13843165f, 0.14126332f, 0.1441285f,
|
||||
0.1470273f, 0.14995982f, 0.15292618f, 0.1559265f, 0.15896086f, 0.16202943f, 0.16513224f, 0.16826946f,
|
||||
0.17144115f, 0.17464745f, 0.17788847f, 0.1811643f, 0.18447503f, 0.1878208f, 0.19120172f, 0.19461787f,
|
||||
0.19806935f, 0.2015563f, 0.20507877f, 0.2086369f, 0.21223079f, 0.21586053f, 0.21952623f, 0.22322798f,
|
||||
0.22696589f, 0.23074007f, 0.23455065f, 0.23839766f, 0.2422812f, 0.2462014f, 0.25015837f, 0.25415218f,
|
||||
0.2581829f, 0.26225072f, 0.26635566f, 0.27049786f, 0.27467737f, 0.27889434f, 0.2831488f, 0.2874409f,
|
||||
0.2917707f, 0.29613832f, 0.30054384f, 0.30498737f, 0.30946895f, 0.31398875f, 0.31854683f, 0.32314324f,
|
||||
0.32777813f, 0.33245158f, 0.33716366f, 0.34191445f, 0.3467041f, 0.3515327f, 0.35640025f, 0.36130688f,
|
||||
0.3662527f, 0.37123778f, 0.37626222f, 0.3813261f, 0.38642952f, 0.39157256f, 0.3967553f, 0.40197787f,
|
||||
0.4072403f, 0.4125427f, 0.41788515f, 0.42326775f, 0.42869055f, 0.4341537f, 0.43965724f, 0.44520125f,
|
||||
0.45078585f, 0.45641106f, 0.46207705f, 0.46778384f, 0.47353154f, 0.47932023f, 0.48514998f, 0.4910209f,
|
||||
0.49693304f, 0.5028866f, 0.50888145f, 0.5149178f, 0.5209957f, 0.52711535f, 0.5332766f, 0.5394797f,
|
||||
0.5457247f, 0.5520116f, 0.5583406f, 0.5647117f, 0.57112503f, 0.57758063f, 0.5840786f, 0.590619f, 0.597202f,
|
||||
0.60382754f, 0.61049575f, 0.61720675f, 0.62396055f, 0.63075733f, 0.637597f, 0.6444799f, 0.6514058f,
|
||||
0.65837497f, 0.66538745f, 0.67244333f, 0.6795426f, 0.68668544f, 0.69387203f, 0.70110214f, 0.70837605f,
|
||||
0.7156938f, 0.72305536f, 0.730461f, 0.7379107f, 0.7454045f, 0.75294244f, 0.76052475f, 0.7681514f, 0.77582246f,
|
||||
0.78353804f, 0.79129815f, 0.79910296f, 0.8069525f, 0.8148468f, 0.822786f, 0.8307701f, 0.83879924f, 0.84687346f,
|
||||
0.8549928f, 0.8631574f, 0.87136734f, 0.8796226f, 0.8879232f, 0.89626956f, 0.90466136f, 0.913099f, 0.92158204f,
|
||||
0.93011117f, 0.9386859f, 0.9473069f, 0.9559735f, 0.9646866f, 0.9734455f, 0.98225087f, 0.9911022f, 1.0f
|
||||
};
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
public ClientBlockStateColorCache(BlockState blockState, IClientLevelWrapper samplingLevel)
|
||||
{
|
||||
this.blockState = blockState;
|
||||
this.clientLevelWrapper = samplingLevel;
|
||||
this.level = (LevelReader) samplingLevel.getWrappedMcObject();
|
||||
this.resolveColors();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//===================//
|
||||
// color calculation //
|
||||
//===================//
|
||||
|
||||
private void resolveColors()
|
||||
{
|
||||
if (this.isColorResolved)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// getQuads() isn't thread safe so we need to put this logic in a lock
|
||||
RESOLVE_LOCK.lock();
|
||||
|
||||
if (this.blockState.getFluidState().isEmpty())
|
||||
{
|
||||
// look for the first non-empty direction
|
||||
List<BakedQuad> quads = null;
|
||||
for (Direction direction : COLOR_RESOLUTION_DIRECTION_ORDER)
|
||||
{
|
||||
quads = this.getQuadsForDirection(direction);
|
||||
if (quads != null && !quads.isEmpty()
|
||||
&& !(
|
||||
this.blockState.getBlock() instanceof RotatedPillarBlock
|
||||
&& direction == Direction.UP
|
||||
)
|
||||
)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (quads == null || quads.isEmpty())
|
||||
{
|
||||
quads = this.getUnculledQuads();
|
||||
}
|
||||
|
||||
if (quads != null
|
||||
&& !quads.isEmpty()
|
||||
&& quads.get(0) != null)
|
||||
{
|
||||
BakedQuad firstQuad = quads.get(0);
|
||||
|
||||
this.needPostTinting = firstQuad.isTinted();
|
||||
#if MC_VER <= MC_1_21_4
|
||||
this.needShade = firstQuad.isShade();
|
||||
this.tintIndex = firstQuad.getTintIndex();
|
||||
#else
|
||||
this.needShade = firstQuad.shade();
|
||||
this.tintIndex = firstQuad.tintIndex();
|
||||
#endif
|
||||
|
||||
#if MC_VER < MC_1_17_1
|
||||
this.baseColor = calculateColorFromTexture(
|
||||
firstQuad.sprite,
|
||||
ColorMode.getColorMode(this.blockState.getBlock()));
|
||||
#elif MC_VER < MC_1_21_5
|
||||
this.baseColor = calculateColorFromTexture(
|
||||
firstQuad.getSprite(),
|
||||
ColorMode.getColorMode(this.blockState.getBlock()));
|
||||
#else
|
||||
this.baseColor = calculateColorFromTexture(
|
||||
firstQuad.sprite(),
|
||||
ColorMode.getColorMode(this.blockState.getBlock()));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
// Backup method.
|
||||
this.needPostTinting = false;
|
||||
this.needShade = false;
|
||||
this.tintIndex = 0;
|
||||
this.baseColor = this.getParticleIconColor();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Liquid Block
|
||||
this.needPostTinting = true;
|
||||
this.needShade = false;
|
||||
this.tintIndex = 0;
|
||||
this.baseColor = this.getParticleIconColor();
|
||||
}
|
||||
|
||||
this.isColorResolved = true;
|
||||
}
|
||||
finally
|
||||
{
|
||||
RESOLVE_LOCK.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private List<BakedQuad> getUnculledQuads() { return this.getQuadsForDirection(null); }
|
||||
@Nullable
|
||||
private List<BakedQuad> getQuadsForDirection(@Nullable Direction direction)
|
||||
{
|
||||
List<BakedQuad> quads = null;
|
||||
|
||||
#if MC_VER < MC_1_21_5
|
||||
quads = Minecraft.getInstance().getModelManager().getBlockModelShaper().
|
||||
getBlockModel(this.blockState).getQuads(this.blockState, direction, RANDOM);
|
||||
#else
|
||||
List<BlockModelPart> blockModelPartList = Minecraft.getInstance().getModelManager().getBlockModelShaper().
|
||||
getBlockModel(this.blockState).collectParts(RANDOM);
|
||||
|
||||
quads = new ArrayList<>();
|
||||
if (blockModelPartList != null)
|
||||
{
|
||||
for (int i = 0; i < blockModelPartList.size(); i++)
|
||||
{
|
||||
// if direction is null this will return the unculled quads
|
||||
quads.addAll(blockModelPartList.get(i).getQuads(direction));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return quads;
|
||||
}
|
||||
|
||||
//TODO: Perhaps make this not just use the first frame?
|
||||
private static int calculateColorFromTexture(TextureAtlasSprite texture, ColorMode colorMode)
|
||||
{
|
||||
int count = 0;
|
||||
int alpha = 0;
|
||||
double red = 0;
|
||||
double green = 0;
|
||||
double blue = 0;
|
||||
int tempColor;
|
||||
|
||||
// don't render Chiseled blocks.
|
||||
// Since ColorMode is set per block, you only need to check this once.
|
||||
if (colorMode != ColorMode.Chisel)
|
||||
{
|
||||
// textures normally use u and v instead of x and y
|
||||
for (int v = 0; v < getTextureHeight(texture); v++)
|
||||
{
|
||||
for (int u = 0; u < getTextureWidth(texture); u++)
|
||||
{
|
||||
//note: Minecraft color format is: 0xAA BB GG RR
|
||||
//________ DH mod color format is: 0xAA RR GG BB
|
||||
//OpenGL RGBA format native order: 0xRR GG BB AA
|
||||
//_ OpenGL RGBA format Java Order: 0xAA BB GG RR
|
||||
tempColor = TextureAtlasSpriteWrapper.getPixelRGBA(texture, 0, u, v);
|
||||
|
||||
int r = (tempColor & 0x000000FF);
|
||||
int g = (tempColor & 0x0000FF00) >>> 8;
|
||||
int b = (tempColor & 0x00FF0000) >>> 16;
|
||||
int a = (tempColor & 0xFF000000) >>> 24;
|
||||
int scale = 1;
|
||||
if (colorMode == ColorMode.Leaves)
|
||||
{
|
||||
//switch (//FIXME add config option)
|
||||
// case BLACK:
|
||||
// a = 255; //simulate black background of fast leaves
|
||||
// break;
|
||||
// case IGNORE:
|
||||
if (a == 0) {
|
||||
continue; //same long grass
|
||||
}
|
||||
else
|
||||
{
|
||||
a = 255; //just in case there are semi transparent pixels
|
||||
}
|
||||
// break;
|
||||
// case TRANSPARENT:
|
||||
// break; //do nothing, let it count towards transparency
|
||||
|
||||
}
|
||||
else if (a == 0 && colorMode != ColorMode.Glass)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (colorMode == ColorMode.Flower && (g + 25 < b || g + 25 < r))
|
||||
{
|
||||
scale = FLOWER_COLOR_SCALE;
|
||||
}
|
||||
count += scale;
|
||||
//apparently alpha is linear
|
||||
alpha += a * scale;
|
||||
//gamma correction is complicated
|
||||
red += srgbToLinearTable[r] * a * scale;
|
||||
green += srgbToLinearTable[g] * a * scale;
|
||||
blue += srgbToLinearTable[b] * a * scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (count == 0)
|
||||
{
|
||||
// this block is entirely transparent
|
||||
tempColor = ColorUtil.argbToInt(0, 255, 255, 255);
|
||||
}
|
||||
else
|
||||
{
|
||||
// determine the average color
|
||||
tempColor = ColorUtil.argbToInt(
|
||||
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.argbToInt(255, 182, 0, 182))
|
||||
{
|
||||
//make it not render at all
|
||||
tempColor = ColorUtil.argbToInt(0, 255, 255, 255);
|
||||
}
|
||||
return tempColor;
|
||||
}
|
||||
private static int getTextureWidth(TextureAtlasSprite texture)
|
||||
{
|
||||
#if MC_VER < MC_1_19_4
|
||||
return texture.getWidth();
|
||||
#else
|
||||
return texture.contents().width();
|
||||
#endif
|
||||
}
|
||||
private static int getTextureHeight(TextureAtlasSprite texture)
|
||||
{
|
||||
#if MC_VER < MC_1_19_4
|
||||
return texture.getHeight();
|
||||
#else
|
||||
return texture.contents().height();
|
||||
#endif
|
||||
}
|
||||
/**
|
||||
* This method was suggested by IMS from the Iris/Sodium team.
|
||||
* That's where the numbers and code are based.
|
||||
*/
|
||||
private static int linearToSrgb(float c)
|
||||
{
|
||||
if (!(c > MIN_SRGB_BOUND)) {
|
||||
c = MIN_SRGB_BOUND;
|
||||
}
|
||||
|
||||
if (c > MAX_SRGB_BOUND) {
|
||||
c = MAX_SRGB_BOUND;
|
||||
}
|
||||
int inputBits = Float.floatToRawIntBits(c);
|
||||
int entry = linearToSrgbTable[((inputBits - MIN_SRGB_BITS) >> 20)];
|
||||
|
||||
int bias = (entry >>> 16) << 9;
|
||||
int scale = entry & 0xffff;
|
||||
int t = (inputBits >>> 12) & 0xff;
|
||||
|
||||
return (bias + (scale * t)) >>> 16;
|
||||
}
|
||||
|
||||
private int getParticleIconColor()
|
||||
{
|
||||
return calculateColorFromTexture(
|
||||
Minecraft.getInstance().getModelManager().getBlockModelShaper().getParticleIcon(this.blockState),
|
||||
ColorMode.getColorMode(this.blockState.getBlock()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
//===============//
|
||||
// public getter //
|
||||
//===============//
|
||||
|
||||
public int getColor(BiomeWrapper biome, DhBlockPos pos)
|
||||
{
|
||||
// only get the tint if the block needs to be tinted
|
||||
if (!this.needPostTinting)
|
||||
{
|
||||
return this.baseColor;
|
||||
}
|
||||
|
||||
// don't try tinting blocks that don't support our method of tint getting
|
||||
if (BROKEN_BLOCK_STATES.contains(this.blockState))
|
||||
{
|
||||
return this.baseColor;
|
||||
}
|
||||
|
||||
|
||||
// attempt to get the tint
|
||||
int tintColor = -1;
|
||||
try
|
||||
{
|
||||
// try to use the fast tint getter logic first
|
||||
if (!BLOCK_STATES_THAT_NEED_LEVEL.contains(this.blockState))
|
||||
{
|
||||
try
|
||||
{
|
||||
tintColor = Minecraft.getInstance().getBlockColors()
|
||||
.getColor(this.blockState, new TintWithoutLevelOverrider(biome, this.clientLevelWrapper), McObjectConverter.Convert(pos), this.tintIndex);
|
||||
}
|
||||
catch (UnsupportedOperationException e)
|
||||
{
|
||||
// this exception generally occurs if the tint requires other blocks besides itself
|
||||
LOGGER.debug("Unable to use ["+TintWithoutLevelOverrider.class.getSimpleName()+"] to get the block tint for block: [" + this.blockState + "] and biome: [" + biome + "] at pos: " + pos + ". Error: [" + e.getMessage() + "]. Attempting to use backup method...", e);
|
||||
BLOCK_STATES_THAT_NEED_LEVEL.add(this.blockState);
|
||||
}
|
||||
}
|
||||
|
||||
// use the level logic only if requested
|
||||
if (BLOCK_STATES_THAT_NEED_LEVEL.contains(this.blockState))
|
||||
{
|
||||
// this logic can't be used all the time due to it breaking some blocks tinting
|
||||
// specifically oceans don't render correctly
|
||||
tintColor = Minecraft.getInstance().getBlockColors()
|
||||
.getColor(this.blockState, new TintGetterOverrideFast(this.level), McObjectConverter.Convert(pos), this.tintIndex);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// only display the error once per block/biome type to reduce log spam
|
||||
if (!BROKEN_BLOCK_STATES.contains(this.blockState))
|
||||
{
|
||||
LOGGER.warn("Failed to get block color for block: [" + this.blockState + "] and biome: [" + biome + "] at pos: " + pos + ". Error: ["+e.getMessage() + "]. Note: future errors for this block/biome will be ignored.", e);
|
||||
BROKEN_BLOCK_STATES.add(this.blockState);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (tintColor != -1)
|
||||
{
|
||||
return ColorUtil.multiplyARGBwithRGB(this.baseColor, tintColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
// unable to get the tinted color, use the base color instead
|
||||
return this.baseColor;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// helper classes //
|
||||
//================//
|
||||
|
||||
enum ColorMode
|
||||
{
|
||||
Default,
|
||||
Flower,
|
||||
Leaves,
|
||||
Chisel,
|
||||
Glass;
|
||||
|
||||
static ColorMode getColorMode(Block block)
|
||||
{
|
||||
if (block instanceof LeavesBlock) return Leaves;
|
||||
if (block instanceof FlowerBlock) return Flower;
|
||||
if (block.toString().contains("glass")) return Glass;
|
||||
if (block.toString().equals("Block{chiselsandbits:chiseled}")) return Chisel;
|
||||
return Default;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers.block;
|
||||
|
||||
import net.minecraft.client.renderer.texture.TextureAtlasSprite;
|
||||
|
||||
#if MC_VER < MC_1_17_1
|
||||
#elif MC_VER < MC_1_21_3
|
||||
#else
|
||||
import com.seibel.distanthorizons.core.util.ColorUtil;
|
||||
import net.minecraft.client.renderer.texture.SpriteContents;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* For wrapping/utilizing around TextureAtlasSprite
|
||||
*
|
||||
* @author Ran
|
||||
*/
|
||||
public class TextureAtlasSpriteWrapper
|
||||
{
|
||||
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);
|
||||
#elif MC_VER < MC_1_21_3
|
||||
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);
|
||||
#else
|
||||
|
||||
SpriteContents content = sprite.contents(); // don't close, otherwise MC will be corrupted and you won't be able to re-access the texture
|
||||
if (content.animatedTexture != null)
|
||||
{
|
||||
x += content.animatedTexture.getFrameX(frameIndex) * content.width();
|
||||
y += content.animatedTexture.getFrameY(frameIndex) * content.width();
|
||||
}
|
||||
|
||||
int abgr = content.originalImage.getPixel(x, y);
|
||||
// re-pack the color so we can access it normally
|
||||
int a = (abgr & 0xFF000000) >>> 24;
|
||||
int b = (abgr & 0x00FF0000) >>> 16;
|
||||
int g = (abgr & 0x0000FF00) >>> 8;
|
||||
int r = (abgr & 0x000000FF);
|
||||
return ColorUtil.argbToInt(a, r, g, b);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.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;
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
public TintGetterOverrideFast(LevelReader parent) { this.parent = parent; }
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// methods //
|
||||
//=========//
|
||||
|
||||
private Biome _getBiome(BlockPos pos)
|
||||
{
|
||||
#if MC_VER >= MC_1_18_2
|
||||
return this.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 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); }
|
||||
|
||||
#if MC_VER < MC_1_21_3
|
||||
@Override
|
||||
public int getMaxLightLevel() { return parent.getMaxLightLevel(); }
|
||||
#else
|
||||
#endif
|
||||
|
||||
@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); }
|
||||
|
||||
#if MC_VER < MC_1_21_3
|
||||
@Override
|
||||
public int getMaxBuildHeight() { return this.parent.getMaxBuildHeight(); }
|
||||
#else
|
||||
@Override
|
||||
public int getMaxY() { return this.parent.getMaxY(); }
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// post MC 1.17 //
|
||||
//==============//
|
||||
|
||||
#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(); }
|
||||
|
||||
#if MC_VER < MC_1_21_3
|
||||
@Override
|
||||
public int getMinBuildHeight() { return this.parent.getMinBuildHeight(); }
|
||||
#else
|
||||
@Override
|
||||
public int getMinY() { return this.parent.getMinY(); }
|
||||
#endif
|
||||
|
||||
@Override
|
||||
public int getSectionsCount() { return this.parent.getSectionsCount(); }
|
||||
|
||||
#if MC_VER < MC_1_21_3
|
||||
@Override
|
||||
public int getMinSection() { return this.parent.getMinSection(); }
|
||||
#else
|
||||
@Override
|
||||
public int getMinSectionY() { return BlockAndTintGetter.super.getMinSectionY(); }
|
||||
#endif
|
||||
|
||||
#if MC_VER < MC_1_21_3
|
||||
@Override
|
||||
public int getMaxSection() { return this.parent.getMaxSection(); }
|
||||
#else
|
||||
@Override
|
||||
public int getMaxSectionY() { return this.parent.getMaxSectionY(); }
|
||||
#endif
|
||||
|
||||
@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
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers.block;
|
||||
|
||||
import com.seibel.distanthorizons.core.util.LodUtil;
|
||||
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;
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
public TintGetterOverrideSmooth(LevelReader parent, int smoothingRange)
|
||||
{
|
||||
this.parent = parent;
|
||||
this.smoothingRange = smoothingRange;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// methods //
|
||||
//=========//
|
||||
|
||||
private Biome _getBiome(BlockPos pos)
|
||||
{
|
||||
#if MC_VER >= MC_1_18_2
|
||||
return this.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); }
|
||||
|
||||
#if MC_VER < MC_1_21_3
|
||||
@Override
|
||||
public int getMaxLightLevel() { return this.parent.getMaxLightLevel(); }
|
||||
#else
|
||||
#endif
|
||||
|
||||
@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); }
|
||||
|
||||
#if MC_VER < MC_1_21_3
|
||||
@Override
|
||||
public int getMaxBuildHeight() { return this.parent.getMaxBuildHeight(); }
|
||||
#else
|
||||
@Override
|
||||
public int getMaxY() { return this.parent.getMaxY(); }
|
||||
#endif
|
||||
|
||||
#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(); }
|
||||
|
||||
#if MC_VER < MC_1_21_3
|
||||
@Override
|
||||
public int getMinBuildHeight() { return this.parent.getMinBuildHeight(); }
|
||||
#else
|
||||
@Override
|
||||
public int getMinY() { return this.parent.getMinY(); }
|
||||
#endif
|
||||
|
||||
@Override
|
||||
public int getSectionsCount() { return this.parent.getSectionsCount(); }
|
||||
|
||||
#if MC_VER < MC_1_21_3
|
||||
@Override
|
||||
public int getMinSection() { return this.parent.getMinSection(); }
|
||||
#else
|
||||
@Override
|
||||
public int getMinSectionY() { return BlockAndTintGetter.super.getMinSectionY(); }
|
||||
#endif
|
||||
|
||||
#if MC_VER < MC_1_21_3
|
||||
@Override
|
||||
public int getMaxSection() { return this.parent.getMaxSection(); }
|
||||
#else
|
||||
@Override
|
||||
public int getMaxSectionY() { return this.parent.getMaxSectionY(); }
|
||||
#endif
|
||||
|
||||
@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
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers.block;
|
||||
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
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.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
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
public class TintWithoutLevelOverrider implements BlockAndTintGetter
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
|
||||
#if MC_VER < MC_1_18_2
|
||||
public static final ConcurrentMap<String, Biome> BIOME_BY_RESOURCE_STRING = new ConcurrentHashMap<>();
|
||||
#else
|
||||
public static final ConcurrentMap<String, Holder<Biome>> BIOME_BY_RESOURCE_STRING = new ConcurrentHashMap<>();
|
||||
#endif
|
||||
|
||||
|
||||
@NotNull
|
||||
private final BiomeWrapper biomeWrapper;
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
public TintWithoutLevelOverrider(@NotNull BiomeWrapper biomeWrapper, IClientLevelWrapper clientLevelWrapper)
|
||||
{ this.biomeWrapper = biomeWrapper; }
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// methods //
|
||||
//=========//
|
||||
|
||||
@Override
|
||||
public int getBlockTint(@NotNull BlockPos blockPos, @NotNull ColorResolver colorResolver)
|
||||
{
|
||||
String biomeString = this.biomeWrapper.getSerialString();
|
||||
if (biomeString == null
|
||||
|| biomeString.isEmpty()
|
||||
|| biomeString.equals(BiomeWrapper.EMPTY_BIOME_STRING))
|
||||
{
|
||||
// default to "plains" for empty/invalid biomes
|
||||
biomeString = "minecraft:plains";
|
||||
}
|
||||
|
||||
|
||||
return colorResolver.getColor(unwrap(getClientBiome(biomeString)), blockPos.getX(), blockPos.getZ());
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Previously, this class might have immediately unwrapped the Holder like this:</p>
|
||||
* <pre>{@code
|
||||
* // Inside constructor (OLD WAY - PROBLEMATIC):
|
||||
* Holder<Biome> biomeHolder = getTheHolderFromSomewhere();
|
||||
* this.biome = biomeHolder.value(); // <-- PROBLEM HERE
|
||||
* }</pre>
|
||||
*
|
||||
* <p>This approach is problematic because the {@link net.minecraft.core.Holder} system,
|
||||
* particularly {@code Holder.Reference}, is designed for <strong>late binding</strong>. Here's why storing
|
||||
* the Holder itself is now necessary:</p>
|
||||
* <ol>
|
||||
* <li>A {@code Holder.Reference<Biome>} might be created initially just with a
|
||||
* {@link net.minecraft.resources.ResourceKey} (like {@code minecraft:plains}), but its actual
|
||||
* {@link net.minecraft.core.Holder#value() value()} (the {@code Biome} object itself) might be {@code null}
|
||||
* at construction time.</li>
|
||||
* <li>Later, during game loading, registry population, or potentially due to modifications by other mods
|
||||
* (e.g., Polytone), the system calls internal binding methods (like {@code bindValue(Biome)})
|
||||
* on the {@code Holder} instance. This sets or <strong>updates</strong> the internal reference to the
|
||||
* actual {@code Biome} object.</li>
|
||||
* <li>Crucially, the binding process might assign a completely <strong>new</strong> {@code Biome} object
|
||||
* instance to the {@code Holder} reference, replacing any previous one.</li>
|
||||
* </ol>
|
||||
*
|
||||
* <p>If we unwrapped the {@code Holder} using {@code .value()} within the constructor (the old way),
|
||||
* our class's internal {@code biome} field would permanently store a reference to whatever {@code Biome}
|
||||
* object the {@code Holder} pointed to *at that exact moment*. It would have no link back to the
|
||||
* {@code Holder} and would be unaware if the {@code Holder} was later updated to point to a different
|
||||
* (or the initially missing) {@code Biome} object. This would lead to using stale or even {@code null} data.</p>
|
||||
*
|
||||
* <p>By storing the {@code Holder<Biome>} itself, this class can call {@link net.minecraft.core.Holder#value()}
|
||||
* whenever the biome information is needed, ensuring it always retrieves the most current {@code Biome}
|
||||
* instance associated with the holder at that time.</p>
|
||||
*/
|
||||
private static #if MC_VER < MC_1_18_2 Biome #else Holder<Biome> #endif getClientBiome(String biomeResourceString)
|
||||
{
|
||||
// cache the client biomes so we don't have to re-parse the resource location every time
|
||||
return BIOME_BY_RESOURCE_STRING.compute(biomeResourceString,
|
||||
(resourceString, existingBiome) ->
|
||||
{
|
||||
if (existingBiome != null)
|
||||
{
|
||||
return existingBiome;
|
||||
}
|
||||
|
||||
ClientLevel clientLevel = Minecraft.getInstance().level;
|
||||
if (clientLevel == null)
|
||||
{
|
||||
// shouldn't happen, but just in case
|
||||
throw new IllegalStateException("Attempted to get client biome when no client level was loaded.");
|
||||
}
|
||||
|
||||
BiomeWrapper.BiomeDeserializeResult result;
|
||||
try
|
||||
{
|
||||
result = BiomeWrapper.deserializeBiome(resourceString, clientLevel.registryAccess());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.warn("Unable to deserialize client biome ["+resourceString+"], using fallback...");
|
||||
|
||||
try
|
||||
{
|
||||
result = BiomeWrapper.deserializeBiome("minecraft:plains", clientLevel.registryAccess());
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
// should never happen, if it does this log will explode, but just in case
|
||||
LOGGER.error("Unable to deserialize fallback client biome [minecraft:plains], returning NULL.");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
if (result.success)
|
||||
{
|
||||
existingBiome = result.biome;
|
||||
}
|
||||
|
||||
return existingBiome;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// 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.");
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// post MC 1.17 //
|
||||
//==============//
|
||||
|
||||
#if MC_VER >= MC_1_17_1
|
||||
|
||||
@Override
|
||||
public int getHeight()
|
||||
{ throw new UnsupportedOperationException("ERROR: getHeight() called on TintWithoutLevelOverrider. Object is for tinting only."); }
|
||||
|
||||
#if MC_VER < MC_1_21_3
|
||||
@Override
|
||||
public int getMinBuildHeight()
|
||||
{ throw new UnsupportedOperationException("ERROR: getMinBuildHeight() called on TintWithoutLevelOverrider. Object is for tinting only."); }
|
||||
#else
|
||||
@Override
|
||||
public int getMinY()
|
||||
{ throw new UnsupportedOperationException("ERROR: getMinY() called on TintWithoutLevelOverrider. Object is for tinting only."); }
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -0,0 +1,144 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers.block;
|
||||
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.world.level.BlockAndTintGetter;
|
||||
import net.minecraft.world.level.ColorResolver;
|
||||
import net.minecraft.world.level.biome.Biome;
|
||||
import net.minecraft.world.level.block.entity.BlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.lighting.LevelLightEngine;
|
||||
import net.minecraft.world.level.material.FluidState;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
#if MC_VER >= MC_1_18_2
|
||||
import net.minecraft.core.Holder;
|
||||
#endif
|
||||
|
||||
public class TintWithoutLevelSmoothOverrider implements BlockAndTintGetter
|
||||
{
|
||||
final BiomeWrapper biome;
|
||||
public int smoothingRange;
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
public TintWithoutLevelSmoothOverrider(BiomeWrapper biome, int smoothingRange)
|
||||
{
|
||||
this.biome = biome;
|
||||
this.smoothingRange = smoothingRange;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// methods //
|
||||
//=========//
|
||||
|
||||
@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;
|
||||
#endif
|
||||
}
|
||||
|
||||
// public int calculateBlockTint(BlockPos blockPos, ColorResolver colorResolver)
|
||||
// {
|
||||
// int i = smoothingRange;
|
||||
// if (i == 0)
|
||||
// return colorResolver.getColor(_getBiome(blockPos), blockPos.getX(), blockPos.getZ());
|
||||
// int j = (i * 2 + 1) * (i * 2 + 1);
|
||||
// int k = 0;
|
||||
// int l = 0;
|
||||
// int m = 0;
|
||||
// Cursor3D cursor3D = new Cursor3D(blockPos.getX() - i, blockPos.getY(), blockPos.getZ() - i, blockPos.getX() + i, blockPos.getY(), blockPos.getZ() + i);
|
||||
// BlockPos.MutableBlockPos mutableBlockPos = new BlockPos.MutableBlockPos();
|
||||
// while (cursor3D.advance())
|
||||
// {
|
||||
// mutableBlockPos.set(cursor3D.nextX(), cursor3D.nextY(), cursor3D.nextZ());
|
||||
// int n;
|
||||
// if (LodCommonMain.forgeMethodCaller != null) {
|
||||
// n = LodCommonMain.forgeMethodCaller.colorResolverGetColor(colorResolver, _getBiome(mutableBlockPos),
|
||||
// mutableBlockPos.getX(), mutableBlockPos.getZ());
|
||||
// } else {
|
||||
// n = colorResolver.getColor(_getBiome(mutableBlockPos), mutableBlockPos.getX(), mutableBlockPos.getZ());
|
||||
// }
|
||||
//
|
||||
// k += (n & 0xFF0000) >> 16;
|
||||
// l += (n & 0xFF00) >> 8;
|
||||
// m += n & 0xFF;
|
||||
// }
|
||||
// return (k / j & 0xFF) << 16 | (l / j & 0xFF) << 8 | m / j & 0xFF;
|
||||
// }
|
||||
|
||||
@Override
|
||||
public float getShade(Direction direction, boolean shade)
|
||||
{ throw new UnsupportedOperationException("ERROR: getShade() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); }
|
||||
@Override
|
||||
public LevelLightEngine getLightEngine()
|
||||
{ throw new UnsupportedOperationException("ERROR: getLightEngine() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); }
|
||||
@Nullable
|
||||
@Override
|
||||
public BlockEntity getBlockEntity(BlockPos pos)
|
||||
{ throw new UnsupportedOperationException("ERROR: getBlockEntity() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); }
|
||||
|
||||
@Override
|
||||
public BlockState getBlockState(BlockPos pos)
|
||||
{ throw new UnsupportedOperationException("ERROR: getBlockState() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); }
|
||||
@Override
|
||||
public FluidState getFluidState(BlockPos pos)
|
||||
{ throw new UnsupportedOperationException("ERROR: getFluidState() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); }
|
||||
|
||||
|
||||
//==============//
|
||||
// post MC 1.17 //
|
||||
//==============//
|
||||
|
||||
#if MC_VER >= MC_1_17_1
|
||||
|
||||
@Override
|
||||
public int getHeight()
|
||||
{ throw new UnsupportedOperationException("ERROR: getHeight() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); }
|
||||
|
||||
#if MC_VER < MC_1_21_3
|
||||
@Override
|
||||
public int getMinBuildHeight()
|
||||
{ throw new UnsupportedOperationException("ERROR: getMinBuildHeight() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); }
|
||||
#else
|
||||
@Override
|
||||
public int getMinY()
|
||||
{ throw new UnsupportedOperationException("ERROR: getMinY() called on TintWithoutLevelSmoothOverrider. Object is for tinting only."); }
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -0,0 +1,647 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
package com.seibel.distanthorizons.common.wrappers.chunk;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.misc.MutableBlockPosWrapper;
|
||||
import com.seibel.distanthorizons.core.config.Config;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.pos.blockPos.DhBlockPos;
|
||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||
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 com.seibel.distanthorizons.core.wrapperInterfaces.misc.IMutableBlockPosWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IBiomeWrapper;
|
||||
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.ILevelWrapper;
|
||||
import net.minecraft.core.BlockPos;
|
||||
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;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
#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;
|
||||
#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 static final ThreadLocal<MutableBlockPosWrapper> MUTABLE_BLOCK_POS_WRAPPER_REF = ThreadLocal.withInitial(() -> new MutableBlockPosWrapper());
|
||||
|
||||
|
||||
private final ChunkAccess chunk;
|
||||
private final DhChunkPos chunkPos;
|
||||
private final ILevelWrapper wrappedLevel;
|
||||
|
||||
private boolean isDhBlockLightCorrect = false;
|
||||
private boolean isDhSkyLightCorrect = false;
|
||||
|
||||
private ChunkLightStorage blockLightStorage;
|
||||
private ChunkLightStorage skyLightStorage;
|
||||
|
||||
private ArrayList<DhBlockPos> blockLightPosList = null;
|
||||
|
||||
private int minNonEmptyHeight = Integer.MIN_VALUE;
|
||||
private int maxNonEmptyHeight = Integer.MAX_VALUE;
|
||||
|
||||
/** will be null if we are using MC heightmaps */
|
||||
private final int[][] solidHeightMap;
|
||||
/** will be null if we are using MC heightmaps */
|
||||
private final int[][] lightBlockingHeightMap;
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
public ChunkWrapper(ChunkAccess chunk, ILevelWrapper wrappedLevel)
|
||||
{
|
||||
this.chunk = chunk;
|
||||
this.wrappedLevel = wrappedLevel;
|
||||
this.chunkPos = new DhChunkPos(chunk.getPos().x, chunk.getPos().z);
|
||||
|
||||
// use DH heightmaps if requested
|
||||
if (Config.Common.LodBuilding.recalculateChunkHeightmaps.get())
|
||||
{
|
||||
this.solidHeightMap = new int[LodUtil.CHUNK_WIDTH][LodUtil.CHUNK_WIDTH];
|
||||
this.lightBlockingHeightMap = new int[LodUtil.CHUNK_WIDTH][LodUtil.CHUNK_WIDTH];
|
||||
|
||||
this.recalculateDhHeightMapsIfNeeded();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.solidHeightMap = null;
|
||||
this.lightBlockingHeightMap = null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// 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 getInclusiveMinBuildHeight() { return getInclusiveMinBuildHeight(this.chunk); }
|
||||
public static int getInclusiveMinBuildHeight(ChunkAccess chunk)
|
||||
{
|
||||
#if MC_VER < MC_1_17_1
|
||||
return 0;
|
||||
#elif MC_VER < MC_1_21_3
|
||||
return chunk.getMinBuildHeight();
|
||||
#else
|
||||
return chunk.getMinY();
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getExclusiveMaxBuildHeight() { return getExclusiveMaxBuildHeight(this.chunk); }
|
||||
public static int getExclusiveMaxBuildHeight(ChunkAccess chunk)
|
||||
{
|
||||
#if MC_VER < MC_1_21_3
|
||||
return chunk.getMaxBuildHeight();
|
||||
#else
|
||||
// +1 since Minecraft made the max value inclusive
|
||||
return chunk.getMaxY() + 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMinNonEmptyHeight()
|
||||
{
|
||||
if (this.minNonEmptyHeight != Integer.MIN_VALUE)
|
||||
{
|
||||
return this.minNonEmptyHeight;
|
||||
}
|
||||
|
||||
|
||||
// default if every section is empty or missing
|
||||
this.minNonEmptyHeight = this.getInclusiveMinBuildHeight();
|
||||
|
||||
// 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.getExclusiveMaxBuildHeight();
|
||||
|
||||
// determine the highest empty section (top down)
|
||||
LevelChunkSection[] sections = this.chunk.getSections();
|
||||
for (int index = sections.length-1; index >= 0; index--)
|
||||
{
|
||||
// update at each position to fix using the max height if the chunk is empty
|
||||
this.maxNonEmptyHeight = this.getChunkSectionMinHeight(index) + 16;
|
||||
|
||||
if (sections[index] == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isChunkSectionEmpty(sections[index]))
|
||||
{
|
||||
// non-empty section found
|
||||
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) { return (index * 16) + this.getInclusiveMinBuildHeight(); }
|
||||
|
||||
/** Will only run if the config says the MC heightmaps shouldn't be trusted. */
|
||||
public void recalculateDhHeightMapsIfNeeded()
|
||||
{
|
||||
// re-calculate the min/max heights for consistency (during world gen these may be wrong)
|
||||
this.minNonEmptyHeight = Integer.MIN_VALUE;
|
||||
this.maxNonEmptyHeight = Integer.MAX_VALUE;
|
||||
|
||||
|
||||
// recalculate heightmaps if needed
|
||||
if (this.solidHeightMap != null)
|
||||
{
|
||||
for (int x = 0; x < LodUtil.CHUNK_WIDTH; x++)
|
||||
{
|
||||
for (int z = 0; z < LodUtil.CHUNK_WIDTH; z++)
|
||||
{
|
||||
int minInclusiveBuildHeight = this.getMinNonEmptyHeight();
|
||||
// if no blocks are found the height map will be at the bottom of the world
|
||||
int solidHeight = minInclusiveBuildHeight;
|
||||
int lightBlockingHeight = minInclusiveBuildHeight;
|
||||
|
||||
|
||||
int y = this.getMaxNonEmptyHeight(); //this.getExclusiveMaxBuildHeight();
|
||||
IBlockStateWrapper block = this.getBlockState(x, y, z);
|
||||
while (// go down until we reach the minimum build height
|
||||
y > minInclusiveBuildHeight
|
||||
// keep going until we find both height map values
|
||||
&& (solidHeight == minInclusiveBuildHeight || lightBlockingHeight == minInclusiveBuildHeight))
|
||||
{
|
||||
// is this block solid?
|
||||
if (solidHeight == minInclusiveBuildHeight
|
||||
&& block.isSolid())
|
||||
{
|
||||
solidHeight = y;
|
||||
}
|
||||
|
||||
// is this block light blocking?
|
||||
if (lightBlockingHeight == minInclusiveBuildHeight
|
||||
&& block.getOpacity() != LodUtil.BLOCK_FULLY_TRANSPARENT)
|
||||
{
|
||||
lightBlockingHeight = y;
|
||||
}
|
||||
|
||||
// get the next block down
|
||||
y--;
|
||||
block = this.getBlockState(x, y, z);
|
||||
}
|
||||
|
||||
this.solidHeightMap[x][z] = solidHeight;
|
||||
this.lightBlockingHeightMap[x][z] = lightBlockingHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSolidHeightMapValue(int xRel, int zRel)
|
||||
{
|
||||
this.throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(xRel, zRel);
|
||||
|
||||
// will be null if we want to use MC heightmaps
|
||||
if (this.solidHeightMap == null)
|
||||
{
|
||||
return this.chunk.getOrCreateHeightmapUnprimed(Heightmap.Types.WORLD_SURFACE).getFirstAvailable(xRel, zRel);
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.solidHeightMap[xRel][zRel];
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLightBlockingHeightMapValue(int xRel, int zRel)
|
||||
{
|
||||
this.throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(xRel, zRel);
|
||||
|
||||
if (this.lightBlockingHeightMap == null)
|
||||
{
|
||||
return this.chunk.getOrCreateHeightmapUnprimed(Heightmap.Types.MOTION_BLOCKING).getFirstAvailable(xRel, zRel);
|
||||
}
|
||||
else
|
||||
{
|
||||
return this.lightBlockingHeightMap[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);
|
||||
|
||||
// TODO copy into pooled array, this isn't thread safe and can cause MC to throw errors if the chunk is loaded
|
||||
return BlockStateWrapper.fromBlockState(this.chunk.getBlockState(blockPos), this.wrappedLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockStateWrapper getBlockState(int relX, int relY, int relZ, IMutableBlockPosWrapper mcBlockPos, IBlockStateWrapper guess)
|
||||
{
|
||||
this.throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, relY, relZ);
|
||||
|
||||
BlockPos.MutableBlockPos pos = (BlockPos.MutableBlockPos)mcBlockPos.getWrappedMcObject();
|
||||
pos.setX(relX);
|
||||
pos.setY(relY);
|
||||
pos.setZ(relZ);
|
||||
|
||||
return BlockStateWrapper.fromBlockState(this.chunk.getBlockState(pos), this.wrappedLevel, guess);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
// Commented out experimental LevelChunkSection cloning logic to fix extremely rare concurrency modification issue
|
||||
// James has only ever seen a report relating to LevelSection concurrent modification once,
|
||||
// the issue can cause DH lighting/LOD building to fail due to the chunk being modified on the server.
|
||||
// James has only heard of this issue once, so it isn't a high priority issue.
|
||||
// And from James' quick look at a few different MC versions it appears the LevelChunkSection object changes quite drastically between MC versions,
|
||||
// meaning any cloning logic would have to either be a new wrapper or very MC version dependent, either way a lot of additional work.
|
||||
// Due to the large time cost and extremely rare nature of the issue, this logic is commented out unless this issue pops up again in the future.
|
||||
|
||||
// instance variable to hold the cloned sections
|
||||
private final LevelChunkSection[] levelChunkSections;
|
||||
|
||||
// new constructor logic to clone the sections
|
||||
public constructor(...)
|
||||
{
|
||||
// other constructor logic //
|
||||
|
||||
LevelChunkSection[] sections = this.chunk.getSections();
|
||||
this.levelChunkSections = new LevelChunkSection[sections.length];
|
||||
for (int i = 0; i < sections.length; i++)
|
||||
{
|
||||
LevelChunkSection section = sections[i];
|
||||
if (section != null)
|
||||
{
|
||||
// TODO implement section cloning for older MC versions, only 1.21.4 MC (and maybe other semi recent versions) have a clean way to handle this
|
||||
// TODO we probably want a wrapper object instead
|
||||
#if MC_VER < MC_1_21_4
|
||||
this.levelChunkSections[i] = section;
|
||||
#else
|
||||
this.levelChunkSections[i] = section.copy();
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// replacement getters
|
||||
@Override
|
||||
public IBlockStateWrapper getBlockState(int relX, int relY, int relZ)
|
||||
{
|
||||
this.throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, relY, relZ);
|
||||
return this.getBlockStateInternal(relX, relY, relZ, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBlockStateWrapper getBlockState(int relX, int relY, int relZ, IMutableBlockPosWrapper mcBlockPos, IBlockStateWrapper guess)
|
||||
{
|
||||
this.throwIndexOutOfBoundsIfRelativePosOutsideChunkBounds(relX, relY, relZ);
|
||||
return this.getBlockStateInternal(relX, relY, relZ, guess);
|
||||
}
|
||||
|
||||
// internal getter logic
|
||||
private IBlockStateWrapper getBlockStateInternal(int relX, int y, int relZ, @Nullable IBlockStateWrapper guess)
|
||||
{
|
||||
try
|
||||
{
|
||||
// attempt to get the section for this position
|
||||
int i = (y - this.getInclusiveMinBuildHeight()) / 16;
|
||||
if (i >= 0 && i < this.levelChunkSections.length)
|
||||
{
|
||||
LevelChunkSection section = this.levelChunkSections[i];
|
||||
if (!section.hasOnlyAir())
|
||||
{
|
||||
if (guess != null)
|
||||
{
|
||||
return BlockStateWrapper.fromBlockState(section.getBlockState(relX & 15, y & 15, relZ & 15), this.wrappedLevel, guess);
|
||||
}
|
||||
else
|
||||
{
|
||||
return BlockStateWrapper.fromBlockState(section.getBlockState(relX & 15, y & 15, relZ & 15), this.wrappedLevel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return BlockStateWrapper.AIR;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return BlockStateWrapper.AIR;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public IMutableBlockPosWrapper getMutableBlockPosWrapper() { return MUTABLE_BLOCK_POS_WRAPPER_REF.get(); }
|
||||
|
||||
@Override
|
||||
public DhChunkPos getChunkPos() { return this.chunkPos; }
|
||||
|
||||
public ChunkAccess getChunk() { return this.chunk; }
|
||||
|
||||
public void trySetStatus(ChunkStatus status) { trySetStatus(this.getChunk(), status); }
|
||||
/** does nothing if the chunk object doesn't support setting it's status */
|
||||
public static void trySetStatus(ChunkAccess chunk, ChunkStatus status)
|
||||
{
|
||||
if (chunk instanceof ProtoChunk)
|
||||
{
|
||||
#if MC_VER < MC_1_21_1
|
||||
((ProtoChunk) chunk).setStatus(status);
|
||||
#else
|
||||
((ProtoChunk) chunk).setPersistedStatus(status);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
public ChunkStatus getStatus() { return getStatus(this.getChunk()); }
|
||||
public static ChunkStatus getStatus(ChunkAccess chunk)
|
||||
{
|
||||
#if MC_VER < MC_1_21_1
|
||||
return chunk.getStatus();
|
||||
#else
|
||||
return chunk.getPersistedStatus();
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
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 setIsDhSkyLightCorrect(boolean isDhLightCorrect) { this.isDhSkyLightCorrect = isDhLightCorrect; }
|
||||
@Override
|
||||
public void setIsDhBlockLightCorrect(boolean isDhLightCorrect) { this.isDhBlockLightCorrect = isDhLightCorrect; }
|
||||
|
||||
@Override
|
||||
public boolean isDhBlockLightingCorrect() { return this.isDhBlockLightCorrect; }
|
||||
@Override
|
||||
public boolean isDhSkyLightCorrect() { return this.isDhSkyLightCorrect; }
|
||||
|
||||
|
||||
@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 void clearDhBlockLighting() { this.getBlockLightStorage().clear(); }
|
||||
|
||||
|
||||
@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);
|
||||
}
|
||||
@Override
|
||||
public void clearDhSkyLighting() { this.getSkyLightStorage().clear(); }
|
||||
|
||||
private ChunkLightStorage getSkyLightStorage()
|
||||
{
|
||||
if (this.skyLightStorage == null)
|
||||
{
|
||||
this.skyLightStorage = ChunkLightStorage.createSkyLightStorage(this);
|
||||
}
|
||||
return this.skyLightStorage;
|
||||
}
|
||||
public void setSkyLightStorage(ChunkLightStorage lightStorage) { this.skyLightStorage = lightStorage; }
|
||||
|
||||
|
||||
/**
|
||||
* 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> getWorldBlockLightPosList()
|
||||
{
|
||||
// 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) ->
|
||||
{
|
||||
DhBlockPos pos = new DhBlockPos(blockPos.getX(), blockPos.getY(), blockPos.getZ());
|
||||
|
||||
// this can be uncommented if MC decides to return relative block positions in the future instead of world positions
|
||||
//pos.mutateToChunkRelativePos(pos);
|
||||
//pos.mutateOffset(this.chunkPos.getMinBlockX(), 0, this.chunkPos.getMinBlockZ(), pos);
|
||||
|
||||
this.blockLightPosList.add(pos);
|
||||
});
|
||||
#endif
|
||||
}
|
||||
|
||||
return this.blockLightPosList;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//===============//
|
||||
// other methods //
|
||||
//===============//
|
||||
|
||||
@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;
|
||||
//}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,729 @@
|
||||
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.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.*;
|
||||
import static com.seibel.distanthorizons.common.wrappers.gui.GuiHelper.Translatable;
|
||||
|
||||
|
||||
/*
|
||||
* Based upon TinyConfig but is highly modified
|
||||
* https://github.com/Minenash/TinyConfig
|
||||
*
|
||||
* Note: floats don't work with this system, use doubles.
|
||||
*
|
||||
* Credits to Motschen
|
||||
*
|
||||
* @author coolGi
|
||||
* @version 5-21-2022
|
||||
*/
|
||||
@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)
|
||||
{
|
||||
((EntryInfo) info.guiValue).widget = (BiFunction<EditBox, Button, Predicate<String>>) (editBox, button) -> stringValue ->
|
||||
{
|
||||
boolean isNumber = (pattern != null);
|
||||
|
||||
stringValue = stringValue.trim();
|
||||
if (!(stringValue.isEmpty() || !isNumber || pattern.matcher(stringValue).matches()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Number value = info.typeIsFloatingPointNumber() ? 0.0 : 0; // different default values are needed so implicit casting works correctly (if not done casting from 0 (an int) to a double will cause an exception)
|
||||
((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); // white and red
|
||||
// button.active = entries.stream().allMatch(e -> e.inLimits);
|
||||
|
||||
|
||||
if (info.getType() == String.class
|
||||
|| info.getType() == List.class)
|
||||
{
|
||||
((ConfigEntry) info).uiSetWithoutSaving(stringValue);
|
||||
}
|
||||
else if (((ConfigEntry) info).isValid(value) == 0)
|
||||
{
|
||||
if (!cast)
|
||||
{
|
||||
((ConfigEntry) info).uiSetWithoutSaving(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
((ConfigEntry) info).uiSetWithoutSaving(value != null ? value.intValue() : 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 (!this.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_1
|
||||
new ResourceLocation(ModInfo.ID, "textures/gui/changelog.png"),
|
||||
#else
|
||||
ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "textures/gui/changelog.png"),
|
||||
#endif
|
||||
20, 20,
|
||||
// Create the button and tell it where to go
|
||||
(buttonWidget) -> {
|
||||
ChangelogScreen changelogScreen = new ChangelogScreen(this);
|
||||
if (changelogScreen.usable)
|
||||
Objects.requireNonNull(this.minecraft).setScreen(changelogScreen);
|
||||
else
|
||||
LOGGER.warn("Changelog was not able to open");
|
||||
},
|
||||
// Add a title to the button
|
||||
Translatable(ModInfo.ID + ".updater.title")
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
this.addBtn(MakeBtn(Translatable("distanthorizons.general.cancel"),
|
||||
this.width / 2 - 154, this.height - 28,
|
||||
150, 20,
|
||||
button ->
|
||||
{
|
||||
ConfigBase.INSTANCE.configFileINSTANCE.loadFromFile();
|
||||
Objects.requireNonNull(this.minecraft).setScreen(this.parent);
|
||||
}));
|
||||
this.doneButton = this.addBtn(MakeBtn(Translatable("distanthorizons.general.done"), this.width / 2 + 4, this.height - 28, 150, 20, (button) -> {
|
||||
ConfigBase.INSTANCE.configFileINSTANCE.saveToFile();
|
||||
Objects.requireNonNull(this.minecraft).setScreen(this.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(this.category) && info.getAppearance().showInGui)
|
||||
this.addMenuItem(info);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
String message = "ERROR: Failed to show [\" + info.getNameWCategory() + \"], error: ["+e.getMessage()+"]";
|
||||
if (info.get() != null)
|
||||
{
|
||||
message += " with the value [" + info.get() + "] with type [" + info.getType() + "]";
|
||||
}
|
||||
|
||||
LOGGER.error(message, e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
CONFIG_CORE_INTERFACE.onScreenChangeListenerList.forEach((listener) -> listener.run());
|
||||
|
||||
}
|
||||
|
||||
private void addMenuItem(AbstractConfigType info)
|
||||
{
|
||||
initEntry(info, this.translationPrefix);
|
||||
Component name = Translatable(this.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(this.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(this.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(this.font, this.width - 150 - ConfigScreenConfigs.SpaceFromRightScreen + 2, 0, 150 - 4, 20, Translatable(""));
|
||||
widget.setMaxLength(150);
|
||||
widget.insertText(String.valueOf(info.get()));
|
||||
Predicate<String> processor = ((BiFunction<EditBox, Button, Predicate<String>>) ((EntryInfo) info.guiValue).widget).apply(widget, this.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(this.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 (ConfigUiLinkedEntry.class.isAssignableFrom(info.getClass()))
|
||||
{
|
||||
this.addMenuItem(((ConfigUiLinkedEntry) 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
|
||||
|
||||
// Render title
|
||||
this.DhDrawCenteredString(matrices, this.font, this.title, this.width / 2, 15,
|
||||
#if MC_VER < MC_1_21_6
|
||||
0xFFFFFF // RGB white
|
||||
#else
|
||||
0xFFFFFFFF // ARGB white
|
||||
#endif);
|
||||
|
||||
if (this.configBase.modID.equals("distanthorizons"))
|
||||
{
|
||||
// Display version
|
||||
this.DhDrawString(matrices, this.font, TextOrLiteral(ModInfo.VERSION), 2, this.height - 10,
|
||||
#if MC_VER < MC_1_21_6
|
||||
0xAAAAAA // RGB white
|
||||
#else
|
||||
0xFFAAAAAA // ARGB white
|
||||
#endif);
|
||||
|
||||
// If the update is pending, display this message to inform the user that it will apply when the game restarts
|
||||
if (SelfUpdater.deleteOldJarOnJvmShutdown)
|
||||
{
|
||||
this.DhDrawString(matrices, this.font, Translatable(this.configBase.modID + ".updater.waitingForClose"), 4, this.height - 38,
|
||||
#if MC_VER < MC_1_21_6
|
||||
0xFFFFFF // RGB white
|
||||
#else
|
||||
0xFFFFFFFF // ARGB white
|
||||
#endif);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 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 = ConfigUiLinkedEntry.class.isAssignableFrom(info.getClass()) ?
|
||||
((ConfigUiLinkedEntry) 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 configType, String translationPrefix)
|
||||
{
|
||||
configType.guiValue = new EntryInfo();
|
||||
Class<?> fieldClass = configType.getType();
|
||||
|
||||
if (ConfigEntry.class.isAssignableFrom(configType.getClass()))
|
||||
{
|
||||
if (fieldClass == Integer.class)
|
||||
{
|
||||
// For int
|
||||
textField(configType, Integer::parseInt, INTEGER_ONLY_REGEX, true);
|
||||
}
|
||||
else if (fieldClass == Double.class)
|
||||
{
|
||||
// For double
|
||||
textField(configType, Double::parseDouble, DECIMAL_ONLY_REGEX, false);
|
||||
}
|
||||
else if (fieldClass == String.class || fieldClass == List.class)
|
||||
{
|
||||
// For string or list
|
||||
textField(configType, 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) configType.guiValue).widget = new AbstractMap.SimpleEntry<Button.OnPress, Function<Object, Component>>(button -> {
|
||||
((ConfigEntry) configType).uiSetWithoutSaving(!(Boolean) configType.get());
|
||||
button.setMessage(func.apply(configType.get()));
|
||||
}, func);
|
||||
}
|
||||
else if (fieldClass.isEnum())
|
||||
{
|
||||
// For enum
|
||||
List<?> values = Arrays.asList(configType.getType().getEnumConstants());
|
||||
Function<Object, Component> func = value -> Translatable(translationPrefix + "enum." + fieldClass.getSimpleName() + "." + configType.get().toString());
|
||||
((EntryInfo) configType.guiValue).widget = new AbstractMap.SimpleEntry<Button.OnPress, Function<Object, Component>>(button -> {
|
||||
|
||||
// get the currently selected enum and enum index
|
||||
int startingIndex = values.indexOf(configType.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<?>>) configType).uiSetWithoutSaving(enumValue);
|
||||
button.setMessage(func.apply(configType.get()));
|
||||
}, func);
|
||||
}
|
||||
}
|
||||
else if (ConfigCategory.class.isAssignableFrom(configType.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);
|
||||
#elif MC_VER < MC_1_21_6
|
||||
matrices.drawString(textRenderer, this.text, 12, y + 5, 0xFFFFFF);
|
||||
#else
|
||||
matrices.drawString(textRenderer, this.text, 12, y + 5, 0xFFFFFFFF);
|
||||
#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,101 @@
|
||||
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);
|
||||
}
|
||||
#elif MC_VER < MC_1_21_6
|
||||
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);
|
||||
}
|
||||
#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.setComponentTooltipForNextFrame(font, comp, x, y);
|
||||
}
|
||||
protected void DhRenderTooltip(GuiGraphics guiStack, Font font, Component text, int x, int y)
|
||||
{
|
||||
guiStack.setTooltipForNextFrame(font, text, x, y);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers.gui;
|
||||
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
#if MC_VER >= MC_1_17_1
|
||||
import net.minecraft.client.gui.components.Button;
|
||||
#endif
|
||||
|
||||
#if MC_VER < MC_1_17_1
|
||||
import net.minecraft.client.gui.components.ImageButton;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import net.minecraft.client.Minecraft;
|
||||
#elif MC_VER < MC_1_20_1
|
||||
import net.minecraft.client.gui.components.ImageButton;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
import net.minecraft.client.renderer.GameRenderer;
|
||||
#elif MC_VER < MC_1_20_2
|
||||
import net.minecraft.client.gui.components.ImageButton;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
#elif MC_VER < MC_1_21_6
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
#else
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.RenderPipelines;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Creates a button with a texture on it (and a background) that works with all mc versions
|
||||
*
|
||||
* @author coolGi
|
||||
* @version 2023-10-03
|
||||
*/
|
||||
#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 textureResourceLocation;
|
||||
|
||||
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 textureResourceLocation, int textureWidth, int textureHeight, OnPress pressAction, Component text)
|
||||
{
|
||||
this(x, y, width, height, u, v, hoveredVOffset, textureResourceLocation, textureWidth, textureHeight, pressAction, text, true);
|
||||
}
|
||||
public TexturedButtonWidget(int x, int y, int width, int height, int u, int v, int hoveredVOffset, ResourceLocation textureResourceLocation, 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, textureResourceLocation, 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.textureResourceLocation = textureResourceLocation;
|
||||
|
||||
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)
|
||||
{
|
||||
#if MC_VER < MC_1_21_3
|
||||
matrices.blitSprite(SPRITES.get(this.active, this.isHoveredOrFocused()), this.getX(), this.getY(), this.getWidth(), this.getHeight());
|
||||
#elif MC_VER < MC_1_21_6
|
||||
matrices.blitSprite(
|
||||
RenderType::guiTextured,
|
||||
SPRITES.get(this.active, this.isHoveredOrFocused()),
|
||||
this.getX(), this.getY(),
|
||||
this.getWidth(), this.getHeight());
|
||||
#else
|
||||
matrices.blitSprite(
|
||||
RenderPipelines.GUI_TEXTURED,
|
||||
SPRITES.get(this.active, this.isHoveredOrFocused()),
|
||||
this.getX(), this.getY(),
|
||||
this.getWidth(), this.getHeight());
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
// Renders the sprite
|
||||
int i = 0;
|
||||
if (!this.active)
|
||||
{
|
||||
i = 2;
|
||||
}
|
||||
else if (this.isHovered)
|
||||
{
|
||||
i = 1;
|
||||
}
|
||||
|
||||
#if MC_VER < MC_1_21_3
|
||||
matrices.blit(this.textureResourceLocation, this.getX(), this.getY(), this.u, this.v + (this.hoveredVOffset * i), this.width, this.height, this.textureWidth, this.textureHeight);
|
||||
#elif MC_VER < MC_1_21_6
|
||||
matrices.blit(
|
||||
RenderType::guiTextured,
|
||||
this.textureResourceLocation,
|
||||
this.getX(), this.getY(),
|
||||
this.u, this.v + (this.hoveredVOffset * i),
|
||||
this.width, this.height,
|
||||
this.textureWidth, this.textureHeight);
|
||||
#else
|
||||
matrices.blit(
|
||||
RenderPipelines.GUI_TEXTURED,
|
||||
this.textureResourceLocation,
|
||||
this.getX(), this.getY(),
|
||||
this.u, this.v + (this.hoveredVOffset * i),
|
||||
this.width, this.height,
|
||||
this.textureWidth, this.textureHeight);
|
||||
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -0,0 +1,290 @@
|
||||
package com.seibel.distanthorizons.common.wrappers.gui.updater;
|
||||
|
||||
import com.seibel.distanthorizons.common.wrappers.gui.DhScreen;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
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;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
#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;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
#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 static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
|
||||
|
||||
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
|
||||
{
|
||||
this.setupChangelog(versionID);
|
||||
this.usable = true;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
LOGGER.error("failed to setup changelog, error: ["+e.getMessage()+"].", e);
|
||||
}
|
||||
}
|
||||
|
||||
public ChangelogScreen(Screen parent, String versionID)
|
||||
{
|
||||
super(Translatable(ModInfo.ID + ".updater.title"));
|
||||
this.parent = parent;
|
||||
this.versionID = versionID;
|
||||
|
||||
|
||||
if (versionID == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
this.setupChangelog(versionID);
|
||||
this.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("");
|
||||
|
||||
String changelog = ModrinthGetter.changeLogs.get(versionID);
|
||||
if (changelog == null)
|
||||
{
|
||||
// in case something goes wrong this will prevent null pointers
|
||||
changelog = "";
|
||||
}
|
||||
|
||||
// Get the release changelog and split it by the new lines
|
||||
String[] unwrappedChangelog = // Arrays.asList could be used if a list object is desired here vs List.of which is only available for Java 9+
|
||||
// This formats markdown to minecraft's "§" charactersnew MarkdownFormatter.MinecraftFormat().convertTo(
|
||||
new MarkdownFormatter.MinecraftFormat().convertTo(changelog).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 (!this.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 < this.changelog.size(); i++)
|
||||
{
|
||||
this.changelogArea.addButton(TextOrLiteral(this.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 (!this.usable)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int maxScroll;
|
||||
#if MC_VER <= MC_1_21_3
|
||||
maxScroll = this.changelogArea.getMaxScroll();
|
||||
#else
|
||||
maxScroll = this.changelogArea.maxScrollAmount();
|
||||
#endif
|
||||
|
||||
// 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 * maxScroll;
|
||||
|
||||
#if MC_VER == MC_1_16_5 || MC_VER == MC_1_17_1
|
||||
this.changelogArea.setScrollAmount(scrollAmount);
|
||||
#elif MC_VER <= MC_1_21_3
|
||||
this.changelogArea.scrollAmount = scrollAmount;
|
||||
#else
|
||||
this.changelogArea.setScrollAmount(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
|
||||
this.DhDrawCenteredString(matrices, this.font, this.title, this.width / 2, 15, 0xFFFFFF); // Render title
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose()
|
||||
{
|
||||
Objects.requireNonNull(this.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;
|
||||
this.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, this.text, 12, y + 5, 0xFFFFFF);
|
||||
}
|
||||
#endif
|
||||
|
||||
@Override
|
||||
public List<? extends GuiEventListener> children()
|
||||
{
|
||||
return this.children;
|
||||
}
|
||||
#if MC_VER >= MC_1_17_1
|
||||
@Override
|
||||
public List<? extends NarratableEntry> narratables()
|
||||
{
|
||||
return this.children;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
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.core.logging.DhLoggerBuilder;
|
||||
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 org.apache.logging.log4j.Logger;
|
||||
|
||||
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 static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
|
||||
|
||||
private Screen parent;
|
||||
private String newVersionID;
|
||||
|
||||
private String currentVer;
|
||||
private String nextVer;
|
||||
|
||||
|
||||
public UpdateModScreen(Screen parent, String newVersionID) throws IllegalArgumentException
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
// done to prevent trying to update to "null"
|
||||
// (this can happen if no versions are available to check/download from modrinth/gitlab)
|
||||
if (this.nextVer == null)
|
||||
{
|
||||
throw new IllegalArgumentException("No new version found with the ID ["+newVersionID+"].");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init()
|
||||
{
|
||||
super.init();
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
|
||||
// Logo image
|
||||
this.addBtn(new TexturedButtonWidget(
|
||||
// Where the button is on the screen
|
||||
this.width / 2 - 95, this.height / 2 - 110,
|
||||
// Width and height of the button
|
||||
195, 65,
|
||||
// Offset
|
||||
0, 0,
|
||||
// Some textuary stuff
|
||||
0,
|
||||
#if MC_VER < MC_1_21_1
|
||||
new ResourceLocation(ModInfo.ID, "logo.png"),
|
||||
#else
|
||||
ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "logo.png"),
|
||||
#endif
|
||||
195, 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)
|
||||
{
|
||||
LOGGER.error("Failed to setup update mod screen, error: ["+e.getMessage()+"].", e);
|
||||
}
|
||||
|
||||
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_1
|
||||
new ResourceLocation(ModInfo.ID, "textures/gui/changelog.png"),
|
||||
#else
|
||||
ResourceLocation.fromNamespaceAndPath(ModInfo.ID, "textures/gui/changelog.png"),
|
||||
#endif
|
||||
20, 20,
|
||||
// Create the button and tell it where to go
|
||||
(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
|
||||
#elif MC_VER < MC_1_21_6
|
||||
this.renderBackground(matrices, mouseX, mouseY, delta); // Render background
|
||||
#else
|
||||
// background blur is already being rendered, rendering again causes the game to crash
|
||||
#endif
|
||||
|
||||
// TODO: add the tooltips for the buttons
|
||||
super.render(matrices, mouseX, mouseY, delta); // Render the buttons
|
||||
// TODO: Add tooltips
|
||||
|
||||
// Render the text's
|
||||
this.DhDrawCenteredString(matrices, this.font,
|
||||
Translatable(ModInfo.ID + ".updater.text1"),
|
||||
this.width / 2, this.height / 2 - 35,
|
||||
#if MC_VER < MC_1_21_6
|
||||
0xFFFFFF // RGB
|
||||
#else
|
||||
0xFFFFFFFF // ARGB
|
||||
#endif
|
||||
);
|
||||
this.DhDrawCenteredString(matrices, this.font,
|
||||
Translatable(ModInfo.ID + ".updater.text2", this.currentVer, this.nextVer),
|
||||
this.width / 2, this.height / 2 - 20,
|
||||
#if MC_VER < MC_1_21_6
|
||||
0x52FD52 // RGB
|
||||
#else
|
||||
0xFF52FD52 // ARGB
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClose()
|
||||
{
|
||||
Objects.requireNonNull(this.minecraft).setScreen(this.parent); // Go to the parent screen
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
package com.seibel.distanthorizons.common.wrappers.level;
|
||||
|
||||
import com.seibel.distanthorizons.core.level.IServerKeyedClientLevel;
|
||||
import com.seibel.distanthorizons.core.level.IKeyedClientLevelManager;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.world.IClientLevelWrapper;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
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. */
|
||||
@Nullable
|
||||
private IServerKeyedClientLevel serverKeyedLevel = null;
|
||||
/** Allows to keep level manager enabled between loading different keyed levels */
|
||||
private boolean enabled = false;
|
||||
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
private KeyedClientLevelManager() { }
|
||||
|
||||
|
||||
|
||||
//======================//
|
||||
// level override logic //
|
||||
//======================//
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public IServerKeyedClientLevel getServerKeyedLevel() { return this.serverKeyedLevel; }
|
||||
|
||||
@Override
|
||||
public IServerKeyedClientLevel setServerKeyedLevel(IClientLevelWrapper clientLevel, String levelKey)
|
||||
{
|
||||
IServerKeyedClientLevel keyedLevel = new ServerKeyedClientLevel((ClientLevel) clientLevel.getWrappedMcObject(), levelKey);
|
||||
this.serverKeyedLevel = keyedLevel;
|
||||
this.enabled = true;
|
||||
return keyedLevel;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearKeyedLevel() { this.serverKeyedLevel = null; }
|
||||
@Override
|
||||
public boolean isEnabled() { return this.enabled; }
|
||||
@Override
|
||||
public void disable() { this.enabled = false; }
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
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.wrapperInterfaces.world.ILevelWrapper;
|
||||
import com.seibel.distanthorizons.coreapi.util.StringUtil;
|
||||
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; }
|
||||
|
||||
@Override
|
||||
public String getDhIdentifier() { return this.getServerLevelKey(); }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,378 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers.minecraft;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Objects;
|
||||
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.file.structure.ClientOnlySaveStructure;
|
||||
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.blockPos.DhBlockPos;
|
||||
import com.seibel.distanthorizons.core.pos.DhChunkPos;
|
||||
|
||||
import net.minecraft.CrashReport;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.multiplayer.ServerData;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.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.util.profiling.ProfilerFiller;
|
||||
import net.minecraft.world.level.ChunkPos;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
#if MC_VER < MC_1_21_3
|
||||
#else
|
||||
import net.minecraft.util.profiling.Profiler;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* A singleton that wraps the Minecraft object.
|
||||
*
|
||||
* @author James Seibel
|
||||
*/
|
||||
public class MinecraftClientWrapper implements IMinecraftClientWrapper, IMinecraftSharedWrapper
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
|
||||
private static final Minecraft MINECRAFT = Minecraft.getInstance();
|
||||
|
||||
public static final MinecraftClientWrapper INSTANCE = new MinecraftClientWrapper();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 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() { this.lightMap = null; }
|
||||
|
||||
|
||||
|
||||
//=================//
|
||||
// method wrappers //
|
||||
//=================//
|
||||
|
||||
@Override
|
||||
public float getShade(EDhDirection lodDirection)
|
||||
{
|
||||
EDhApiLodShading lodShading = Config.Client.Advanced.Graphics.Quality.lodShading.get();
|
||||
switch (lodShading)
|
||||
{
|
||||
default:
|
||||
case AUTO:
|
||||
if (MINECRAFT.level != null)
|
||||
{
|
||||
Direction mcDir = McObjectConverter.Convert(lodDirection);
|
||||
return MINECRAFT.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 MINECRAFT.hasSingleplayerServer(); }
|
||||
@Override
|
||||
public boolean clientConnectedToDedicatedServer() { return MINECRAFT.getCurrentServer() != null && !this.hasSinglePlayerServer(); }
|
||||
@Override
|
||||
public boolean connectedToReplay() { return !MINECRAFT.hasSingleplayerServer() && MINECRAFT.getCurrentServer() == null; }
|
||||
|
||||
@Override
|
||||
public String getCurrentServerName()
|
||||
{
|
||||
if (this.connectedToReplay())
|
||||
{
|
||||
return ClientOnlySaveStructure.REPLAY_SERVER_FOLDER_NAME;
|
||||
}
|
||||
else
|
||||
{
|
||||
ServerData server = MINECRAFT.getCurrentServer();
|
||||
return (server != null) ? server.name : "NULL";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCurrentServerIp()
|
||||
{
|
||||
if (this.connectedToReplay())
|
||||
{
|
||||
return "";
|
||||
}
|
||||
else
|
||||
{
|
||||
ServerData server = MINECRAFT.getCurrentServer();
|
||||
return (server != null) ? server.ip : "NA";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCurrentServerVersion()
|
||||
{
|
||||
ServerData server = MINECRAFT.getCurrentServer();
|
||||
return (server != null) ? server.version.getString() : "UNKOWN";
|
||||
}
|
||||
|
||||
//=============//
|
||||
// Simple gets //
|
||||
//=============//
|
||||
|
||||
public LocalPlayer getPlayer() { return MINECRAFT.player; }
|
||||
|
||||
@Override
|
||||
public boolean playerExists() { return MINECRAFT.player != null; }
|
||||
|
||||
@Override
|
||||
public UUID getPlayerUUID() { return this.getPlayer().getUUID(); }
|
||||
|
||||
@Override
|
||||
public String getUsername() { return MINECRAFT.getUser().getName(); }
|
||||
|
||||
@Override
|
||||
public DhBlockPos getPlayerBlockPos()
|
||||
{
|
||||
LocalPlayer player = this.getPlayer();
|
||||
if (player == null)
|
||||
{
|
||||
return new DhBlockPos(0, 0, 0);
|
||||
}
|
||||
|
||||
BlockPos playerPos = player.blockPosition();
|
||||
return new DhBlockPos(playerPos.getX(), playerPos.getY(), playerPos.getZ());
|
||||
}
|
||||
|
||||
@Override
|
||||
public DhChunkPos getPlayerChunkPos()
|
||||
{
|
||||
LocalPlayer player = this.getPlayer();
|
||||
if (player == null)
|
||||
{
|
||||
return new DhChunkPos(0, 0);
|
||||
}
|
||||
|
||||
#if MC_VER < MC_1_17_1
|
||||
ChunkPos playerPos = new ChunkPos(player.blockPosition());
|
||||
#else
|
||||
ChunkPos playerPos = player.chunkPosition();
|
||||
#endif
|
||||
return new DhChunkPos(playerPos.x, playerPos.z);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public IClientLevelWrapper getWrappedClientLevel() { return this.getWrappedClientLevel(false); }
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public IClientLevelWrapper getWrappedClientLevel(boolean bypassLevelKeyManager)
|
||||
{
|
||||
ClientLevel level = MINECRAFT.level;
|
||||
if (level == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return ClientLevelWrapper.getWrapper(level, bypassLevelKeyManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IProfilerWrapper getProfiler()
|
||||
{
|
||||
ProfilerFiller profiler;
|
||||
#if MC_VER < MC_1_21_3
|
||||
profiler = MINECRAFT.getProfiler();
|
||||
#else
|
||||
profiler = Profiler.get();
|
||||
#endif
|
||||
|
||||
if (this.profilerWrapper == null)
|
||||
{
|
||||
this.profilerWrapper = new ProfilerWrapper(profiler);
|
||||
}
|
||||
else if (profiler != this.profilerWrapper.profiler)
|
||||
{
|
||||
this.profilerWrapper.profiler = profiler;
|
||||
}
|
||||
|
||||
return this.profilerWrapper;
|
||||
}
|
||||
|
||||
/** Returns all worlds available to the server */
|
||||
@Override
|
||||
public ArrayList<ILevelWrapper> getAllServerWorlds()
|
||||
{
|
||||
ArrayList<ILevelWrapper> worlds = new ArrayList<ILevelWrapper>();
|
||||
|
||||
Iterable<ServerLevel> serverWorlds = MINECRAFT.getSingleplayerServer().getAllLevels();
|
||||
for (ServerLevel world : serverWorlds)
|
||||
{
|
||||
worlds.add(ServerLevelWrapper.getWrapper(world));
|
||||
}
|
||||
|
||||
return worlds;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void sendChatMessage(String string)
|
||||
{
|
||||
LocalPlayer player = this.getPlayer();
|
||||
if (player == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if MC_VER < MC_1_19_2
|
||||
player.sendMessage(new TextComponent(string), getPlayer().getUUID());
|
||||
#else
|
||||
player.displayClientMessage(net.minecraft.network.chat.Component.translatable(string), /*isOverlay*/false);
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendOverlayMessage(String string)
|
||||
{
|
||||
LocalPlayer player = this.getPlayer();
|
||||
if (player == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#if MC_VER < MC_1_19_2
|
||||
player.displayClientMessage(new TextComponent(string), /*isOverlay*/true);
|
||||
#else
|
||||
player.displayClientMessage(net.minecraft.network.chat.Component.translatable(string), /*isOverlay*/true);
|
||||
#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 MINECRAFT.options; }
|
||||
|
||||
@Override
|
||||
public boolean isDedicatedServer() { return false; }
|
||||
|
||||
@Override
|
||||
public File getInstallationDirectory() { return MINECRAFT.gameDirectory; }
|
||||
|
||||
@Override
|
||||
public void executeOnRenderThread(Runnable runnable) { MINECRAFT.execute(runnable); }
|
||||
|
||||
@Override
|
||||
public int getPlayerCount()
|
||||
{
|
||||
// can be null if the server hasn't finished booting up yet
|
||||
if (MINECRAFT.getSingleplayerServer() == null)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
return MINECRAFT.getSingleplayerServer().getPlayerCount();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,252 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers.minecraft;
|
||||
|
||||
#if MC_VER < MC_1_21_5
|
||||
import com.mojang.blaze3d.platform.GlStateManager;
|
||||
#elif MC_VER >= MC_1_21_5
|
||||
import com.mojang.blaze3d.opengl.GlStateManager;
|
||||
#endif
|
||||
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftGLWrapper;
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
|
||||
|
||||
/**
|
||||
* <b>Why does DH often call GL methods twice? </b><br>
|
||||
* Once using the base {@link GL32} function and a second time using
|
||||
* Minecraft's {@link GlStateManager}?<br><br>
|
||||
*
|
||||
* <b>Answer: </b><br>
|
||||
* Compatibility and robustness<br>
|
||||
* In general all MC rendering should go through MC's {@link GlStateManager},
|
||||
* however that isn't always the case.
|
||||
* So, to prevent issues if a mod (or MC itself) calls a direct GL function
|
||||
* instead of the {@link GlStateManager} wrapper, we need to be sure about what the actual
|
||||
* set value is (whether setting or getting) and that MC knows what DH has done.
|
||||
* This way whether a mod (or MC) is using the {@link GlStateManager} or direct GL calls,
|
||||
* they should always have the correct value for anything DH has modified.
|
||||
* <br><br>
|
||||
* This may slow down some low end GPUs that are driver limited,
|
||||
* however James would rather have slow correct rendering vs fast broken rendering.
|
||||
*/
|
||||
public class MinecraftGLWrapper implements IMinecraftGLWrapper
|
||||
{
|
||||
public static final MinecraftGLWrapper INSTANCE = new MinecraftGLWrapper();
|
||||
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
|
||||
|
||||
|
||||
/*
|
||||
private static final StencilState STENCIL;
|
||||
*/
|
||||
|
||||
|
||||
// scissor //
|
||||
|
||||
/** @see GL32#GL_SCISSOR_TEST */
|
||||
@Override
|
||||
public void enableScissorTest()
|
||||
{
|
||||
GL32.glEnable(GL32.GL_SCISSOR_TEST);
|
||||
GlStateManager._enableScissorTest();
|
||||
}
|
||||
/** @see GL32#GL_SCISSOR_TEST */
|
||||
@Override
|
||||
public void disableScissorTest()
|
||||
{
|
||||
GL32.glDisable(GL32.GL_SCISSOR_TEST);
|
||||
GlStateManager._disableScissorTest();
|
||||
}
|
||||
|
||||
|
||||
// stencil //
|
||||
//
|
||||
// /** @see GL32#GL_SCISSOR_TEST */
|
||||
// public void enableScissorTest() { GlStateManager._stencilFunc(); }
|
||||
// /** @see GL32#GL_SCISSOR_TEST */
|
||||
// public void disableScissorTest() { GlStateManager._disableScissorTest(); }
|
||||
|
||||
|
||||
// depth //
|
||||
|
||||
/** @see GL32#GL_DEPTH_TEST */
|
||||
@Override
|
||||
public void enableDepthTest()
|
||||
{
|
||||
GL32.glEnable(GL32.GL_DEPTH_TEST);
|
||||
GlStateManager._enableDepthTest();
|
||||
}
|
||||
/** @see GL32#GL_DEPTH_TEST */
|
||||
@Override
|
||||
public void disableDepthTest()
|
||||
{
|
||||
GL32.glDisable(GL32.GL_DEPTH_TEST);
|
||||
GlStateManager._disableDepthTest();
|
||||
}
|
||||
|
||||
/** @see GL32#glDepthFunc(int) */
|
||||
@Override
|
||||
public void glDepthFunc(int func)
|
||||
{
|
||||
GL32.glDepthFunc(func);
|
||||
GlStateManager._depthFunc(func);
|
||||
}
|
||||
|
||||
/** @see GL32#glDepthMask(boolean) */
|
||||
@Override
|
||||
public void enableDepthMask()
|
||||
{
|
||||
GL32.glDepthMask(true);
|
||||
GlStateManager._depthMask(true);
|
||||
}
|
||||
/** @see GL32#glDepthMask(boolean) */
|
||||
@Override
|
||||
public void disableDepthMask()
|
||||
{
|
||||
GL32.glDepthMask(false);
|
||||
GlStateManager._depthMask(false);
|
||||
}
|
||||
|
||||
|
||||
// blending //
|
||||
|
||||
/** @see GL32#GL_BLEND */
|
||||
@Override
|
||||
public void enableBlend()
|
||||
{
|
||||
GL32.glEnable(GL32.GL_BLEND);
|
||||
GlStateManager._enableBlend();
|
||||
}
|
||||
/** @see GL32#GL_BLEND */
|
||||
@Override
|
||||
public void disableBlend()
|
||||
{
|
||||
GL32.glDisable(GL32.GL_BLEND);
|
||||
GlStateManager._disableBlend();
|
||||
}
|
||||
|
||||
/** @see GL32#glBlendFunc */
|
||||
@Override
|
||||
public void glBlendFunc(int sfactor, int dfactor)
|
||||
{
|
||||
GL32.glBlendFunc(sfactor, dfactor);
|
||||
|
||||
#if MC_VER < MC_1_21_5
|
||||
GlStateManager._blendFunc(sfactor, dfactor);
|
||||
#endif
|
||||
}
|
||||
/** @see GL32#glBlendFuncSeparate */
|
||||
@Override
|
||||
public void glBlendFuncSeparate(int sfactorRGB, int dfactorRGB, int sfactorAlpha, int dfactorAlpha)
|
||||
{
|
||||
GL32.glBlendFuncSeparate(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha);
|
||||
GlStateManager._blendFuncSeparate(sfactorRGB, dfactorRGB, sfactorAlpha, dfactorAlpha);
|
||||
}
|
||||
|
||||
|
||||
// frame buffers //
|
||||
|
||||
/** @see GL32#glBindFramebuffer */
|
||||
@Override
|
||||
public void glBindFramebuffer(int target, int framebuffer)
|
||||
{
|
||||
GL32.glBindFramebuffer(target, framebuffer);
|
||||
GlStateManager._glBindFramebuffer(target, framebuffer);
|
||||
}
|
||||
|
||||
|
||||
// buffers //
|
||||
|
||||
/** @see GL32#glGenBuffers() */
|
||||
@Override
|
||||
public int glGenBuffers()
|
||||
{ return GlStateManager._glGenBuffers(); }
|
||||
|
||||
/** @see GL32#glDeleteBuffers(int) */
|
||||
@Override
|
||||
public void glDeleteBuffers(int buffer)
|
||||
{
|
||||
GL32.glDeleteBuffers(buffer);
|
||||
|
||||
// MC's implementation has a bug where it will throw:
|
||||
// GL_INVALID_OPERATION in glBufferData(immutable)
|
||||
// when attempting to delete Storage Buffers
|
||||
// So we need to manually delete the buffers ourselves
|
||||
//GlStateManager._glDeleteBuffers(buffer);
|
||||
}
|
||||
|
||||
|
||||
// culling //
|
||||
|
||||
/** @see GL32#GL_CULL_FACE */
|
||||
@Override
|
||||
public void enableFaceCulling()
|
||||
{
|
||||
GL32.glEnable(GL32.GL_CULL_FACE);
|
||||
GlStateManager._enableCull();
|
||||
}
|
||||
/** @see GL32#GL_CULL_FACE */
|
||||
@Override
|
||||
public void disableFaceCulling()
|
||||
{
|
||||
GL32.glDisable(GL32.GL_CULL_FACE);
|
||||
GlStateManager._disableCull();
|
||||
}
|
||||
|
||||
|
||||
// textures //
|
||||
|
||||
/** @see GL32#glGenTextures() */
|
||||
@Override
|
||||
public int glGenTextures() { return GlStateManager._genTexture(); }
|
||||
/** @see GL32#glDeleteTextures(int) */
|
||||
@Override
|
||||
public void glDeleteTextures(int texture) { GlStateManager._deleteTexture(texture); }
|
||||
|
||||
/** @see GL32#glActiveTexture(int) */
|
||||
@Override
|
||||
public void glActiveTexture(int textureId)
|
||||
{
|
||||
GL32.glActiveTexture(textureId);
|
||||
GlStateManager._activeTexture(textureId);
|
||||
}
|
||||
@Override
|
||||
public int getActiveTexture() { return GL32.glGetInteger(GL32.GL_TEXTURE_BINDING_2D); }
|
||||
|
||||
/**
|
||||
* Always binds to {@link GL32#GL_TEXTURE_2D}
|
||||
* @see GL32#glBindTexture(int, int)
|
||||
*/
|
||||
@Override
|
||||
public void glBindTexture(int texture)
|
||||
{
|
||||
GL32.glBindTexture(GL32.GL_TEXTURE_2D, texture);
|
||||
GlStateManager._bindTexture(texture);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,462 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers.minecraft;
|
||||
|
||||
import java.awt.Color;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.mojang.blaze3d.pipeline.RenderTarget;
|
||||
import com.mojang.blaze3d.platform.NativeImage;
|
||||
import com.seibel.distanthorizons.common.wrappers.WrapperFactory;
|
||||
import com.seibel.distanthorizons.common.wrappers.misc.LightMapWrapper;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.ModAccessorInjector;
|
||||
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.util.ColorUtil;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.ILightMapWrapper;
|
||||
|
||||
#if MC_VER < MC_1_17_1
|
||||
#elif MC_VER < MC_1_21_6
|
||||
import net.minecraft.client.renderer.FogRenderer;
|
||||
import com.mojang.blaze3d.systems.RenderSystem;
|
||||
#else
|
||||
import net.minecraft.client.renderer.fog.FogRenderer;
|
||||
#endif
|
||||
|
||||
#if MC_VER < MC_1_19_4
|
||||
import org.joml.Matrix4f;
|
||||
import org.joml.Vector3f;
|
||||
#else
|
||||
#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.core.util.math.Vec3d;
|
||||
import com.seibel.distanthorizons.core.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 net.minecraft.client.Camera;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.world.effect.MobEffects;
|
||||
#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
|
||||
import net.minecraft.world.level.material.FogType;
|
||||
#endif
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.joml.Vector4f;
|
||||
|
||||
#if MC_VER >= MC_1_21_5
|
||||
import com.mojang.blaze3d.opengl.GlTexture;
|
||||
#endif
|
||||
|
||||
/**
|
||||
* A singleton that contains everything
|
||||
* related to rendering in Minecraft.
|
||||
*
|
||||
* @author James Seibel
|
||||
* @version 12-12-2021
|
||||
*/
|
||||
//@Environment(EnvType.CLIENT)
|
||||
public class MinecraftRenderWrapper implements IMinecraftRenderWrapper
|
||||
{
|
||||
public static final MinecraftRenderWrapper INSTANCE = new MinecraftRenderWrapper();
|
||||
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
|
||||
private static final Minecraft MC = Minecraft.getInstance();
|
||||
private static final IWrapperFactory FACTORY = WrapperFactory.INSTANCE;
|
||||
|
||||
private static final IOptifineAccessor OPTIFINE_ACCESSOR = ModAccessorInjector.INSTANCE.get(IOptifineAccessor.class);
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
public boolean colorTextureCastFailLogged = false;
|
||||
public boolean depthTextureCastFailLogged = false;
|
||||
|
||||
#if MC_VER < MC_1_21_6
|
||||
#else
|
||||
private static FogRenderer mcFogRenderer = null;
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// methods //
|
||||
//=========//
|
||||
|
||||
@Override
|
||||
public Vec3f getLookAtVector()
|
||||
{
|
||||
Camera camera = MC.gameRenderer.getMainCamera();
|
||||
return new Vec3f(camera.getLookVector().x(), camera.getLookVector().y(), camera.getLookVector().z());
|
||||
}
|
||||
|
||||
@Override
|
||||
/** Unless you really need to know if the player is blind, use {@link MinecraftRenderWrapper#isFogStateSpecial()}/{@link IMinecraftRenderWrapper#isFogStateSpecial()} instead */
|
||||
public boolean playerHasBlindingEffect()
|
||||
{
|
||||
if (MC.player == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else if (MC.player.getActiveEffectsMap() == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
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
|
||||
public Vec3d getCameraExactPosition()
|
||||
{
|
||||
Camera camera = MC.gameRenderer.getMainCamera();
|
||||
Vec3 projectedView = camera.getPosition();
|
||||
|
||||
return new Vec3d(projectedView.x, projectedView.y, projectedView.z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getFogColor(float partialTicks)
|
||||
{
|
||||
#if MC_VER < MC_1_17_1
|
||||
float[] colorValues = new float[4];
|
||||
GL15.glGetFloatv(GL15.GL_FOG_COLOR, colorValues);
|
||||
return new Color(
|
||||
Math.max(0f, Math.min(colorValues[0], 1f)), // r
|
||||
Math.max(0f, Math.min(colorValues[1], 1f)), // g
|
||||
Math.max(0f, Math.min(colorValues[2], 1f)), // b
|
||||
Math.max(0f, Math.min(colorValues[3], 1f)) // a
|
||||
);
|
||||
#elif MC_VER < MC_1_21_3
|
||||
FogRenderer.setupColor(MC.gameRenderer.getMainCamera(), partialTicks, MC.level, 1, MC.gameRenderer.getDarkenWorldAmount(partialTicks));
|
||||
float[] colorValues = RenderSystem.getShaderFogColor();
|
||||
return new Color(
|
||||
Math.max(0f, Math.min(colorValues[0], 1f)), // r
|
||||
Math.max(0f, Math.min(colorValues[1], 1f)), // g
|
||||
Math.max(0f, Math.min(colorValues[2], 1f)), // b
|
||||
Math.max(0f, Math.min(colorValues[3], 1f)) // a
|
||||
);
|
||||
#elif MC_VER < MC_1_21_6
|
||||
Vector4f colorValues = FogRenderer.computeFogColor(MC.gameRenderer.getMainCamera(), partialTicks, MC.level, 1, MC.gameRenderer.getDarkenWorldAmount(partialTicks));
|
||||
return new Color(
|
||||
Math.max(0f, Math.min(colorValues.x, 1f)), // r
|
||||
Math.max(0f, Math.min(colorValues.y, 1f)), // g
|
||||
Math.max(0f, Math.min(colorValues.z, 1f)), // b
|
||||
Math.max(0f, Math.min(colorValues.w, 1f)) // a
|
||||
);
|
||||
#else
|
||||
|
||||
if (mcFogRenderer == null)
|
||||
{
|
||||
mcFogRenderer = new FogRenderer();
|
||||
}
|
||||
|
||||
if (MC.level == null)
|
||||
{
|
||||
// shouldn't happen, but just in case
|
||||
return Color.white;
|
||||
}
|
||||
|
||||
boolean isFoggy =
|
||||
MC.level.effects().isFoggyAt(
|
||||
MC.gameRenderer.getMainCamera().getBlockPosition().getX(),
|
||||
MC.gameRenderer.getMainCamera().getBlockPosition().getZ())
|
||||
|| MC.gui.getBossOverlay().shouldCreateWorldFog();
|
||||
Vector4f colorValues = mcFogRenderer.setupFog(MC.gameRenderer.getMainCamera(), MC.options.getEffectiveRenderDistance(), isFoggy, MC.deltaTracker, MC.gameRenderer.getDarkenWorldAmount(MC.deltaTracker.getGameTimeDeltaPartialTick(true)), MC.level);
|
||||
return new Color(
|
||||
Math.max(0f, Math.min(colorValues.x, 1f)), // r
|
||||
Math.max(0f, Math.min(colorValues.y, 1f)), // g
|
||||
Math.max(0f, Math.min(colorValues.z, 1f)), // b
|
||||
Math.max(0f, Math.min(colorValues.w, 1f)) // a
|
||||
);
|
||||
#endif
|
||||
}
|
||||
// getSpecialFogColor() is the same as getFogColor()
|
||||
|
||||
@Override
|
||||
public Color getSkyColor()
|
||||
{
|
||||
if (MC.level.dimensionType().hasSkyLight())
|
||||
{
|
||||
float frameTime;
|
||||
#if MC_VER < MC_1_21_1
|
||||
frameTime = MC.getFrameTime();
|
||||
#elif MC_VER < MC_1_21_3
|
||||
frameTime = MC.getTimer().getRealtimeDeltaTicks();
|
||||
#else
|
||||
frameTime = MC.deltaTracker.getGameTimeDeltaTicks();
|
||||
#endif
|
||||
|
||||
#if MC_VER < MC_1_17_1
|
||||
Vec3 colorValues = MC.level.getSkyColor(MC.gameRenderer.getMainCamera().getBlockPosition(), frameTime);
|
||||
return new Color((float) colorValues.x, (float) colorValues.y, (float) colorValues.z);
|
||||
#elif MC_VER < MC_1_21_3
|
||||
Vec3 colorValues = MC.level.getSkyColor(MC.gameRenderer.getMainCamera().getPosition(), frameTime);
|
||||
return new Color((float) colorValues.x, (float) colorValues.y, (float) colorValues.z);
|
||||
#else
|
||||
int argbColorInt = MC.level.getSkyColor(MC.gameRenderer.getMainCamera().getPosition(), frameTime);;
|
||||
return ColorUtil.toColorObjARGB(argbColorInt); // TODO MC changed color formats
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
return new Color(0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getFov(float partialTicks)
|
||||
{
|
||||
return MC.gameRenderer.getFov(MC.gameRenderer.getMainCamera(), partialTicks, true);
|
||||
}
|
||||
|
||||
/** Measured in chunks */
|
||||
@Override
|
||||
public int getRenderDistance()
|
||||
{
|
||||
#if MC_VER < MC_1_18_2
|
||||
//FIXME: How to resolve this?
|
||||
return MC.options.renderDistance;
|
||||
#else
|
||||
return MC.options.getEffectiveRenderDistance();
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getScreenWidth()
|
||||
{
|
||||
// alternate ways of getting the window's resolution,
|
||||
// using one of these methods may fix the optifine render resolution bug
|
||||
// TODO: test these once we can run with Optifine again
|
||||
// int[] heightArray = new int[1];
|
||||
// int[] widthArray = new int[1];
|
||||
//
|
||||
// long window = GLProxy.getInstance().minecraftGlContext;
|
||||
// GLFW.glfwGetWindowSize(window, widthArray, heightArray); // option 1
|
||||
// GLFW.glfwGetFramebufferSize(window, widthArray, heightArray); // option 2
|
||||
|
||||
|
||||
|
||||
int width = MC.getWindow().getWidth();
|
||||
if (OPTIFINE_ACCESSOR != null)
|
||||
{
|
||||
// TODO remove comment after testing:
|
||||
// this should fix the issue where different optifine render resolutions screw up the LOD rendering
|
||||
width *= OPTIFINE_ACCESSOR.getRenderResolutionMultiplier();
|
||||
}
|
||||
return width;
|
||||
}
|
||||
@Override
|
||||
public int getScreenHeight()
|
||||
{
|
||||
int height = MC.getWindow().getHeight();
|
||||
if (OPTIFINE_ACCESSOR != null)
|
||||
{
|
||||
height *= OPTIFINE_ACCESSOR.getRenderResolutionMultiplier();
|
||||
}
|
||||
return height;
|
||||
}
|
||||
|
||||
private RenderTarget getRenderTarget() { return MC.getMainRenderTarget(); }
|
||||
|
||||
@Override
|
||||
public boolean mcRendersToFrameBuffer()
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean runningLegacyOpenGL()
|
||||
{
|
||||
#if MC_VER <= MC_1_16_5
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTargetFrameBuffer()
|
||||
{
|
||||
// used so we can access the framebuffer shaders end up rendering to
|
||||
if (AbstractOptifineAccessor.optifinePresent())
|
||||
{
|
||||
return this.finalLevelFrameBufferId;
|
||||
}
|
||||
|
||||
#if MC_VER < MC_1_21_5
|
||||
return this.getRenderTarget().frameBufferId;
|
||||
#else
|
||||
// MC renders to a texture and then directly to the default FBO now
|
||||
// we need to draw to their texture instead of the FBO
|
||||
return 0; // 0 is the ID for the default frame buffer
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearTargetFrameBuffer() { this.finalLevelFrameBufferId = -1; }
|
||||
|
||||
@Override
|
||||
public int getDepthTextureId()
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return this.getRenderTarget().getDepthTextureId();
|
||||
#else
|
||||
try
|
||||
{
|
||||
GlTexture glTexture = (GlTexture) this.getRenderTarget().getDepthTexture();
|
||||
if (glTexture == null)
|
||||
{
|
||||
// shouldn't happen, but just in case
|
||||
return 0;
|
||||
}
|
||||
|
||||
return glTexture.glId();
|
||||
}
|
||||
catch (ClassCastException e)
|
||||
{
|
||||
// only log this error once per session
|
||||
if (!this.depthTextureCastFailLogged)
|
||||
{
|
||||
this.depthTextureCastFailLogged = true;
|
||||
LOGGER.error("Unable to cast render Target depth texture to GlTexture. MC or a rendering mod may have changed the object type.", e);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@Override
|
||||
public int getColorTextureId()
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return this.getRenderTarget().getColorTextureId();
|
||||
#else
|
||||
try
|
||||
{
|
||||
GlTexture glTexture = (GlTexture) this.getRenderTarget().getColorTexture();
|
||||
if (glTexture == null)
|
||||
{
|
||||
// shouldn't happen, but just in case
|
||||
return 0;
|
||||
}
|
||||
|
||||
return glTexture.glId();
|
||||
}
|
||||
catch (ClassCastException e)
|
||||
{
|
||||
// only log this error once per session
|
||||
if (!this.colorTextureCastFailLogged)
|
||||
{
|
||||
this.colorTextureCastFailLogged = true;
|
||||
LOGGER.error("Unable to cast render Target color texture to GlTexture. MC or a rendering mod may have changed the object type.", e);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTargetFrameBufferViewportWidth()
|
||||
{
|
||||
return this.getRenderTarget().viewWidth;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTargetFrameBufferViewportHeight()
|
||||
{
|
||||
return this.getRenderTarget().viewHeight;
|
||||
}
|
||||
|
||||
@Override
|
||||
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 isBlind = this.playerHasBlindingEffect();
|
||||
isBlind |= fluidState.is(FluidTags.WATER);
|
||||
isBlind |= fluidState.is(FluidTags.LAVA);
|
||||
return isBlind;
|
||||
#else
|
||||
boolean isBlind = this.playerHasBlindingEffect();
|
||||
return MC.gameRenderer.getMainCamera().getFluidInCamera() != FogType.NONE || isBlind;
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* It's better to use {@link MinecraftRenderWrapper#setLightmapId(int, IClientLevelWrapper)} if possible,
|
||||
* however old MC versions don't support it.
|
||||
*/
|
||||
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.computeIfAbsent(dimensionType, (dimType) -> new LightMapWrapper());
|
||||
wrapper.uploadLightmap(lightPixels);
|
||||
}
|
||||
public void setLightmapId(int tetxureId, 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.computeIfAbsent(dimensionType, (dimType) -> new LightMapWrapper());
|
||||
wrapper.setLightmapId(tetxureId);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
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 MinecraftServerWrapper implements IMinecraftSharedWrapper
|
||||
{
|
||||
public static final MinecraftServerWrapper INSTANCE = new MinecraftServerWrapper();
|
||||
|
||||
public DedicatedServer dedicatedServer = null;
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
private MinecraftServerWrapper() { }
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// methods //
|
||||
//=========//
|
||||
|
||||
@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 completed initialization!");
|
||||
}
|
||||
|
||||
#if MC_VER < MC_1_21_1
|
||||
return this.dedicatedServer.getServerDirectory();
|
||||
#else
|
||||
return this.dedicatedServer.getServerDirectory().toFile();
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPlayerCount()
|
||||
{
|
||||
return this.dedicatedServer.getPlayerCount();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers.minecraft;
|
||||
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IProfilerWrapper;
|
||||
|
||||
import net.minecraft.util.profiling.ProfilerFiller;
|
||||
|
||||
/**
|
||||
* @author James Seibel
|
||||
* @version 11-20-2021
|
||||
*/
|
||||
public class ProfilerWrapper implements IProfilerWrapper
|
||||
{
|
||||
public ProfilerFiller profiler;
|
||||
|
||||
public ProfilerWrapper(ProfilerFiller newProfiler) { this.profiler = newProfiler; }
|
||||
|
||||
|
||||
/** starts a new section inside the currently running section */
|
||||
@Override
|
||||
public void push(String newSection) { this.profiler.push(newSection); }
|
||||
|
||||
/** ends the currently running section and starts a new one */
|
||||
@Override
|
||||
public void popPush(String newSection) { this.profiler.popPush(newSection); }
|
||||
|
||||
/** ends the currently running section */
|
||||
@Override
|
||||
public void pop() { this.profiler.pop(); }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package com.seibel.distanthorizons.common.wrappers.misc;
|
||||
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface IMixinServerPlayer
|
||||
{
|
||||
@Nullable
|
||||
ServerLevel distantHorizons$getDimensionChangeDestination();
|
||||
|
||||
#if MC_VER == MC_1_16_5
|
||||
void distantHorizons$setDimensionChangeDestination(ServerLevel dimensionChangeDestination);
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers.misc;
|
||||
|
||||
import com.mojang.blaze3d.platform.NativeImage;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.minecraft.IMinecraftGLWrapper;
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.ILightMapWrapper;
|
||||
import org.apache.logging.log4j.Logger;
|
||||
import org.lwjgl.opengl.GL32;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class LightMapWrapper implements ILightMapWrapper
|
||||
{
|
||||
private static final IMinecraftGLWrapper GLMC = SingletonInjector.INSTANCE.get(IMinecraftGLWrapper.class);
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
|
||||
private int textureId = 0;
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// constructors //
|
||||
//==============//
|
||||
|
||||
public LightMapWrapper() { }
|
||||
|
||||
|
||||
|
||||
//==================//
|
||||
// lightmap syncing //
|
||||
//==================//
|
||||
|
||||
public void uploadLightmap(NativeImage image)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
int currentTexture = GLMC.getActiveTexture();
|
||||
if (this.textureId == 0)
|
||||
{
|
||||
this.createLightmap(image);
|
||||
}
|
||||
else
|
||||
{
|
||||
GLMC.glBindTexture(this.textureId);
|
||||
}
|
||||
image.upload(0, 0, 0, false);
|
||||
|
||||
// getActiveTexture() may return textures that aren't valid and attempting to bind them will
|
||||
// throw a GL error in MC 1.21.1
|
||||
if (GL32.glIsTexture(currentTexture))
|
||||
{
|
||||
GLMC.glBindTexture(currentTexture);
|
||||
}
|
||||
#else
|
||||
throw new UnsupportedOperationException("setLightmapId should be used for MC versions after 1.21.5"); // TODO that MC version number is wrong, when did we actually start using setLightmapId()?
|
||||
#endif
|
||||
}
|
||||
private void createLightmap(NativeImage image)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
this.textureId = GLMC.glGenTextures();
|
||||
GLMC.glBindTexture(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);
|
||||
#else
|
||||
throw new UnsupportedOperationException("setLightmapId should be used for MC versions after 1.21.5"); // TODO that MC version number is wrong, when did we actually start using setLightmapId()?
|
||||
#endif
|
||||
}
|
||||
|
||||
public void setLightmapId(int minecraftLightmapTetxureId)
|
||||
{
|
||||
// just use the MC texture ID
|
||||
this.textureId = minecraftLightmapTetxureId;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// lightmap use //
|
||||
//==============//
|
||||
|
||||
@Override
|
||||
public void bind()
|
||||
{
|
||||
GLMC.glActiveTexture(GL32.GL_TEXTURE0);
|
||||
GLMC.glBindTexture(this.textureId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unbind() { GLMC.glBindTexture(0); }
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.seibel.distanthorizons.common.wrappers.misc;
|
||||
|
||||
import com.seibel.distanthorizons.core.wrapperInterfaces.misc.IMutableBlockPosWrapper;
|
||||
import net.minecraft.core.BlockPos;
|
||||
|
||||
public class MutableBlockPosWrapper implements IMutableBlockPosWrapper
|
||||
{
|
||||
public final BlockPos.MutableBlockPos pos;
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
public MutableBlockPosWrapper()
|
||||
{
|
||||
this.pos = new BlockPos.MutableBlockPos();
|
||||
}
|
||||
|
||||
|
||||
|
||||
//===========//
|
||||
// overrides //
|
||||
//===========//
|
||||
|
||||
@Override
|
||||
public Object getWrappedMcObject() { return this.pos; }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
package com.seibel.distanthorizons.common.wrappers.misc;
|
||||
|
||||
import com.google.common.base.Objects;
|
||||
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 com.seibel.distanthorizons.core.util.math.Vec3d;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.network.ServerGamePacketListenerImpl;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
import java.net.SocketAddress;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
|
||||
/**
|
||||
* This wrapper transparently ensures that the underlying {@link ServerPlayer} is always valid,
|
||||
* unless the player has disconnected.
|
||||
*/
|
||||
public class ServerPlayerWrapper implements IServerPlayerWrapper
|
||||
{
|
||||
private static final ConcurrentMap<ServerGamePacketListenerImpl, ServerPlayerWrapper> serverPlayerWrapperMap = new MapMaker().weakKeys().weakValues().makeMap();
|
||||
|
||||
private final ServerGamePacketListenerImpl connection;
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
public static ServerPlayerWrapper getWrapper(ServerPlayer serverPlayer)
|
||||
{ return serverPlayerWrapperMap.computeIfAbsent(serverPlayer.connection, ignored -> new ServerPlayerWrapper(serverPlayer.connection)); }
|
||||
|
||||
private ServerPlayerWrapper(ServerGamePacketListenerImpl connection) { this.connection = connection; }
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// getters //
|
||||
//=========//
|
||||
|
||||
private ServerPlayer getServerPlayer() { return this.connection.player; }
|
||||
|
||||
@Override
|
||||
public String getName() { return this.getServerPlayer().getName().getString(); }
|
||||
|
||||
@Override
|
||||
public IServerLevelWrapper getLevel()
|
||||
{
|
||||
ServerLevel level = ((IMixinServerPlayer) this.getServerPlayer()).distantHorizons$getDimensionChangeDestination();
|
||||
if (level == null)
|
||||
{
|
||||
#if MC_VER < MC_1_20_1
|
||||
level = this.getServerPlayer().getLevel();
|
||||
#elif MC_VER < MC_1_21_6
|
||||
level = this.getServerPlayer().serverLevel();
|
||||
#else
|
||||
level = this.getServerPlayer().level();
|
||||
#endif
|
||||
}
|
||||
|
||||
return ServerLevelWrapper.getWrapper(level);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vec3d getPosition()
|
||||
{
|
||||
Vec3 position = this.getServerPlayer().position();
|
||||
return new Vec3d(position.x, position.y, position.z);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getViewDistance()
|
||||
{
|
||||
#if MC_VER < MC_1_21_6
|
||||
return this.getServerPlayer().server.getPlayerList().getViewDistance();
|
||||
#else
|
||||
return this.getServerPlayer().getServer().getPlayerList().getViewDistance();
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public SocketAddress getRemoteAddress()
|
||||
{
|
||||
#if MC_VER >= MC_1_19_4
|
||||
return this.getServerPlayer().connection.getRemoteAddress();
|
||||
#else // < 1.19.4
|
||||
return this.getServerPlayer().connection.connection.getRemoteAddress();
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// base overrides //
|
||||
//================//
|
||||
|
||||
@Override
|
||||
public Object getWrappedMcObject() { return this.getServerPlayer(); }
|
||||
|
||||
@Override
|
||||
public String toString() { return "Wrapped{" + this.getServerPlayer() + "}"; }
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (this == obj)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
if (!(obj instanceof ServerPlayerWrapper))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
ServerPlayerWrapper that = (ServerPlayerWrapper) obj;
|
||||
return Objects.equal(this.connection, that.connection);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() { return Objects.hashCode(this.connection); }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,374 @@
|
||||
package com.seibel.distanthorizons.common.wrappers.world;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiLevelType;
|
||||
import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegister;
|
||||
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
|
||||
import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.block.ClientBlockStateColorCache;
|
||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||
import com.seibel.distanthorizons.core.dependencyInjection.SingletonInjector;
|
||||
import com.seibel.distanthorizons.core.level.*;
|
||||
import com.seibel.distanthorizons.core.level.IServerKeyedClientLevel;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.pos.blockPos.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.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
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.awt.*;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Function;
|
||||
|
||||
#if MC_VER <= MC_1_20_4
|
||||
import net.minecraft.world.level.chunk.ChunkStatus;
|
||||
#else
|
||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||
#endif
|
||||
|
||||
#if MC_VER < MC_1_21_3
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
#else
|
||||
import com.seibel.distanthorizons.core.util.ColorUtil;
|
||||
#endif
|
||||
|
||||
public class ClientLevelWrapper implements IClientLevelWrapper
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger(ClientLevelWrapper.class.getSimpleName());
|
||||
/**
|
||||
* weak references are to prevent rare issues
|
||||
* where, upon world closure, some levels aren't shutdown/removed properly
|
||||
* and/or for servers were the level object isn't consistent
|
||||
*/
|
||||
private static final Map<ClientLevel, WeakReference<ClientLevelWrapper>> LEVEL_WRAPPER_REF_BY_CLIENT_LEVEL = Collections.synchronizedMap(new WeakHashMap<>());
|
||||
private static final IKeyedClientLevelManager KEYED_CLIENT_LEVEL_MANAGER = SingletonInjector.INSTANCE.get(IKeyedClientLevelManager.class);
|
||||
|
||||
private static final Minecraft MINECRAFT = Minecraft.getInstance();
|
||||
|
||||
private final ClientLevel level;
|
||||
private final ConcurrentHashMap<BlockState, ClientBlockStateColorCache> blockCache = new ConcurrentHashMap<>();
|
||||
|
||||
/** cached method reference to reduce GC overhead */
|
||||
private final Function<BlockState, ClientBlockStateColorCache> cachedBlockColorCacheFunction = (blockState) -> this.createBlockColorCache(blockState);
|
||||
|
||||
|
||||
private BlockStateWrapper dirtBlockWrapper;
|
||||
private BiomeWrapper plainsBiomeWrapper;
|
||||
@Deprecated // TODO circular references are bad
|
||||
private IDhLevel parentDhLevel;
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// constructor //
|
||||
//=============//
|
||||
|
||||
protected ClientLevelWrapper(ClientLevel level) { this.level = level; }
|
||||
|
||||
|
||||
|
||||
//==================//
|
||||
// instance methods //
|
||||
//==================//
|
||||
|
||||
public static IClientLevelWrapper getWrapper(@NotNull ClientLevel level) { return getWrapper(level, false); }
|
||||
|
||||
@Nullable
|
||||
public static IClientLevelWrapper getWrapper(@Nullable ClientLevel level, boolean bypassLevelKeyManager)
|
||||
{
|
||||
if (!bypassLevelKeyManager)
|
||||
{
|
||||
if (level == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// used if the client is connected to a server that defines the currently loaded level
|
||||
IServerKeyedClientLevel overrideLevel = KEYED_CLIENT_LEVEL_MANAGER.getServerKeyedLevel();
|
||||
if (overrideLevel != null)
|
||||
{
|
||||
return overrideLevel;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
WeakReference<ClientLevelWrapper> levelRef = LEVEL_WRAPPER_REF_BY_CLIENT_LEVEL.get(level);
|
||||
if (levelRef != null)
|
||||
{
|
||||
ClientLevelWrapper levelWrapper = levelRef.get();
|
||||
if (levelWrapper != null)
|
||||
{
|
||||
return levelWrapper;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return LEVEL_WRAPPER_REF_BY_CLIENT_LEVEL.compute(level, (newLevel, newLevelRef) ->
|
||||
{
|
||||
if (newLevelRef != null)
|
||||
{
|
||||
ClientLevelWrapper oldLevelWrapper = newLevelRef.get();
|
||||
if (oldLevelWrapper != null)
|
||||
{
|
||||
return newLevelRef;
|
||||
}
|
||||
}
|
||||
|
||||
return new WeakReference<>(new ClientLevelWrapper(newLevel));
|
||||
}).get();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public IServerLevelWrapper tryGetServerSideWrapper()
|
||||
{
|
||||
try
|
||||
{
|
||||
Iterable<ServerLevel> serverLevels = MINECRAFT.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: " + this.level);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//====================//
|
||||
// base level methods //
|
||||
//====================//
|
||||
|
||||
@Override
|
||||
public int getBlockColor(DhBlockPos pos, IBiomeWrapper biome, IBlockStateWrapper blockWrapper)
|
||||
{
|
||||
ClientBlockStateColorCache blockColorCache = this.blockCache.computeIfAbsent(
|
||||
((BlockStateWrapper) blockWrapper).blockState,
|
||||
this.cachedBlockColorCacheFunction);
|
||||
|
||||
return blockColorCache.getColor((BiomeWrapper) biome, pos);
|
||||
}
|
||||
/** used by {@link ClientLevelWrapper#cachedBlockColorCacheFunction} */
|
||||
private ClientBlockStateColorCache createBlockColorCache(BlockState block) { return new ClientBlockStateColorCache(block, this); }
|
||||
|
||||
|
||||
@Override
|
||||
public int getDirtBlockColor()
|
||||
{
|
||||
if (this.dirtBlockWrapper == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.dirtBlockWrapper = (BlockStateWrapper) BlockStateWrapper.deserialize(BlockStateWrapper.DIRT_RESOURCE_LOCATION_STRING, this);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
// shouldn't happen, but just in case
|
||||
LOGGER.warn("Unable to get dirt color with resource location ["+BlockStateWrapper.DIRT_RESOURCE_LOCATION_STRING+"] with level ["+this+"].", e);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return this.getBlockColor(DhBlockPos.ZERO,BiomeWrapper.EMPTY_WRAPPER, this.dirtBlockWrapper);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearBlockColorCache() { this.blockCache.clear(); }
|
||||
|
||||
@Override
|
||||
public IBiomeWrapper getPlainsBiomeWrapper()
|
||||
{
|
||||
if (this.plainsBiomeWrapper == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
this.plainsBiomeWrapper = (BiomeWrapper) BiomeWrapper.deserialize(BiomeWrapper.PLAINS_RESOURCE_LOCATION_STRING, this);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
// shouldn't happen, but just in case
|
||||
LOGGER.warn("Unable to get planes biome with resource location ["+BiomeWrapper.PLAINS_RESOURCE_LOCATION_STRING+"] with level ["+this+"].", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return this.plainsBiomeWrapper;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IDimensionTypeWrapper getDimensionType() { return DimensionTypeWrapper.getDimensionTypeWrapper(this.level.dimensionType()); }
|
||||
|
||||
|
||||
@Override
|
||||
public String getDimensionName() { return this.level.dimension().location().toString(); }
|
||||
|
||||
@Override
|
||||
public long getHashedSeed() { return this.level.getBiomeManager().biomeZoomSeed; }
|
||||
|
||||
@Override
|
||||
public String getDhIdentifier() { return this.getHashedSeedEncoded() + "@" + this.getDimensionName(); }
|
||||
|
||||
@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 getMaxHeight() { return this.level.getHeight(); }
|
||||
|
||||
@Override
|
||||
public int getMinHeight()
|
||||
{
|
||||
#if MC_VER < MC_1_17_1
|
||||
return 0;
|
||||
#elif MC_VER < MC_1_21_3
|
||||
return this.level.getMinBuildHeight();
|
||||
#else
|
||||
return this.level.getMinY();
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkWrapper tryGetChunk(DhChunkPos pos)
|
||||
{
|
||||
if (!this.level.hasChunk(pos.getX(), pos.getZ()))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
ChunkAccess chunk = this.level.getChunk(pos.getX(), pos.getZ(), ChunkStatus.EMPTY, false);
|
||||
if (chunk == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ChunkWrapper(chunk, 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_REF_BY_CLIENT_LEVEL.remove(this.level);
|
||||
this.parentDhLevel = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getDhSaveFolder()
|
||||
{
|
||||
if (this.parentDhLevel == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.parentDhLevel.getSaveStructure().getSaveFolder(this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//===================//
|
||||
// generic rendering //
|
||||
//===================//
|
||||
|
||||
@Override
|
||||
public void setParentLevel(IDhLevel parentLevel) { this.parentDhLevel = parentLevel; }
|
||||
|
||||
@Override
|
||||
public IDhApiCustomRenderRegister getRenderRegister()
|
||||
{
|
||||
if (this.parentDhLevel == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.parentDhLevel.getGenericRenderer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Color getCloudColor(float tickDelta)
|
||||
{
|
||||
#if MC_VER < MC_1_21_3
|
||||
Vec3 colorVec3 = this.level.getCloudColor(tickDelta);
|
||||
return new Color((float)colorVec3.x, (float)colorVec3.y, (float)colorVec3.z);
|
||||
#else
|
||||
int argbColor = this.level.getCloudColor(tickDelta);
|
||||
return ColorUtil.toColorObjARGB(argbColor);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// base overrides //
|
||||
//================//
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
if (this.level == null)
|
||||
{
|
||||
return "Wrapped{null}";
|
||||
}
|
||||
|
||||
return "Wrapped{" + this.level.toString() + "@" + this.getDhIdentifier() + "}";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.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
|
||||
*/
|
||||
public class DimensionTypeWrapper implements IDimensionTypeWrapper
|
||||
{
|
||||
private static final ConcurrentMap<String, DimensionTypeWrapper> DIMENSION_WRAPPER_BY_NAME = new ConcurrentHashMap<>();
|
||||
private final DimensionType dimensionType;
|
||||
|
||||
|
||||
|
||||
//=============//
|
||||
// Constructor //
|
||||
//=============//
|
||||
|
||||
public DimensionTypeWrapper(DimensionType dimensionType) { this.dimensionType = dimensionType; }
|
||||
|
||||
public static DimensionTypeWrapper getDimensionTypeWrapper(DimensionType dimensionType)
|
||||
{
|
||||
String dimName = getName(dimensionType);
|
||||
|
||||
// check if the dimension has already been wrapped
|
||||
if (DIMENSION_WRAPPER_BY_NAME.containsKey(dimName)
|
||||
&& DIMENSION_WRAPPER_BY_NAME.get(dimName) != null)
|
||||
{
|
||||
return DIMENSION_WRAPPER_BY_NAME.get(dimName);
|
||||
}
|
||||
|
||||
|
||||
// create the missing wrapper
|
||||
DimensionTypeWrapper dimensionTypeWrapper = new DimensionTypeWrapper(dimensionType);
|
||||
DIMENSION_WRAPPER_BY_NAME.put(dimName, dimensionTypeWrapper);
|
||||
return dimensionTypeWrapper;
|
||||
}
|
||||
|
||||
public static void clearMap() { DIMENSION_WRAPPER_BY_NAME.clear(); }
|
||||
|
||||
|
||||
|
||||
//=================//
|
||||
// wrapper methods //
|
||||
//=================//
|
||||
|
||||
@Override
|
||||
public String getName() { return getName(this.dimensionType); }
|
||||
public static String getName(DimensionType dimensionType)
|
||||
{
|
||||
#if MC_VER <= MC_1_16_5
|
||||
// effectsLocation() is marked as client only, so using the backing field directly
|
||||
return dimensionType.effectsLocation.getPath();
|
||||
#else
|
||||
return dimensionType.effectsLocation().getPath();
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasCeiling() { return this.dimensionType.hasCeiling(); }
|
||||
|
||||
@Override
|
||||
public boolean hasSkyLight() { return this.dimensionType.hasSkyLight(); }
|
||||
|
||||
@Override
|
||||
public Object getWrappedMcObject() { return this.dimensionType; }
|
||||
|
||||
// there's definitely a better way of doing this, but it should work well enough for now
|
||||
@Override
|
||||
public boolean isTheEnd() { return this.getName().equalsIgnoreCase("the_end"); }
|
||||
|
||||
@Override
|
||||
public double getCoordinateScale() { return this.dimensionType.coordinateScale(); }
|
||||
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// base overrides //
|
||||
//================//
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj)
|
||||
{
|
||||
if (obj.getClass() != DimensionTypeWrapper.class)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
DimensionTypeWrapper other = (DimensionTypeWrapper) obj;
|
||||
return other.getName().equals(this.getName());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers.world;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.WeakHashMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiLevelType;
|
||||
import com.seibel.distanthorizons.api.interfaces.render.IDhApiCustomRenderRegister;
|
||||
import com.seibel.distanthorizons.common.wrappers.McObjectConverter;
|
||||
import com.seibel.distanthorizons.common.wrappers.block.BiomeWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.block.BlockStateWrapper;
|
||||
import com.seibel.distanthorizons.common.wrappers.chunk.ChunkWrapper;
|
||||
import com.seibel.distanthorizons.core.level.IDhLevel;
|
||||
import com.seibel.distanthorizons.core.logging.DhLoggerBuilder;
|
||||
import com.seibel.distanthorizons.core.pos.blockPos.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.IServerLevelWrapper;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.level.Level;
|
||||
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
|
||||
|
||||
#if MC_VER < MC_1_21_3
|
||||
#else
|
||||
import java.nio.file.Path;
|
||||
#endif
|
||||
|
||||
import org.apache.logging.log4j.Logger;
|
||||
|
||||
public class ServerLevelWrapper implements IServerLevelWrapper
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger();
|
||||
/**
|
||||
* weak references are to prevent rare issues
|
||||
* where, upon world closure, some levels aren't shutdown/removed properly
|
||||
*/
|
||||
private static final Map<ServerLevel, WeakReference<ServerLevelWrapper>> LEVEL_WRAPPER_REF_BY_SERVER_LEVEL = Collections.synchronizedMap(new WeakHashMap<>());
|
||||
|
||||
private final ServerLevel level;
|
||||
@Deprecated // TODO circular references are bad
|
||||
private IDhLevel parentDhLevel;
|
||||
|
||||
|
||||
|
||||
//==============//
|
||||
// constructors //
|
||||
//==============//
|
||||
|
||||
public static ServerLevelWrapper getWrapper(ServerLevel level)
|
||||
{
|
||||
return LEVEL_WRAPPER_REF_BY_SERVER_LEVEL.compute(level, (newLevel, levelRef) ->
|
||||
{
|
||||
if (levelRef != null)
|
||||
{
|
||||
ServerLevelWrapper oldLevelWrapper = levelRef.get();
|
||||
if (oldLevelWrapper != null)
|
||||
{
|
||||
return levelRef;
|
||||
}
|
||||
}
|
||||
|
||||
return new WeakReference<>(new ServerLevelWrapper(newLevel));
|
||||
}).get();
|
||||
}
|
||||
|
||||
public ServerLevelWrapper(ServerLevel level) { this.level = level; }
|
||||
|
||||
|
||||
|
||||
//==================//
|
||||
// instance methods //
|
||||
//==================//
|
||||
|
||||
@Override
|
||||
public File getMcSaveFolder()
|
||||
{
|
||||
#if MC_VER < MC_1_21_3
|
||||
return this.level.getChunkSource().getDataStorage().dataFolder;
|
||||
#else
|
||||
return this.level.getChunkSource().getDataStorage().dataFolder.toFile();
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getWorldFolderName()
|
||||
{
|
||||
// Need specifically overworld since it's the only dimension that is stored in a server root folder
|
||||
|
||||
#if MC_VER >= MC_1_21_3
|
||||
return this.level.getServer().getLevel(Level.OVERWORLD).getChunkSource().getDataStorage().dataFolder.getParent().getFileName().toString();
|
||||
#else // <= 1.21.3
|
||||
return this.level.getServer().getLevel(Level.OVERWORLD).getChunkSource().getDataStorage().dataFolder.getParentFile().getName();
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public DimensionTypeWrapper getDimensionType() { return DimensionTypeWrapper.getDimensionTypeWrapper(this.level.dimensionType()); }
|
||||
|
||||
@Override
|
||||
public String getDimensionName() { return this.level.dimension().location().toString(); }
|
||||
|
||||
@Override
|
||||
public long getHashedSeed() { return this.level.getBiomeManager().biomeZoomSeed; }
|
||||
|
||||
@Override
|
||||
public String getDhIdentifier() { return this.getDimensionName(); }
|
||||
|
||||
@Override
|
||||
public EDhApiLevelType getLevelType() { return EDhApiLevelType.SERVER_LEVEL; }
|
||||
|
||||
public ServerLevel 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 getMaxHeight() { return this.level.getHeight(); }
|
||||
|
||||
@Override
|
||||
public int getMinHeight()
|
||||
{
|
||||
#if MC_VER < MC_1_17_1
|
||||
return 0;
|
||||
#elif MC_VER < MC_1_21_3
|
||||
return this.level.getMinBuildHeight();
|
||||
#else
|
||||
return this.level.getMinY();
|
||||
#endif
|
||||
}
|
||||
|
||||
@Override
|
||||
public IChunkWrapper tryGetChunk(DhChunkPos pos)
|
||||
{
|
||||
if (!this.level.hasChunk(pos.getX(), pos.getZ()))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
ChunkAccess chunk = this.level.getChunk(pos.getX(), pos.getZ(), ChunkStatus.FULL, false);
|
||||
if (chunk == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new ChunkWrapper(chunk, 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 = 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 ServerLevel getWrappedMcObject() { return this.level; }
|
||||
|
||||
@Override
|
||||
public void onUnload() { LEVEL_WRAPPER_REF_BY_SERVER_LEVEL.remove(this.level); }
|
||||
|
||||
|
||||
@Override
|
||||
public void setParentLevel(IDhLevel parentLevel) { this.parentDhLevel = parentLevel; }
|
||||
|
||||
@Override
|
||||
public IDhApiCustomRenderRegister getRenderRegister()
|
||||
{
|
||||
if (this.parentDhLevel == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.parentDhLevel.getGenericRenderer();
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getDhSaveFolder()
|
||||
{
|
||||
if (this.parentDhLevel == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return this.parentDhLevel.getSaveStructure().getSaveFolder(this);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// base overrides //
|
||||
//================//
|
||||
|
||||
@Override
|
||||
public String toString() { return "Wrapped{" + this.level.toString() + "@" + this.getDhIdentifier() + "}"; }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration;
|
||||
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import com.seibel.distanthorizons.api.enums.worldGeneration.EDhApiDistantGeneratorMode;
|
||||
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;
|
||||
|
||||
public final class GenerationEvent
|
||||
{
|
||||
private static final Logger LOGGER = DhLoggerBuilder.getLogger(MethodHandles.lookup().lookupClass().getSimpleName());
|
||||
private static int generationFutureDebugIDs = 0;
|
||||
|
||||
public final int id;
|
||||
public final ThreadedParameters threadedParam;
|
||||
public final DhChunkPos minPos;
|
||||
/** the number of chunks wide this event is */
|
||||
public final int size;
|
||||
public final EDhApiWorldGenerationStep targetGenerationStep;
|
||||
public final EDhApiDistantGeneratorMode generatorMode;
|
||||
public EventTimer timer = null;
|
||||
public long inQueueTime;
|
||||
public long timeoutTime = -1;
|
||||
public CompletableFuture<Void> future = null;
|
||||
public final Consumer<IChunkWrapper> resultConsumer;
|
||||
|
||||
|
||||
|
||||
public GenerationEvent(
|
||||
DhChunkPos minPos, int size, BatchGenerationEnvironment generationGroup,
|
||||
EDhApiDistantGeneratorMode generatorMode, EDhApiWorldGenerationStep targetGenerationStep, Consumer<IChunkWrapper> resultConsumer)
|
||||
{
|
||||
this.inQueueTime = System.nanoTime();
|
||||
this.id = generationFutureDebugIDs++;
|
||||
this.minPos = minPos;
|
||||
this.size = size;
|
||||
this.generatorMode = generatorMode;
|
||||
this.targetGenerationStep = targetGenerationStep;
|
||||
this.threadedParam = ThreadedParameters.getOrMake(generationGroup.params);
|
||||
this.resultConsumer = resultConsumer;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static GenerationEvent startEvent(
|
||||
DhChunkPos minPos, int size, BatchGenerationEnvironment genEnvironment,
|
||||
EDhApiDistantGeneratorMode generatorMode, EDhApiWorldGenerationStep target, Consumer<IChunkWrapper> resultConsumer,
|
||||
ExecutorService worldGeneratorThreadPool)
|
||||
{
|
||||
GenerationEvent generationEvent = new GenerationEvent(minPos, size, genEnvironment, generatorMode, target, resultConsumer);
|
||||
generationEvent.future = CompletableFuture.supplyAsync(() ->
|
||||
{
|
||||
long runStartTime = System.nanoTime();
|
||||
generationEvent.timeoutTime = runStartTime;
|
||||
generationEvent.inQueueTime = runStartTime - generationEvent.inQueueTime;
|
||||
generationEvent.timer = new EventTimer("setup");
|
||||
|
||||
BatchGenerationEnvironment.isDistantGeneratorThread.set(true);
|
||||
|
||||
try
|
||||
{
|
||||
genEnvironment.generateLodFromListAsync(generationEvent, (runnable) ->
|
||||
{
|
||||
worldGeneratorThreadPool.execute(() ->
|
||||
{
|
||||
boolean alreadyMarked = BatchGenerationEnvironment.isCurrentThreadDistantGeneratorThread();
|
||||
if (!alreadyMarked)
|
||||
{
|
||||
BatchGenerationEnvironment.isDistantGeneratorThread.set(true);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
runnable.run();
|
||||
}
|
||||
catch (Throwable throwable)
|
||||
{
|
||||
handleWorldGenThrowable(generationEvent, throwable);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (!alreadyMarked)
|
||||
{
|
||||
BatchGenerationEnvironment.isDistantGeneratorThread.set(false);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
catch (Throwable initialThrowable)
|
||||
{
|
||||
handleWorldGenThrowable(generationEvent, initialThrowable);
|
||||
}
|
||||
finally
|
||||
{
|
||||
BatchGenerationEnvironment.isDistantGeneratorThread.remove();
|
||||
}
|
||||
|
||||
return null;
|
||||
}, worldGeneratorThreadPool);
|
||||
return generationEvent;
|
||||
}
|
||||
/** There's probably a better way to handle this, but it'll work for now */
|
||||
private static void handleWorldGenThrowable(GenerationEvent generationEvent, Throwable initialThrowable)
|
||||
{
|
||||
Throwable throwable = initialThrowable;
|
||||
while (throwable instanceof CompletionException)
|
||||
{
|
||||
throwable = throwable.getCause();
|
||||
}
|
||||
|
||||
if (throwable instanceof InterruptedException
|
||||
|| throwable instanceof UncheckedInterruptedException
|
||||
|| throwable instanceof RejectedExecutionException)
|
||||
{
|
||||
// these exceptions can be ignored, generally they just mean
|
||||
// the thread is busy so it'll need to try again later.
|
||||
// FIXME this should cause the world gen task to be re-queued so we can try again later
|
||||
// however, currently it can cause large gaps in the world gen instead.
|
||||
// These gaps will generate correctly if the level is reloaded and the world gen is re-queued,
|
||||
// however this is makes it look like the generator isn't working or skipped something.
|
||||
}
|
||||
else
|
||||
{
|
||||
generationEvent.future.completeExceptionally(throwable);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isComplete() { return this.future.isDone(); }
|
||||
|
||||
public boolean hasTimeout(int duration, TimeUnit unit)
|
||||
{
|
||||
if (this.timeoutTime == -1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
long currentTime = System.nanoTime();
|
||||
long delta = currentTime - this.timeoutTime;
|
||||
return (delta > TimeUnit.NANOSECONDS.convert(duration, unit));
|
||||
}
|
||||
|
||||
public boolean terminate()
|
||||
{
|
||||
LOGGER.info("======================DUMPING ALL THREADS FOR WORLD GEN=======================");
|
||||
ThreadPoolUtil.WORLD_GEN_THREAD_FACTORY.dumpAllThreadStacks();
|
||||
this.future.cancel(true);
|
||||
return this.future.isCancelled();
|
||||
}
|
||||
|
||||
public void refreshTimeout()
|
||||
{
|
||||
this.timeoutTime = System.nanoTime();
|
||||
UncheckedInterruptedException.throwIfInterrupted();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() { return this.id + ":" + this.size + "@" + this.minPos + "(" + this.targetGenerationStep + ")"; }
|
||||
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration;
|
||||
|
||||
import com.mojang.datafixers.DataFixer;
|
||||
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;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
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 MC_VER >= MC_1_18_2
|
||||
import net.minecraft.world.level.chunk.storage.ChunkScanAccess;
|
||||
#endif
|
||||
import net.minecraft.world.level.levelgen.WorldGenSettings;
|
||||
#if MC_VER < MC_1_19_2
|
||||
import net.minecraft.world.level.levelgen.structure.templatesystem.StructureManager;
|
||||
#else
|
||||
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;
|
||||
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 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;
|
||||
#else
|
||||
public final WorldOptions worldOptions;
|
||||
#endif
|
||||
|
||||
#if MC_VER >= MC_1_18_2
|
||||
public final BiomeManager biomeManager;
|
||||
public final ChunkScanAccess chunkScanner; // FIXME: Figure out if this is actually needed
|
||||
#endif
|
||||
|
||||
public GlobalParameters(IDhServerLevel lodLevel)
|
||||
{
|
||||
this.lodLevel = lodLevel;
|
||||
|
||||
this.level = ((ServerLevelWrapper) lodLevel.getServerLevelWrapper()).getWrappedMcObject();
|
||||
MinecraftServer server = this.level.getServer();
|
||||
WorldData worldData = server.getWorldData();
|
||||
this.registry = server.registryAccess();
|
||||
|
||||
#if MC_VER < MC_1_19_4
|
||||
this.worldGenSettings = worldData.worldGenSettings();
|
||||
this.biomes = registry.registryOrThrow(Registry.BIOME_REGISTRY);
|
||||
this.worldSeed = worldGenSettings.seed();
|
||||
#elif MC_VER < MC_1_21_3
|
||||
this.worldOptions = worldData.worldGenOptions();
|
||||
this.biomes = registry.registryOrThrow(Registries.BIOME);
|
||||
this.worldSeed = worldOptions.seed();
|
||||
#else
|
||||
this.worldOptions = worldData.worldGenOptions();
|
||||
this.biomes = this.registry.lookupOrThrow(Registries.BIOME);
|
||||
this.worldSeed = this.worldOptions.seed();
|
||||
#endif
|
||||
|
||||
#if MC_VER >= MC_1_18_2
|
||||
this.biomeManager = new BiomeManager(this.level, BiomeManager.obfuscateSeed(this.worldSeed));
|
||||
this.chunkScanner = this.level.getChunkSource().chunkScanner();
|
||||
#endif
|
||||
this.structures = server.getStructureManager();
|
||||
this.generator = this.level.getChunkSource().getGenerator();
|
||||
this.fixerUpper = server.getFixerUpper();
|
||||
#if MC_VER >= MC_1_19_2
|
||||
this.randomState = this.level.getChunkSource().randomState();
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration;
|
||||
|
||||
//FIXME: Move this outside the WorldGenerationStep thingy
|
||||
public class Rolling
|
||||
{
|
||||
|
||||
private final int size;
|
||||
private double total = 0d;
|
||||
private int index = 0;
|
||||
private final double[] samples;
|
||||
|
||||
public Rolling(int size)
|
||||
{
|
||||
this.size = size;
|
||||
samples = new double[size];
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
samples[i] = 0d;
|
||||
}
|
||||
}
|
||||
|
||||
public void add(double x)
|
||||
{
|
||||
total -= samples[index];
|
||||
samples[index] = x;
|
||||
total += x;
|
||||
if (++index == size)
|
||||
index = 0; // cheaper than modulus
|
||||
}
|
||||
|
||||
public double getAverage()
|
||||
{
|
||||
return size == 0 ? 0 : total / size;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,109 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU LGPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Lesser General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
package com.seibel.distanthorizons.common.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 MC_VER >= MC_1_18_2
|
||||
import net.minecraft.world.level.levelgen.structure.StructureCheck;
|
||||
#endif
|
||||
|
||||
public final class ThreadedParameters
|
||||
{
|
||||
private static final ThreadLocal<ThreadedParameters> LOCAL_PARAM = new ThreadLocal<>();
|
||||
|
||||
final ServerLevel level;
|
||||
public WorldGenStructFeatManager structFeat = null;
|
||||
#if MC_VER >= MC_1_18_2
|
||||
public StructureCheck structCheck;
|
||||
#endif
|
||||
boolean isValid = true;
|
||||
public final PerfCalculator perf = new PerfCalculator();
|
||||
|
||||
private static GlobalParameters previousGlobalParameters = null;
|
||||
|
||||
|
||||
|
||||
public static ThreadedParameters getOrMake(GlobalParameters param)
|
||||
{
|
||||
ThreadedParameters tParam = LOCAL_PARAM.get();
|
||||
if (tParam != null && tParam.isValid && tParam.level == param.level)
|
||||
{
|
||||
return tParam;
|
||||
}
|
||||
|
||||
tParam = new ThreadedParameters(param);
|
||||
LOCAL_PARAM.set(tParam);
|
||||
return tParam;
|
||||
}
|
||||
|
||||
private ThreadedParameters(GlobalParameters param)
|
||||
{
|
||||
previousGlobalParameters = param;
|
||||
|
||||
this.level = param.level;
|
||||
#if MC_VER < MC_1_18_2
|
||||
this.structFeat = new WorldGenStructFeatManager(param.worldGenSettings, level);
|
||||
#elif MC_VER < MC_1_19_2
|
||||
this.structCheck = this.createStructureCheck(param);
|
||||
#else
|
||||
this.structCheck = new StructureCheck(param.chunkScanner, param.registry, param.structures,
|
||||
param.level.dimension(), param.generator, param.randomState, level, param.generator.getBiomeSource(), param.worldSeed,
|
||||
param.fixerUpper);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void markAsInvalid() { isValid = false; }
|
||||
|
||||
public void makeStructFeat(WorldGenLevel genLevel, GlobalParameters param)
|
||||
{
|
||||
#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 MC_VER >= MC_1_18_2 && MC_VER < MC_1_19_2
|
||||
public void recreateStructureCheck()
|
||||
{
|
||||
if (previousGlobalParameters != null)
|
||||
{
|
||||
this.structCheck = createStructureCheck(previousGlobalParameters);
|
||||
}
|
||||
}
|
||||
private StructureCheck createStructureCheck(GlobalParameters param)
|
||||
{
|
||||
return new StructureCheck(param.chunkScanner, param.registry, param.structures,
|
||||
param.level.dimension(), param.generator, this.level, param.generator.getBiomeSource(), param.worldSeed,
|
||||
param.fixerUpper);
|
||||
}
|
||||
#else
|
||||
public void recreateStructureCheck() { /* do nothing */ }
|
||||
#endif
|
||||
|
||||
}
|
||||
@@ -0,0 +1,851 @@
|
||||
/*
|
||||
* This file is part of the Distant Horizons mod
|
||||
* licensed under the GNU GPL v3 License.
|
||||
*
|
||||
* Copyright (C) 2020 James Seibel
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, version 3.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.seibel.distanthorizons.common.wrappers.worldGeneration.mimicObject;
|
||||
|
||||
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.chunk.ChunkLightStorage;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
|
||||
import it.unimi.dsi.fastutil.shorts.ShortList;
|
||||
import net.minecraft.core.Registry;
|
||||
#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.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.*;
|
||||
|
||||
#if MC_VER < MC_1_21_3
|
||||
import net.minecraft.world.level.chunk.storage.ChunkSerializer;
|
||||
#else
|
||||
#endif
|
||||
|
||||
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.ticks.LevelChunkTicks;
|
||||
#endif
|
||||
#if MC_VER >= MC_1_18_2
|
||||
import net.minecraft.core.Holder;
|
||||
#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_1
|
||||
import net.minecraft.world.level.chunk.status.ChunkStatus;
|
||||
import net.minecraft.world.level.chunk.status.ChunkType;
|
||||
#endif
|
||||
|
||||
import net.minecraft.world.level.material.Fluid;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
|
||||
public class ChunkLoader
|
||||
{
|
||||
private static final AtomicBoolean ZERO_CHUNK_POS_ERROR_LOGGED_REF = new AtomicBoolean(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;
|
||||
|
||||
private static final ConcurrentHashMap<String, Object> LOGGED_ERROR_MESSAGE_MAP = new ConcurrentHashMap<>();
|
||||
|
||||
|
||||
|
||||
//============//
|
||||
// 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
|
||||
|
||||
int chunkX = tagGetInt(tagLevel,"xPos");
|
||||
int chunkZ = tagGetInt(tagLevel, "zPos");
|
||||
ChunkPos actualPos = new ChunkPos(chunkX, chunkZ);
|
||||
|
||||
if (!Objects.equals(chunkPos, actualPos))
|
||||
{
|
||||
if (chunkX == 0 && chunkZ == 0)
|
||||
{
|
||||
if (!ZERO_CHUNK_POS_ERROR_LOGGED_REF.getAndSet(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;
|
||||
#elif MC_VER < MC_1_21_6
|
||||
|
||||
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
|
||||
#else
|
||||
|
||||
// ignore blending data, there appears to be an issue with parsing it in 1.21.6
|
||||
BlendingData blendingData = null;
|
||||
|
||||
if (chunkType == ChunkType.PROTOCHUNK)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
#endif
|
||||
|
||||
long inhabitedTime = tagGetLong(tagLevel, "InhabitedTime");
|
||||
|
||||
//================== Read params for making the LevelChunk ==================
|
||||
|
||||
UpgradeData upgradeData = UpgradeData.EMPTY;
|
||||
// commented out 2025-06-04 as a test to see if the upgrade data
|
||||
// is actually necessary for DH or if it can be ignored
|
||||
// (if it can't be ignored we'll need to handle null responses from tagGetCompoundTag())
|
||||
//
|
||||
//#if MC_VER < MC_1_17_1
|
||||
//upgradeData = tagLevel.contains(TAG_UPGRADE_DATA, 10)
|
||||
// ? new UpgradeData(tagGetCompoundTag(tagLevel, TAG_UPGRADE_DATA))
|
||||
// : UpgradeData.EMPTY;
|
||||
//#elif MC_VER < MC_1_21_5
|
||||
//upgradeData = tagLevel.contains(TAG_UPGRADE_DATA, 10)
|
||||
// ? new UpgradeData(tagGetCompoundTag(tagLevel, TAG_UPGRADE_DATA), level)
|
||||
// : UpgradeData.EMPTY;
|
||||
//#else
|
||||
//upgradeData = tagLevel.contains(TAG_UPGRADE_DATA)
|
||||
// ? new UpgradeData(tagGetCompoundTag(tagLevel, TAG_UPGRADE_DATA), level)
|
||||
// : UpgradeData.EMPTY;
|
||||
//#endif
|
||||
|
||||
|
||||
boolean isLightOn = tagGetBoolean(tagLevel, "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);
|
||||
#elif MC_VER < MC_1_21_4
|
||||
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);
|
||||
#else
|
||||
// do we need the ticks for what we're doing?
|
||||
LevelChunkTicks<Block> blockTicks = new LevelChunkTicks<>();
|
||||
LevelChunkTicks<Fluid> fluidTicks = new LevelChunkTicks<>();
|
||||
#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);
|
||||
#elif MC_VER < MC_1_21_3
|
||||
Registry<Biome> biomes = level.registryAccess().registryOrThrow(Registries.BIOME);
|
||||
#else
|
||||
Registry<Biome> biomes = level.registryAccess().lookupOrThrow(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));
|
||||
#elif MC_VER < MC_1_21_3
|
||||
Codec<PalettedContainer<Holder<Biome>>> biomeCodec = PalettedContainer.codecRW(
|
||||
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.getOrThrow(Biomes.PLAINS));
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int sectionYIndex = #if MC_VER < MC_1_17_1 16; #else level.getSectionsCount(); #endif
|
||||
LevelChunkSection[] chunkSections = new LevelChunkSection[sectionYIndex];
|
||||
|
||||
ListTag tagSections = tagGetListTag(chunkData, "Sections", 10);
|
||||
if (tagSections == null || tagSections.isEmpty())
|
||||
{
|
||||
tagSections = tagGetListTag(chunkData, "sections", 10);
|
||||
}
|
||||
|
||||
|
||||
if (tagSections != null)
|
||||
{
|
||||
for (int j = 0; j < tagSections.size(); ++j)
|
||||
{
|
||||
CompoundTag tagSection = tagGetCompoundTag(tagSections, j);
|
||||
if (tagSection == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
final int sectionYPos = tagGetByte(tagSection, "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
|
||||
|
||||
|
||||
boolean containsBlockStates;
|
||||
#if MC_VER < MC_1_21_5
|
||||
containsBlockStates = tagSection.contains("block_states", 10);
|
||||
#else
|
||||
containsBlockStates = tagSection.contains("block_states");
|
||||
#endif
|
||||
|
||||
if (containsBlockStates)
|
||||
{
|
||||
#if MC_VER < MC_1_20_6
|
||||
blockStateContainer = BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, tagGetCompoundTag(tagSection, "block_states"))
|
||||
.promotePartial(string -> logBlockDeserializationWarning(chunkPos, sectionYPos, string))
|
||||
.getOrThrow(false, (message) -> logParsingWarningOnce(message));
|
||||
#else
|
||||
blockStateContainer = BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, tagGetCompoundTag(tagSection, "block_states"))
|
||||
.promotePartial(string -> logBlockDeserializationWarning(chunkPos, sectionYPos, string))
|
||||
.getOrThrow((message) -> logErrorAndReturnException(message));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
blockStateContainer = 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, (message) -> logWarningOnce(message))
|
||||
: new PalettedContainer<Biome>(biomes, biomes.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES);
|
||||
#else
|
||||
|
||||
|
||||
boolean containsBiomes;
|
||||
#if MC_VER < MC_1_21_5
|
||||
containsBiomes = tagSection.contains("biomes", 10);
|
||||
#else
|
||||
containsBiomes = tagSection.contains("biomes");
|
||||
#endif
|
||||
|
||||
if (containsBiomes)
|
||||
{
|
||||
#if MC_VER < MC_1_20_6
|
||||
biomeContainer = biomeCodec.parse(NbtOps.INSTANCE, tagGetCompoundTag(tagSection, "biomes"))
|
||||
.promotePartial(string -> logBiomeDeserializationWarning(chunkPos, sectionYIndex, (String) string))
|
||||
.getOrThrow(false, (message) -> logParsingWarningOnce(message));
|
||||
#else
|
||||
biomeContainer = biomeCodec.parse(NbtOps.INSTANCE, tagGetCompoundTag(tagSection, "biomes"))
|
||||
.promotePartial(string -> logBiomeDeserializationWarning(chunkPos, sectionYIndex, (String) string))
|
||||
.getOrThrow((message) -> logErrorAndReturnException(message));
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
biomeContainer = new PalettedContainer<Holder<Biome>>(biomes.asHolderIdMap(),
|
||||
#if MC_VER < MC_1_21_3
|
||||
biomes.getHolderOrThrow(Biomes.PLAINS),
|
||||
#else
|
||||
biomes.getOrThrow(Biomes.PLAINS),
|
||||
#endif
|
||||
PalettedContainer.Strategy.SECTION_BIOMES);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if MC_VER < MC_1_20_1
|
||||
chunkSections[sectionId] = new LevelChunkSection(sectionYPos, blockStateContainer, biomeContainer);
|
||||
#else
|
||||
chunkSections[sectionId] = new LevelChunkSection(blockStateContainer, biomeContainer);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
}
|
||||
return chunkSections;
|
||||
}
|
||||
private static
|
||||
#if MC_VER < MC_1_20_6 ChunkStatus.ChunkType
|
||||
#elif MC_VER < MC_1_21_1 ChunkType
|
||||
#else ChunkType #endif
|
||||
readChunkType(CompoundTag tagLevel)
|
||||
{
|
||||
String statusString = tagGetString(tagLevel,"Status");
|
||||
if (statusString != null)
|
||||
{
|
||||
ChunkStatus chunkStatus = ChunkStatus.byName(statusString);
|
||||
if (chunkStatus != null)
|
||||
{
|
||||
return chunkStatus.getChunkType();
|
||||
}
|
||||
}
|
||||
|
||||
#if MC_VER <= MC_1_20_4
|
||||
return ChunkStatus.ChunkType.PROTOCHUNK;
|
||||
#else
|
||||
return ChunkType.PROTOCHUNK;
|
||||
#endif
|
||||
}
|
||||
private static void readHeightmaps(LevelChunk chunk, CompoundTag chunkData)
|
||||
{
|
||||
CompoundTag tagHeightmaps = tagGetCompoundTag(chunkData, "Heightmaps");
|
||||
if (tagHeightmaps != null)
|
||||
{
|
||||
for (Heightmap.Types type : ChunkStatus.FULL.heightmapsAfter())
|
||||
{
|
||||
String heightmap = type.getSerializationKey();
|
||||
#if MC_VER < MC_1_21_5
|
||||
if (tagHeightmaps.contains(heightmap, 12))
|
||||
{
|
||||
chunk.setHeightmap(type, tagHeightmaps.getLongArray(heightmap));
|
||||
}
|
||||
#else
|
||||
if (tagHeightmaps.contains(heightmap))
|
||||
{
|
||||
Optional<long[]> optionalHeightmap = tagHeightmaps.getLongArray(heightmap);
|
||||
if (optionalHeightmap.isPresent())
|
||||
{
|
||||
chunk.setHeightmap(type, optionalHeightmap.get());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
Heightmap.primeHeightmaps(chunk, ChunkStatus.FULL.heightmapsAfter());
|
||||
}
|
||||
}
|
||||
// commented out as a test as of 2025-06-04 to see if this is actually necessary for DH
|
||||
// DH probably doesn't need any chunk post-processing data
|
||||
//private static void readPostPocessings(LevelChunk chunk, CompoundTag chunkData)
|
||||
//{
|
||||
// ListTag tagPostProcessings = tagGetListTag(chunkData,"PostProcessing", 9);
|
||||
// if (tagPostProcessings != null)
|
||||
// {
|
||||
// for (int i = 0; i < tagPostProcessings.size(); ++i)
|
||||
// {
|
||||
// ListTag listTag3 = tagGetListTag(tagPostProcessings, i);
|
||||
// for (int j = 0; j < listTag3.size(); ++j)
|
||||
// {
|
||||
// #if MC_VER < MC_1_21_3
|
||||
// chunk.addPackedPostProcess(listTag3.getShort(j), i);
|
||||
// #else
|
||||
// chunk.addPackedPostProcess(ShortList.of(tagGetShort(listTag3, j)), i);
|
||||
// #endif
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
#if MC_VER >= MC_1_18_2
|
||||
private static BlendingData readBlendingData(CompoundTag chunkData)
|
||||
{
|
||||
BlendingData blendingData = null;
|
||||
|
||||
|
||||
boolean containsBlendingData;
|
||||
#if MC_VER < MC_1_21_5
|
||||
containsBlendingData = chunkData.contains("blending_data", 10);
|
||||
#else
|
||||
containsBlendingData = chunkData.contains("blending_data");
|
||||
#endif
|
||||
|
||||
if (containsBlendingData)
|
||||
{
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
Dynamic<CompoundTag> blendingDataTag = new Dynamic(NbtOps.INSTANCE, chunkData.getCompound("blending_data"));
|
||||
|
||||
try
|
||||
{
|
||||
#if MC_VER < MC_1_21_3
|
||||
blendingData = BlendingData.CODEC.parse(blendingDataTag).resultOrPartial((message) -> logParsingWarningOnce(message)).orElse(null);
|
||||
#else
|
||||
// blending data appears to have changed as of 1.21.6 causing a class cast exception here due to it being wrapped in a Java.Optional
|
||||
blendingData = BlendingData.unpack(BlendingData.Packed.CODEC.parse(blendingDataTag).resultOrPartial((message) -> logParsingWarningOnce(message)).orElse(null));
|
||||
#endif
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
String message = e.getMessage();
|
||||
if (message == null || message.trim().isEmpty())
|
||||
{
|
||||
message = "Failed to parse blending data";
|
||||
}
|
||||
|
||||
logParsingWarningOnce(message, e);
|
||||
}
|
||||
}
|
||||
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.getInclusiveMinBuildHeight(chunk), ChunkWrapper.getExclusiveMaxBuildHeight(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 = tagGetByteArray(chunkSectionCompoundTag, "BlockLight");
|
||||
byte[] skyLightNibbleArray = tagGetByteArray(chunkSectionCompoundTag, "SkyLight");
|
||||
|
||||
if (blockLightNibbleArray != null
|
||||
&& skyLightNibbleArray != null)
|
||||
{
|
||||
// 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.getInclusiveMinBuildHeight(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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//=========//
|
||||
// logging //
|
||||
//=========//
|
||||
|
||||
private static void logBlockDeserializationWarning(ChunkPos chunkPos, int sectionYIndex, String message)
|
||||
{
|
||||
LOGGED_ERROR_MESSAGE_MAP.computeIfAbsent(message, (newMessage) ->
|
||||
{
|
||||
LOGGER.warn("Unable to deserialize blocks for chunk section [" + chunkPos.x + ", " + sectionYIndex + ", " + chunkPos.z + "], error: ["+newMessage+"]. " +
|
||||
"This can probably be ignored, although if your world looks wrong, optimizing it via the single player menu then deleting your DH database(s) should fix the problem.");
|
||||
|
||||
return newMessage;
|
||||
});
|
||||
}
|
||||
private static void logBiomeDeserializationWarning(ChunkPos chunkPos, int sectionYIndex, String message)
|
||||
{
|
||||
LOGGED_ERROR_MESSAGE_MAP.computeIfAbsent(message, (newMessage) ->
|
||||
{
|
||||
LOGGER.warn("Unable to deserialize biomes for chunk section [" + chunkPos.x + ", " + sectionYIndex + ", " + chunkPos.z + "], error: ["+newMessage+"]. " +
|
||||
"This can probably be ignored, although if your world looks wrong, optimizing it via the single player menu then deleting your DH database(s) should fix the problem.");
|
||||
|
||||
return newMessage;
|
||||
});
|
||||
}
|
||||
|
||||
private static void logParsingWarningOnce(String message) { logParsingWarningOnce(message, null); }
|
||||
private static void logParsingWarningOnce(String message, Exception e)
|
||||
{
|
||||
if (message == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
LOGGED_ERROR_MESSAGE_MAP.computeIfAbsent(message, (newMessage) ->
|
||||
{
|
||||
LOGGER.warn("Parsing error: ["+newMessage+"]. " +
|
||||
"This can probably be ignored, although if your world looks wrong, optimizing it via the single player menu then deleting your DH database(s) should fix the problem.",
|
||||
e);
|
||||
|
||||
return newMessage;
|
||||
});
|
||||
}
|
||||
|
||||
private static RuntimeException logErrorAndReturnException(String message)
|
||||
{
|
||||
LOGGED_ERROR_MESSAGE_MAP.computeIfAbsent(message, (newMessage) ->
|
||||
{
|
||||
LOGGER.warn("Parsing error: ["+newMessage+"]. " +
|
||||
"This can probably be ignored, although if your world looks wrong, optimizing it via the single player menu then deleting your DH database(s) should fix the problem.");
|
||||
|
||||
return newMessage;
|
||||
});
|
||||
|
||||
// Currently we want to ignore these errors, if returning null is a problem, we can change this later
|
||||
return null; //new RuntimeException(message);
|
||||
}
|
||||
|
||||
|
||||
|
||||
//====================//
|
||||
// tag helper methods //
|
||||
//====================//
|
||||
|
||||
// TODO move into separate file (this file is getting long)
|
||||
// these tag helpers are to simplify tag accessing between MC versions
|
||||
|
||||
/** defaults to "false" if the tag isn't present */
|
||||
private static boolean tagGetBoolean(CompoundTag tag, String key)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return tag.getBoolean(key);
|
||||
#else
|
||||
return tag.getBoolean(key).orElse(false);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** defaults to "0" if the tag isn't present */
|
||||
private static byte tagGetByte(CompoundTag tag, String key)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return tag.getByte(key);
|
||||
#else
|
||||
return tag.getByte(key).orElse((byte)0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** defaults to "0" if the tag isn't present */
|
||||
private static short tagGetShort(ListTag tag, int index)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return tag.getShort(index);
|
||||
#else
|
||||
return tag.getShort(index).orElse((short)0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** defaults to "0" if the tag isn't present */
|
||||
private static int tagGetInt(CompoundTag tag, String key)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return tag.getInt(key);
|
||||
#else
|
||||
return tag.getInt(key).orElse(0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** defaults to "0" if the tag isn't present */
|
||||
private static long tagGetLong(CompoundTag tag, String key)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return tag.getInt(key);
|
||||
#else
|
||||
return tag.getLong(key).orElse(0L);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** defaults to null if the tag isn't present */
|
||||
@Nullable
|
||||
private static String tagGetString(CompoundTag tag, String key)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return tag.getString(key);
|
||||
#else
|
||||
return tag.getString(key).orElse(null);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** defaults to null if the tag isn't present */
|
||||
@Nullable
|
||||
private static byte[] tagGetByteArray(CompoundTag tag, String key)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return tag.getByteArray(key);
|
||||
#else
|
||||
return tag.getByteArray(key).orElse(null);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** defaults to null if the tag isn't present */
|
||||
@Nullable
|
||||
private static CompoundTag tagGetCompoundTag(CompoundTag tag, String key)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return tag.getCompound(key);
|
||||
#else
|
||||
return tag.getCompound(key).orElse(null);
|
||||
#endif
|
||||
}
|
||||
/** defaults to null if the tag isn't present */
|
||||
@Nullable
|
||||
private static CompoundTag tagGetCompoundTag(ListTag tag, int index)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return tag.getCompound(index);
|
||||
#else
|
||||
return tag.getCompound(index).orElse(null);
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
* defaults to null if the tag isn't present
|
||||
* @param elementType unused after MC 1.21.5
|
||||
*/
|
||||
@Nullable
|
||||
private static ListTag tagGetListTag(CompoundTag tag, String key, int elementType)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return tag.getList(key, elementType);
|
||||
#else
|
||||
return tag.getList(key).orElse(null);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** defaults to null if the tag isn't present */
|
||||
@Nullable
|
||||
private static ListTag tagGetListTag(ListTag tag, int index)
|
||||
{
|
||||
#if MC_VER < MC_1_21_5
|
||||
return tag.getList(index);
|
||||
#else
|
||||
return tag.getList(index).orElse(null);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
//================//
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||