diff --git a/divinemc-server/minecraft-patches/features/0057-Leaves-Protocol-Core.patch b/divinemc-server/minecraft-patches/features/0056-Leaves-Protocol-Core.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0057-Leaves-Protocol-Core.patch rename to divinemc-server/minecraft-patches/features/0056-Leaves-Protocol-Core.patch diff --git a/divinemc-server/minecraft-patches/features/0058-Paper-PR-Optimise-non-flush-packet-sending.patch b/divinemc-server/minecraft-patches/features/0057-Paper-PR-Optimise-non-flush-packet-sending.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0058-Paper-PR-Optimise-non-flush-packet-sending.patch rename to divinemc-server/minecraft-patches/features/0057-Paper-PR-Optimise-non-flush-packet-sending.patch diff --git a/divinemc-server/minecraft-patches/features/0059-Linear-region-file-format.patch b/divinemc-server/minecraft-patches/features/0058-Linear-region-file-format.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0059-Linear-region-file-format.patch rename to divinemc-server/minecraft-patches/features/0058-Linear-region-file-format.patch diff --git a/divinemc-server/minecraft-patches/features/0060-Cleanup-dead-code-from-Paper.patch b/divinemc-server/minecraft-patches/features/0059-Cleanup-dead-code-from-Paper.patch similarity index 98% rename from divinemc-server/minecraft-patches/features/0060-Cleanup-dead-code-from-Paper.patch rename to divinemc-server/minecraft-patches/features/0059-Cleanup-dead-code-from-Paper.patch index f2ec4c6..c44ee4a 100644 --- a/divinemc-server/minecraft-patches/features/0060-Cleanup-dead-code-from-Paper.patch +++ b/divinemc-server/minecraft-patches/features/0059-Cleanup-dead-code-from-Paper.patch @@ -102,7 +102,7 @@ index eb2ed61faac0d4803298325dc5aeec3c6b0a1ad2..92521490b6ddc0ff4a102d870f5826f1 private void tickPassenger(Entity ridingEntity, Entity passengerEntity, final boolean isActive) { // Paper - EAR 2 diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index 5893372688c9355759602645577cdbab7e6e3716..e18f4d60e94054f7f7ebbd066ff3ae45ce441507 100644 +index 65a72cedfd3f3da0323b553afe0e9a515d4f3986..36acef56faf73bd9c0afa987775c6f7bebfc66e1 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java @@ -1131,29 +1131,10 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name diff --git a/divinemc-server/minecraft-patches/features/0061-C2ME-The-End-Biome-Cache.patch b/divinemc-server/minecraft-patches/features/0060-C2ME-The-End-Biome-Cache.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0061-C2ME-The-End-Biome-Cache.patch rename to divinemc-server/minecraft-patches/features/0060-C2ME-The-End-Biome-Cache.patch diff --git a/divinemc-server/minecraft-patches/features/0062-Euclidean-distance-squared-option.patch b/divinemc-server/minecraft-patches/features/0061-Euclidean-distance-squared-option.patch similarity index 95% rename from divinemc-server/minecraft-patches/features/0062-Euclidean-distance-squared-option.patch rename to divinemc-server/minecraft-patches/features/0061-Euclidean-distance-squared-option.patch index 688a1e4..a8b0e39 100644 --- a/divinemc-server/minecraft-patches/features/0062-Euclidean-distance-squared-option.patch +++ b/divinemc-server/minecraft-patches/features/0061-Euclidean-distance-squared-option.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Euclidean distance squared option diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java -index 646bd06468bdd7a7ebc5ecc7e876617ad0fc6c05..87b4ccc200e090a8c5149b3bc5ae457932b8e15d 100644 +index cc0a7819dd4209141f36668a8ebf51f6db3b0cf4..db365a399b6e51f67105ecbb3e2f82d19d10a3fb 100644 --- a/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java +++ b/ca/spottedleaf/moonrise/patches/chunk_system/player/RegionizedPlayerChunkLoader.java @@ -387,10 +387,19 @@ public final class RegionizedPlayerChunkLoader { diff --git a/divinemc-server/minecraft-patches/features/0063-Do-not-send-spectator-change-packet.patch b/divinemc-server/minecraft-patches/features/0062-Do-not-send-spectator-change-packet.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0063-Do-not-send-spectator-change-packet.patch rename to divinemc-server/minecraft-patches/features/0062-Do-not-send-spectator-change-packet.patch diff --git a/divinemc-server/minecraft-patches/features/0064-Paper-PR-Fire-ServerListPingEvent-for-secondary-motd.patch b/divinemc-server/minecraft-patches/features/0063-Paper-PR-Fire-ServerListPingEvent-for-secondary-motd.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0064-Paper-PR-Fire-ServerListPingEvent-for-secondary-motd.patch rename to divinemc-server/minecraft-patches/features/0063-Paper-PR-Fire-ServerListPingEvent-for-secondary-motd.patch diff --git a/divinemc-server/minecraft-patches/features/0065-Configurable-player-spawn-tracking-range.patch b/divinemc-server/minecraft-patches/features/0064-Configurable-player-spawn-tracking-range.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0065-Configurable-player-spawn-tracking-range.patch rename to divinemc-server/minecraft-patches/features/0064-Configurable-player-spawn-tracking-range.patch diff --git a/divinemc-server/minecraft-patches/features/0066-Optimize-collections.patch b/divinemc-server/minecraft-patches/features/0065-Optimize-collections.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0066-Optimize-collections.patch rename to divinemc-server/minecraft-patches/features/0065-Optimize-collections.patch diff --git a/divinemc-server/minecraft-patches/features/0067-Optimize-level-ticking.patch b/divinemc-server/minecraft-patches/features/0066-Optimize-level-ticking.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0067-Optimize-level-ticking.patch rename to divinemc-server/minecraft-patches/features/0066-Optimize-level-ticking.patch diff --git a/divinemc-server/minecraft-patches/features/0068-Optimize-Moonrise.patch b/divinemc-server/minecraft-patches/features/0067-Optimize-Moonrise.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0068-Optimize-Moonrise.patch rename to divinemc-server/minecraft-patches/features/0067-Optimize-Moonrise.patch diff --git a/divinemc-server/minecraft-patches/features/0069-lithium-combined_heightmap_update.patch b/divinemc-server/minecraft-patches/features/0068-lithium-combined_heightmap_update.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0069-lithium-combined_heightmap_update.patch rename to divinemc-server/minecraft-patches/features/0068-lithium-combined_heightmap_update.patch diff --git a/divinemc-server/minecraft-patches/features/0070-Entity-Status-Lock.patch b/divinemc-server/minecraft-patches/features/0069-Entity-Status-Lock.patch similarity index 98% rename from divinemc-server/minecraft-patches/features/0070-Entity-Status-Lock.patch rename to divinemc-server/minecraft-patches/features/0069-Entity-Status-Lock.patch index 81bf6b8..08d9d41 100644 --- a/divinemc-server/minecraft-patches/features/0070-Entity-Status-Lock.patch +++ b/divinemc-server/minecraft-patches/features/0069-Entity-Status-Lock.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Entity Status Lock diff --git a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java -index b2bcfb3557a0326fd7ec1059f95d6da4568dfd80..5b3e8951c619cc2af023d13c2067b8d3df9e76e3 100644 +index 2dfd412344a0e57f25a08d9c65656a13113baa4e..e58e29524e1ad70b6e33fb866178157c5cec61d3 100644 --- a/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java +++ b/ca/spottedleaf/moonrise/patches/chunk_system/level/entity/ChunkEntitySlices.java @@ -225,8 +225,10 @@ public final class ChunkEntitySlices { diff --git a/divinemc-server/minecraft-patches/features/0071-lithium-sleeping_block_entity.patch b/divinemc-server/minecraft-patches/features/0070-lithium-sleeping_block_entity.patch similarity index 99% rename from divinemc-server/minecraft-patches/features/0071-lithium-sleeping_block_entity.patch rename to divinemc-server/minecraft-patches/features/0070-lithium-sleeping_block_entity.patch index f11aaf2..633f0b2 100644 --- a/divinemc-server/minecraft-patches/features/0071-lithium-sleeping_block_entity.patch +++ b/divinemc-server/minecraft-patches/features/0070-lithium-sleeping_block_entity.patch @@ -96,7 +96,7 @@ index 6489b47810b0431c350098d574469bbe0adcd726..9e67466397fe5cd903154e89e00e9a8a int getContainerSize(); diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java -index e18f4d60e94054f7f7ebbd066ff3ae45ce441507..9f463bfa228d791eede8d1131749dd08aebe786a 100644 +index 36acef56faf73bd9c0afa987775c6f7bebfc66e1..f7ca136af6f75e6be362c0f797970b447f1dbe89 100644 --- a/net/minecraft/world/entity/Entity.java +++ b/net/minecraft/world/entity/Entity.java @@ -5127,6 +5127,18 @@ public abstract class Entity implements SyncedDataHolder, DebugValueSource, Name diff --git a/divinemc-server/minecraft-patches/features/0072-lithium-equipment_tracking.patch b/divinemc-server/minecraft-patches/features/0071-lithium-equipment_tracking.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0072-lithium-equipment_tracking.patch rename to divinemc-server/minecraft-patches/features/0071-lithium-equipment_tracking.patch diff --git a/divinemc-server/minecraft-patches/features/0073-Configurable-Files-Locations.patch b/divinemc-server/minecraft-patches/features/0072-Configurable-Files-Locations.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0073-Configurable-Files-Locations.patch rename to divinemc-server/minecraft-patches/features/0072-Configurable-Files-Locations.patch diff --git a/divinemc-server/minecraft-patches/features/0074-Pufferfish-Cache-climbing-check-for-activation.patch b/divinemc-server/minecraft-patches/features/0073-Pufferfish-Cache-climbing-check-for-activation.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0074-Pufferfish-Cache-climbing-check-for-activation.patch rename to divinemc-server/minecraft-patches/features/0073-Pufferfish-Cache-climbing-check-for-activation.patch diff --git a/divinemc-server/minecraft-patches/features/0075-Pufferfish-Make-EntityCollisionContext-a-live-repres.patch b/divinemc-server/minecraft-patches/features/0074-Pufferfish-Make-EntityCollisionContext-a-live-repres.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0075-Pufferfish-Make-EntityCollisionContext-a-live-repres.patch rename to divinemc-server/minecraft-patches/features/0074-Pufferfish-Make-EntityCollisionContext-a-live-repres.patch diff --git a/divinemc-server/minecraft-patches/features/0076-Pufferfish-Better-checking-for-useless-move-packets.patch b/divinemc-server/minecraft-patches/features/0075-Pufferfish-Better-checking-for-useless-move-packets.patch similarity index 100% rename from divinemc-server/minecraft-patches/features/0076-Pufferfish-Better-checking-for-useless-move-packets.patch rename to divinemc-server/minecraft-patches/features/0075-Pufferfish-Better-checking-for-useless-move-packets.patch diff --git a/divinemc-server/paper-patches/features/0001-Rebrand.patch b/divinemc-server/paper-patches/features/0001-Rebrand.patch index 0c9253a..f9b0708 100644 --- a/divinemc-server/paper-patches/features/0001-Rebrand.patch +++ b/divinemc-server/paper-patches/features/0001-Rebrand.patch @@ -247,311 +247,326 @@ diff --git a/src/main/resources/logo.png b/src/main/resources/logo.png index 518591dd83289e041a16e2c2e7d7e7640d4b2e1b..f54753531b3bf2e8b5377f342465e727c7da98f2 100644 GIT binary patch literal 6677 -zcmZ`ecT^MIvk65y(vr|S0wD$n1T=z3m0m+wF=$9cr3j%}P!W;dMd>0)Cy6mZP(Xpu -z`KXEn5Jf2hLO#R>ih{iOJMX-A-XCxG+?_jjX7=vRopyIq-Cd813CjzEKp-&(dmB#> -z2#omK1bMk5u9dOJxq$DSrHds9#LO1i@#p8_sw8_)7Z51s00J|A35u(#^8|4ULRXr{u5ar-vE3hmqE3r=>bw!l> -zCLnNFgew+2R&lAAi)cmJ0#RrDqXICbhyX4Cp$t%{gN6nNQN~z96O4fg24$*eV1O|& -z`24~m`2Pr82s;ya_R9Y+a5FP`iYwq7063g=aRI@(eL)aESPJx4yI}4K0?UK`s+8LU -zIf51br|${Y`EMQ`5Qs-kkkt%z@DqvQS0OciO<6(B~X-Ttj8^Ly;I -zo6TV6_jdf1w>dz}4f>(bF>w9Nl+(tmyuNjboV5a{jFW#sdhZ3z{C6FC!V#*o?@AZ* -z6@#2M7W4S(D=_e$&8q=XmdM!qgOR%?ntYTjPFBys6aK5aZOW9A-@mVhM4$Tn#+hCB -zNpgxYSKw4B-@=Ml8HJRuwG70o3_~8YcHFp3NRQPixJk)8jWlBG`$)0fR?<9ouc(Iq -z@M>AWUQmUPC;T+To4^Nb6>2S#hFq7L&p%!1Cs%tkSst0NNYZm;6BFuVg$q)J!)F7( -z%(e_;?{knc?~C+ODT}S?y_c3y-kj+)Wgt5{`{U-T!|fUc+rlYhRs);U0u{fq@D7>$ -z_>Lp=enScNrA5b3pV^mFIh4g1^)G(S4aMb`J2kRvHwN--6UVxbA8uFjF<}pE*7ZMK -zD7IlonkOy3AIJvqJ+^v3B{iHk+09aQ#>kl{ -zmaISJQBQP8%5~(PD4NTU;H% -zN4-1eLAj|t8F9I*tOJKM3*6eu_ik{zyQXVr`+F=q1YAwrdHH=#%BbwO{yyyY;)#O9 -zGoK`Ujx6-fNTj483E1!FGtYVz6zXJkTq}>qH=7wK@z<-uMz+lx_|+jFzKR&rwU*h7 -z-SX~-k+=i6A(lrB*0r`9T8GUNIhfO&-z;_$ZArSIsvPp?xN$s|$dHe^`OM^F>B%4e -z+B+^26JapEmg)E{;0#))&Eg{uHb-Q`84A;T-g<0_D1txOzm@fAkH7Bi)a>I9KNL*w -z8u{ixFO8tyq?{r4KmQm -zSNiE?)c%L{xJxhP4&5oKhr-|T5c1%mU!3b24|v+PPTx7XiKE<3_og)W8hwd4bQ{h> -zw@BZ$Vn;F^AsxsUQYH4)WS37yHJ(jv^McSfJ!KYWI{j#p^1Z|(l4aXFHm%b)_D;p6 -zeK-F2{zQ2YFT{AfE%kmcleZA9 -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 -zKQC*8IZKJ85gXf`D@XmrZ}z0B4$-% -z#5u_aJlT~Rz#nDlIJ6PugYP20>(80*@KTjt2Lvz5mZ0M7$)CcUk@p_s$^h?o_rF$>!zEoV+I-e)}5CY2o9PEjay* -zV>Cj8ZChL}gx7qpb>?}aNx}GS69W2l#$e=$@mq@2rNQ3ZaqlTtH2F0b9YVEg_&cmp -z9vx$cf7u~q1PkZir56Xw60;6fM=X)hnQ`bvgB}QZiFos!aZPc!EHRvJhPYeZiG3_? -zjZbnKVSm#-9*)S}?Zz7Ix5mdiDb3_8pG#x{I61G8qoRfu1(?S9zqVOT5UPa0RFVoy -zxGZG6EN57Ym|95?5w#v3susU+2$|LdW!O*>lhl?!cqW?wb$~FN*e&rbyxv*?dCe5X -zA3X1$($YNfAX74Uu7Tv&Y0zVaUwg5SyFa7>J}6Pc<8{{Dz36a2cWZ@ziU|3oYtGnA -znJD06B5HU9wr-RKbRVXY{N@dMhVhN*V%+a3VjRb0wX;hVazYu=%el;UduXEp%w^7< -zb|+!8yUq+Ya!HO6tIB5eqD~poR2H$D+@pe77pwERgEIA -z0!|y>AQ6FFu;Cr?4;OGC36S8`-RHRs!ojv|9~nbh^^c7~^@OJH?SB5}xeQZzNnGTp -zU${G$vNFg^JlLjxT2*m!{P!2zieBFsmDoj7By5jYgbdVWx_kcpnE-OIb+w^e5#s*~ -DA-Nv< +zcmeAS@N?(olHy`uVBq!ia0y~yVAKI&4rT@h2EWC1?hFhJEa{HEjtmSN`?>!lvNA9* +zC?tCX`7$t6sWC7#v@kIIVqjosc)`F>YQVtoDuIE)Y6b&?c)^@qfi?^b46y+|A+8Jz +z4AzE*1{#{~F76Sb5mpvfPWDb-4o==4-paCa1{xY-Lc;2bN^+7?DspmG=2rST`W|i` +z=BDO)>Kgib`Z`)VdK#K$#%3zYDt1+tPBi3T(HkZ(U6;;l9^VC +zTSH@S`*j8ehN#pC&op0O1}z2#1`Y;RMj-}J=rS@eGB7YoF@S=Uk%581i%}ZR4r0`R +zs$pVaU=oJ1L8=(Qzyst71_lN&Eg$sVgn>cA)YHW=q~g}wyDyzqTL~~ccwP48O4Nnm +zH%YbsukT6qoMAe%CE%4&{gx>~pEwm~viy0!|Nf6&d13SC5moa0Jnryp{8CrbxPx)y +zmwhpncP2zs)vvS2JI}cC)^+dqm!}?kD=^{Jbnl*M5Y>G&S7qA0{n}hb3U}|#eLPJj +z%lrM~sVplOS!o^lTAf=}Pc+G&5nZ@ze|<$lcb&%c##O!Xdd64v!-cN;Kko|q +zTd7d^J$UD%kX!|=OD#VPW6ZQpxJoa#Z#(VxbVtVa=f?|{25xnF1d*Q{{9zVFI(}8GFZ@uogp}^Jh$6k5icQ0O_u$t^4QDNUcK +zb;MQshoG|0*Q+~(R+#ABDmfsLxN7~8(%EjRnHLkx3|B9=uiwWcKG!+4rE5;<#?2pA +z{=c)e_~OmVqbnHv*VNTZ*;k*9DY=&(xT;b8T2aNJ`TN84Y%;%nn-;psf66OOH`m|i +z`*RqVCjGhi<$;j#{NMU)Azx-)nckZ6P9WU+(a~E19bI|}Azw0j(}JhZ(CFJ=v!E$v +zhmCq-Ujvp;P&u_}o^`NVCqPW9Q<$A_f?EcL?F!cHFutP1g4epqZpNFTTEgdNj% +z@HUz{Cg&>1<@|FuX$nc&AXU=1+w8^M=~~tMDe5RqyFPu~yevtsJGM{;#Tb +z{Je8gU((FiOtr@ZLbr2gvYvhHwNBnLe98HUCT+K`E_#_xQNr6RjQH2C3@g7VX)$^B +zN-?cFObJu9@;>^k*rFEXy6eW|=&xa`CU%Fe+HutQW0A!~tplbzg{L@OE#BxQx?k^t +z&}@&T1-|c$mj!Lz`;bHI_L2GaDFpFiBZ_L9tS0^ugd7!N6$um~HJ&YcyPoe}@?XQ377r07#oBR`D9&d@29XU-~HFm1s +zWcc0Hek1(P(vLF7qt@oVl=La*4BRTHrESeSwQ;V9-p>!*K^Kh`{J!QK`V{k6{pCA_ +zRRZFxA22^o2-EwU!yDwN$30ba_2WbHm$6$dy0jzWvZ7H=#zU^~JV&kLsf#xyuMNxL +z-lDQa`P9yc&ma7ClA>xBG_4a@w&>(dfl#h%RdbK2_FdXAtwbn%PS?7lX3xK!@%#E| +zQtQ-1OZl=k`nAtI?Z$dtWTn9LMlI>nr$l9#Q~nwYPoH~g?b@K9wkCnT2R0Qf<)7)c +z^U{hVzL%t~dYN*b4!GJr`^%a~dDlIxH@#3>l6^3C!mGBtNupVsJfuknmo^QbKQ +z#%rBlZ6&$~Vs5osxlC={8dtm~N3V_HI!DmYO&86#PCfpfduwLNDxWoS9LcGLh8(-x +zCaltqUQ_fqX5+K@Zc}@&3I(o_xITG8-vQQY0i~FVmv=Xaz75|nZIhQNV|LHgQ-@5i +zurl_rtCr}!ovR@Fu1z(-_s}Y>zNLkYt9zP03UElOmYiW->9$Tqt3C93WQ6VYEYZhG +zZ^aoOD+=M8)^t^Dfu-w;qK#I1U8cRS +z=l7dvZO~f%AXV$Y(RI!%-g>V1wDDYwjQ0H3@?9pY8oNzpOI9^@Z!Pd}o*UqMFlsMX +zgqfb1&hLIVsjJNf6Hc%G8j;oiHH+h_$(rlojN0d}zLh*%$hPxQ$d>nqR^BoQWL&d- +z`=kij>#wu9rr)=Ysb<-c6EeYj8B@%|zOxCT`==hWD&D*A*3JuZb`#I+JdwJ*D8}mQ +z0nyjYe0QH(Ziw5yK1|QHadDyHOogd8Hl+Gqh$yc#E}1SF7R;0#-Lcx%u_?yqv0Imc +zsO>&;o3?jG2eW25MX2tGxw^W@uvc35P{;)D1-E`|?hTlFc-ARa{Z~rjmv?Zw&Nx-r +z8IsQwc3I@ut+1alTV|fxkvB>CTI@I9fNQa75x&OEVWo!aelS%n-5MOYX4y>6*G4fP +zS-0>`cWT`@E6r`q&z+CBGu|uoawVCbJrnV{=&1OGx^%6p9al}n51e`?WF+)osJZT+ +z{@J&#D`l?z{w)(>-8c2=(Gk6H{W7p{CVdY7-~0+Ccmr<2jG3$+G?8$2JwO +zeR+Z{d)cLbMV70UJ&ZWMxZ$eF=cLG;*It`0niTc5IIwWd5IVKtYLP78%9y$~zb)Oq +z%62>p17)R^ucZaEtbVQ(Aur$VtR+6&4PE6kE6DE=^@o;{VX+dp`%Z_u}r(zEEayYL0 +zR;m_yc4G{)ZP(MZKA$76cIZSHT~~a$j`zD&cUR)ouTM9gi!sybeEnzM&vm>%teU$L +zu6{L&u+|oP{_39T-K~zwGr1D4Zf&?4BPn)v8Q=S2orN>IoMt?fU&s_us+(YXRwv?} +z){NHHoqwd9_^V|XJ&G{Y>OZ4-+OJPM%bLJ14+*lx}O>? +zF;3k2G%bQ%`PzxrTWg*8tJel5>Trj)AAMD3vP0_dtVyL0BHEh;Uq5y}&=j+evFuPt +z-KIC*T302zw@Oahuxwd|McDD98?^ea7H^ajJZ{Cf?rd9fhzU9dlX@^ +z`to}H1WUb+r#p82RgWlJe#B+-HD|!EZH#)Y^RSb>ARA7W#cU-jgXlUcm2CUlMXl?vnsy1;nsAK +z*NcTVSm`mY)^BhUJv!;0L|xJvqs7)z)2??VHk#Uqy-eCIYB^22!AbPsDrd%xUc9X@ +zBa(NUG#%aHF~2aUK~N|Esz%7U!%KSv!(yd3p6Zp}bdLMgH;IiL;xCQ0BL2y=MED-w +zcqhOm>W7TqLC3HQ+9Df{{o7Jtd*rNs-_xBcI`P|`*VG=~ct;>yF6{D|meyj^eNTec +zxgB7NS-`t2;inn%5hm784<{X|jJT`D5!R{czQukov+DFBQ@1sJ-HCfSB3`WbU-4-} +zTd%^JT_^tNn1(*SJ@?A7j?!mF2@```1D+=QJj<}=UGL3}QR|#_Ox9?1eckpvqT<;h +zg#*=d+IbO#e +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 literal 9260 -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 -z<wCdy-3tTl}j4kzaCmrni9Diizn#a{@0 -zu;<>ZBofe$`#ML)Z*Aj8mbPS3-(VgSdF3LA8LJgBPj{3IaB~uLBuylKO*>ev*i|tuS(Wff3`Ogj^{GsE -zb-&NcY_)d|4#vv+AW}skSWrN{p$KOp?oug)BPoM*O}*h=wrr-PGYCt{qwP-&I!~hn -z&+*{EI5^09slk8i%kFcTjCcO6Oc}M9iiS}cuLLw0fyMPfjZ_M`;HWDHP^ke=f*5^! -z(0!2p!N9nZ8J+AP5sfunmbw64l@2)3@53_`Q@g&4FYKeDLbz2F-Pl@Er#INAtM()n -z<;MFT;osC}L2=Y4P1?cm)V{7nauSgh -zx4)k@#lLT}(uM?{Z&NvzT8pnJk@-MDvv4wOKsY+l9S8OdOw}cex#$t*B6ppAEloQy -z8u`9L`Ky$*$*G}A=)h6BjVn=_YuPie5epXe0vLKZP=Pxps%a&uGrdg4y#R{YobnDn -zWlMl5J;9|5ev`f`BO3Uh(yuK%@i^`+fAimq+_>*)z(;wrFdXn2nVJw1y_>PcV%p-) -zt#ZCU`}~DIE5y1BiI$qSd5XIebq(uRB-FnL#^x=bDHO-ls3({4R}-PgePOPH8ggGN -z^EAdT|N11qATWCZQ}ZY#=hum&;_xeyp*|O{VN?%jM$?&+DK=8LzLP4?U!YQ_JT0`M -z`m!W@TCB5mlr9&jJ{^cX4Ye=uf(7g!BDG1LQfZM#P5u-^$L1K~rOMk7oWI24W>ZJVoZ8!*NX>jC%2pgw@7$v*amGL8JnA`*TjN)y=JPix$ -zHom^xjfr~ZFvhO?xbJHg&jfEZgboIqN@pk*%G-#&cX5DM>_>dMo{P<(#6bOBlgEyG -zzi7pMrVsz<*TT+n%Xo*+rUVN -ztJqe<9EEg`YU)i$PQ+gn%oA5sG>b*6QUjZVf+Ju4QKWr32^B^>#t1pQ*dNT#SxuC8 -zGNJ9mH6R-92O+m#!DECXMrB|3+|cZ$?^qoag;w8-vr)Z5hx@2MVoazOwqdLo2-lu( -ziwF(a3SNH{+U_=d6KFp}-N^eInrfTZ{p%Yc;K{NXO^Sl0qy(%)%sUXL -zA6Ic}&$4}O+ulD-?|#%otX@aO$zD_RW;|WXeL`u5;iz`2Ja937zabkT*wwyB&2HIU -z%>tpNcvDWCsG=IjRr(V|Z7N`9^tphbhiC}fIrVcS>=>)uMStm;g&z-HK{fFz2ud&X -zKo;y87PhB3IZGZ&D%bJ2dZ<-Z7I$fCrPWl6O0ir})>f~+rM8k@!Q(EpWCD9f!k>me -zRhs@Q3_eZ!{s3QHUMaN0uShhn$y!N+)a -z6F#K#O21}#Wz2NGar1LUq3S|3=0~&VTjxVeqcysO1QIGwgglMcjXc3^9R9i556MW! -zA%G1+Y)mPX16RcVB#B?R~Xl -zIeR6G9EBEoU+Sk|=Q=4gQdT~j9ecG~G45m|E+IkhfuBxT`M%^wZkNkXpL0AjS!$%u -zg-={lr6QW@$p<#-f}T{y|0rAEpY~$9`Ffd=BP+`1#;?ge=@mLGkdmI~u?Dai2i+}> -zr-d}7M&xTHsK7@<3$tPd^Yg3fLzxDa!oOJ_N!hGt&$}5!9&TOIuzhIP>)^&CM1CIF -zY>A-293)fzq2lbB(1wKk=>#3=G1eTT&8(iBSJab=V@AGnDSwOhxKg{m8sa~TR||^x -zH?*-f-l|Zq;GkYEt~~O`56i(Z6gi`*^TxMZuc-f=NMlvry~%u2a>kz*@R^tJ@{7%-A@wfa)Z -z0~dL|Z*tTjEX7ED(M%2gZ|Zi_L4TWr%=BR=y4%;?-COo)8t(xaW)#f?Uhc9^d-1?K -z=UDW-cu8J#%~t1$>T7o{K5NXC7Z^ -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 -zWZQ?eQkgCCqwANoAm&K4|fw*k7ipV -zB1v2pR!seE-oV-2@pAb2ne;%k;&0+LB7z16@)VH1MO9)MHU9kSp)dCNVB91j?4mmO -zv3NP2%#IeX=+W7Ni#8IjoTpc(!3T*dt7!EX8VlAzQq6uvFcs%W{$71OuAvW8Wpseg+*PVYLv?WMN=C|H@$;E_S5fVp$L;GyupU7jZ$kfvC58X?uLqEZijH!v -HqBZh=dic2S +zcmeAS@N?(olHy`uVBq!ia0y~yU^oH79Lx+1471we)-W(I{SEL5ab;j&*zEAXF5~}E +zga0u-|5FKJPi^?W!SR1V#sAsC|8uJUhfe&z&gK7d&;R>O|DV(NKOy%25rhB6YyQs+`9DA4 +z|3%gRmz4isR{DQe>fa*2|M`{wv+6)wkRP|JySE-tqjO5%zzj`~TS?|Lqq2Kd$@#pwa(% +zK_K^^)%c&<_`fa(q-#?2|HS5hrA7aNBJ|DTBbKWy~hY5xDD=KocB|K|q%k8l5Pz4U*0FUT=Ftw17C-5?)LivHi7_e`Bnd?M*c4@1G)K< +z%Kw6LP<~1toyYy8jhL|I->k9$D%QN-E1e|Cbj3KcW3UvE_eqGbnBJ#s1%828y_a +zejqE>JN>UJ_bNd +z`hTk}DC9%?{@s=Q7ux~y;~~TU&xHS5FZ;jC0u+Nf8~@j5|Np@C|AF{F*SY_Frv2Y! +z|GzT{l;pm${STV>za{PeW6}R_c>kL(|9?~FpZ}EqvqJydEdHNf_wS|P|MG@^Zp|@8 +z3=9k#N`m}?894b^+5QP>J1X;wRB*Y=c539fqD_#g}^n4fMaf +zTwj +z#M$P{hj&}bKU_GuzAohLgIm|8M*Dw#{P5<&1x@jv-(0#bA-bp +z_CUjo4HG0)n3W!|@7LHaqA~ZtsTl{DIC{Ey4vFniS-`F4qL6m}^Bg6vFK=&)iT;a! +zHaq9s{O5npSI+xi{NUa$o5knU)3tY)>Oa46XwIA`-gl&?o2=SXoRqX^_wEk{+ow&9 +zy~ioTz_d&A@wHWa;$=$i4||{FT}ioetE9_h=VXf{(S#p|JTG)_3chnII7hQk#OigJ +zy0Amso*nN_uGN)2C+X5Rr}eVeqcApw;Na=1cWzC5{?qZn42|=3pB46T$}Hd!-0t?o +zzC&j2ze}pGr*O(FUR;=cSnH;%!^OL`at700h1_}Z;>F+JJHOq@y8h59rtf1?ZTQZV +z^gFcy*HbmO&w4t?%$h^1`|0oUzOuXTUrBYBJq}x|vT^B=i8&AQZ{K5gIChM$rC@ci +zc^AjxfV3GF7KJ%EDK4)cA6aWx`HW{#*CtEFpdxn`O64 +zsd!7XFSP8LuAx)qw>Ip0d*S=|f0r+3^rv)o*7GvH`t|GAsjBjKf3NCanIKi!AkAle?Qm}5i@1Yg7_yr$&IOQSxYBq +zYlp6yewEMchbn)+<&Sq{^t=AU +zmQ&QH#T)&)6B-t_N=y55MmVdPusctKO;yR!S=GBg=}0<=#y&~vTw)yA);%TGZ)3)? +z<$+VDZ4&xobh>k$>-)C0Hv9H_5_}hx4PZmb!XcniA^R;BqHuGdHrQ%newK` +zTg={-@xAZNgGPcOl~?=hCe50td?)jwqreVnhk3RiA|h97Y`b&lsl*MXST#A<`TkRO +zdQNz)){vm3^-%wgqnA;8FLPpr{$uvpC(_T)v#q!wwWUeMoa@%a#V*_a%sajCnc%;xZUtNjM>h7&uw}0y#O>#YSxa`W>h<^+D&K0Vu +zFV1+)dOUGowf*%YwKh#UzTg|v!nbYFH?L@D +z9G+?S$l$)L=a!lNbxS2gkv2xtX*g&zIz;Y`nB&UO8{^*sui^N!6e +zm}zn%art_k@*J1jmx>hZ4+I%657fRJImPvFW$}W-Z(F-(%zXL!_2;`;dn^Nv9!uPy +z++A}nE$CY(LsI5S#!>*k?8N=zM7id^DZ@1d*)evhwpUZ>o(7= +zsctdi=j`=PpU`6OaF$JQPteihynlYC0=GLuW;VC40OvaQ4AWcNXULSty3Ou)Ij%iH +zTizkY`GicR)|5+6e%0JIR9Lx^(^gq5tY5&r({knP$@~*CwstBC#jxE@_|wk2gy+VM +zwwncN-Z@img#-r|m!H==x8M?o@>v<4D!B)XuVzIr;&i;;nDAdv&)m3D{QZpz@he|i +z4`%lkzF5V*S&X&z-QtR?O$zO&826pM(syCEudi<%+xn(xj-Ux?@BV+7;_vO=W_9^Wi%c8;gYJ+p&7?^C +zh@@G;Z%#hfwR>~o)FMZ}rE5FZIp=3_EL?5m8vo(I$kbb +zw{G#`WNCYj(!h?O9u;QR_Fl`?d_6sk?hJp~4ti!iIiO+~vGUNrX4QAUliL);YKx9` +zgvHb>(os{F*X?m%eng+U6gD@ZTC%|mb_T>u5w+e0<*$_z&myfNz2zCntzXx=a)9i%w(S1 +z{Tb1$wijmv@3$=9w)@r{hOWf0pP4TN+4hLD%zV7sET;d$+B2Fh54SIToXO75q0{CP +z=I}F*FIV&Yp-7o0Q{tycn7H4O_!juteI1)+LAY*4y~WQzchVkNedl1lx0&sCc;O-2 +zCo4REaGaeO5Z$f7dF?mDkyde*>QzieR+~>9RWdtac_zQ_h~bkD7oRFmliKRG_epM> +zi=4CD|IWy#Dy(~+$5a@8YZY?aWh%Ebf$vJ&*9ViA`_GqRc{peL22Ky1T+RPMRr{+i +zNA9=m>uYr5+Y#tB-;g~>`|0VW*6i&k0T +z4~wJ!_6P`A)n@()tZH5w_NKOakCVUcrK_!{1^wlJu8}_@{4z6gJ&!Hp+`Y#x_N>}3 +zUv%-VxXQ0v{7*RkI`+uF+`47$iW7@Of6hLxobV-lx{d7*$t#hn?QE7$Z=ODz&6i+r +zF{!(5!W^$F0rnZ^C%>Ch+tO9CsDJWWi4XI(L@kr^v?zLiZ|}BQELOLLoH`F@+b(DR +z`8(fEpy21D_F99|a{KR$py>+&}TNm&qR4jJPP;<4L-?4~!D(jxff%&tV4Q{LxN_AMsvC@Cvl?N$* +z)j$1wr@+0Xi@j;fw`Cpi=hyGgZn>Iqdv|wV%zCvaH$GRL-0f+>VO@K3hVksPOXBu4 +zgly5Nt8>>bV`96Z?CfQmxJA`tvigHxOJ<7PdiIu1FG6jL)=aecwy|IB +zk%#()R?(lY_2VYIJSv-P`Lm`@jaA`8(EknZPVDVhNa4#`!oa+3hQdW3uDgOS4+UL} +z>u{|uVPb!<)z?aYF?Tf=^Sz6wxz5>5{dtGfdwpilDSnG3@I`37yK^w$N1~yG_MzC`{}soHM_8HO{w6K +zJC4iO-}rcfXP0vAY`s*63B7uA%@AW`bimY +z16x0pZaKz(yu)t&*)YqSx$>LH+9YRvtD?Qm1l?LnG4U> +zACL_dt=``CFzBXR{jRSsb8|0vw7%l6HT(OK{eG82?a}Z@mu3`e2`h?OZ22ivY;fai +zd+{8}BCeUt*O)9W=~~21;P+utJUaR8ZoSui>he!E*c_d?b_&;w$6sXQU$8f_92T;h +zQ2*~D|0Dj;MGF_qJ-2%C8*LS-&qChC^%<{zbao{MbalkOUU-B5mt@CE^S_^0zf@2; +z?-DV|rSGIB17F;P-I5YzaiJ$3THA+hUUl#wW9^6LKc|?PuIi-+*cq&?4OMDq$WK9iO)S +zw|KM@5=(jd@5OG|7}L`5CtL5t#dU@;6EiHzb2IfaxH~y*^3NOp64>@@UDvBgkKc&2 +zeN&coIPfy8&GFyg>GDe^8?U%y$TBgjFmHm$nKe!aS6s4K-LcKMM*8$t|KI+^Y*5m4@$EceJ` +zrNOA6tju#nh~?XcrMjx&mkxYe)q5fKYO{i1*n{$op)96B44VWUX0bH>NoQCRtkGdC +zwx?2;A?W?7OU}`vwr4nm6GW$b=!mZNW9cm29MvPaCn&o_VXKovU3{bH#YbHSidc#d +zuKUv0ldCDs{;luLgoEsodu=z!iLP1t=|irIfWCNlGS8B2VG<|aYqKqC+~y^6rmpYk +z!A@Q-!w0$FwmmmJ{!&h)y5i?c!HgvdrVpHXie(sXD)Kxjuba@B$EXm+B6!gD#IM5! +zs=PTjr&)1g!>f^YAuah9&{a; +zxYRmtuFQ$&SBt8?%6BL@`!k7F&71hp+NeU>`PmC*(>ApiWihYrsxhq;X8APxrUE0& +zBOZ7CrU`E*zmSdGk*DVR^WDwVv>-Wwgo8~JEUzU-FuiX4t8mhZJxHD9$?W?-92T{# +z_2^!zy@sQQw?rZ5jHliHRkJ-W{{B|noyHdJui&1)gjd_IO;EXXp|#LY)3p*F<=ZES +zM)Ejq;>%fPxqQwYK@a|~^Wz2g-n0F>$nV9ciFOqp*D9WTtx1_%s8IgyLz53zgrGNX +zE#VlwGsz)nO3g7`$NyM&uBswOQh9g +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 +z%E>H+(#~Iu39^6niZ{|Ww56~q +z$YpnIJIK=%X4+B1GwtS7!N$o~V*XX+zs)&u&(5JFe6`dOcY*%&_GP!Ww6&!<1%b$L7G+Fg|x$!6_mNq|G;Vt&LYl417v`Bqn +zlHvrurUiKmCJ1hic5++hoMYN7bIf_2lP(M2k=o0O%jYY4EN4==d|j~N#Wl%^0#~w& +zm!EgHkUcf`@CSWA8Mg&$rks{_)=Qw@ +z-N|oNN=inDV%+;}2WnEL$XFjfs&w?~C(DN2*S$Qn9ZlAp6aB?;O}@Cbf_cKGxooQ-BbXFYi}*YwPRnv{#lH{C2Y9Q^(57{d}*MdiAVU``_=rwJbm^93b3KHfT- +zej+w-y7xZgj{=SxYL`x!*l6jz=ka6fn}I3f=^6o(l|00qH`J%{b{?p+cD}V%F-b}J +z@sS(3!s!N1_nVsg54UcU32Jd+zO;_dGtE7AoyFn8w{AVVzcVydy>-7PAhN_v(|ON5 +zE5)2Ri&IA;JEq4~h^Gozo4LIYZL|nAUi9{3)kML)8Rav5=j^?}mlz$w_^2evO-f2c +zq4eIzyN}kmtGw;Lm&57EXgf=B({gi8&uM+w9XY~x8K3b +zu9W2{P(5+F%+;-Bh3^(AOjP*Wd9!Uo8(VRQT-;f{Gw$bdYo=Vc@A>uMo9XAK1);qY +zlr;w)32R%b-4x}&GL^pxH|6}IQ6}X*{E`8-=uS?KdeqQJH6t3#KE>voVS-D +zD0X${QX$sc4?mPVNj=kcgQvy)}(K{kW6u)1>G!J8-?Hl%jjkjEJPf +z^&dV|woN*bIibpaNww9HFy-j0W*b?U)s5K%S}$IkVDw$UaYN+}6J@3L^Iw;)o6S`y +zu%uc`rTn@;(vq~5MjDH_=870j+^qP`;rWdNJ-bwIu2MT3*VMeegKKw-h0JB+Ndb?` +z4hP0+Ppi3c>A`~c4@yqR$<<|-PfUI?=e+wBCF7~@SEt@waH!Ctt>^8=;O7rYayE2+ +zR$Zk1vnqFv7{7;}^Q179+*eYgDy5PiD4>%l- +z-4Sv1&bC`5wsUHN!is*6V{M-&9(>PqL?~se-l~p`>772;p1XS9-_U(&gH>jD%)6h4 +sPuTcv7jDytWnQr+YqnZRA=~46q4sdGkFvem3=9kmp00i_>zopr0DAbi?*IS* diff --git a/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/DataProvider.java b/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/DataProvider.java deleted file mode 100644 index 8c3044f..0000000 --- a/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/DataProvider.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.logisticscraft.occlusionculling; - -import com.logisticscraft.occlusionculling.util.Vec3d; - -public interface DataProvider { - /** - * Prepares the requested chunk. Returns true if the chunk is ready, false when - * not loaded. Should not reload the chunk when the x and y are the same as the - * last request! - * - * @param chunkX - * @param chunkZ - * @return - */ - boolean prepareChunk(int chunkX, int chunkZ); - - /** - * Location is inside the chunk. - * - * @param x - * @param y - * @param z - * @return - */ - boolean isOpaqueFullCube(int x, int y, int z); - - default void cleanup() { } - - default void checkingPosition(Vec3d[] targetPoints, int size, Vec3d viewerPosition) { } -} diff --git a/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/OcclusionCullingInstance.java b/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/OcclusionCullingInstance.java deleted file mode 100644 index f5bdb2d..0000000 --- a/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/OcclusionCullingInstance.java +++ /dev/null @@ -1,513 +0,0 @@ -package com.logisticscraft.occlusionculling; - -import com.logisticscraft.occlusionculling.cache.ArrayOcclusionCache; -import com.logisticscraft.occlusionculling.cache.OcclusionCache; -import com.logisticscraft.occlusionculling.util.MathUtilities; -import com.logisticscraft.occlusionculling.util.Vec3d; - -import java.util.Arrays; -import java.util.BitSet; - -public class OcclusionCullingInstance { - private static final int ON_MIN_X = 0x01; - private static final int ON_MAX_X = 0x02; - private static final int ON_MIN_Y = 0x04; - private static final int ON_MAX_Y = 0x08; - private static final int ON_MIN_Z = 0x10; - private static final int ON_MAX_Z = 0x20; - - private final int reach; - private final double aabbExpansion; - private final DataProvider provider; - private final OcclusionCache cache; - - // Reused allocated data structures - private final BitSet skipList = new BitSet(); // Grows bigger in case some mod introduces giant hitboxes - private final Vec3d[] targetPoints = new Vec3d[15]; - private final Vec3d targetPos = new Vec3d(0, 0, 0); - private final int[] cameraPos = new int[3]; - private final boolean[] dotselectors = new boolean[14]; - private boolean allowRayChecks = false; - private final int[] lastHitBlock = new int[3]; - private boolean allowWallClipping = false; - - - public OcclusionCullingInstance(int maxDistance, DataProvider provider) { - this(maxDistance, provider, new ArrayOcclusionCache(maxDistance), 0.5); - } - - public OcclusionCullingInstance(int maxDistance, DataProvider provider, OcclusionCache cache, double aabbExpansion) { - this.reach = maxDistance; - this.provider = provider; - this.cache = cache; - this.aabbExpansion = aabbExpansion; - for(int i = 0; i < targetPoints.length; i++) { - targetPoints[i] = new Vec3d(0, 0, 0); - } - } - - public boolean isAABBVisible(Vec3d aabbMin, Vec3d aabbMax, Vec3d viewerPosition) { - try { - int maxX = MathUtilities.floor(aabbMax.x - + aabbExpansion); - int maxY = MathUtilities.floor(aabbMax.y - + aabbExpansion); - int maxZ = MathUtilities.floor(aabbMax.z - + aabbExpansion); - int minX = MathUtilities.floor(aabbMin.x - - aabbExpansion); - int minY = MathUtilities.floor(aabbMin.y - - aabbExpansion); - int minZ = MathUtilities.floor(aabbMin.z - - aabbExpansion); - - cameraPos[0] = MathUtilities.floor(viewerPosition.x); - cameraPos[1] = MathUtilities.floor(viewerPosition.y); - cameraPos[2] = MathUtilities.floor(viewerPosition.z); - - Relative relX = Relative.from(minX, maxX, cameraPos[0]); - Relative relY = Relative.from(minY, maxY, cameraPos[1]); - Relative relZ = Relative.from(minZ, maxZ, cameraPos[2]); - - if(relX == Relative.INSIDE && relY == Relative.INSIDE && relZ == Relative.INSIDE) { - return true; // We are inside of the AABB, don't cull - } - - skipList.clear(); - - // Just check the cache first - int id = 0; - for (int x = minX; x <= maxX; x++) { - for (int y = minY; y <= maxY; y++) { - for (int z = minZ; z <= maxZ; z++) { - int cachedValue = getCacheValue(x, y, z); - - if (cachedValue == 1) { - // non-occluding - return true; - } - - if (cachedValue != 0) { - // was checked and it wasn't visible - skipList.set(id); - } - id++; - } - } - } - - // only after the first hit wall the cache becomes valid. - allowRayChecks = false; - - // since the cache wasn't helpfull - id = 0; - for (int x = minX; x <= maxX; x++) { - byte visibleOnFaceX = 0; - byte faceEdgeDataX = 0; - faceEdgeDataX |= (x == minX) ? ON_MIN_X : 0; - faceEdgeDataX |= (x == maxX) ? ON_MAX_X : 0; - visibleOnFaceX |= (x == minX && relX == Relative.POSITIVE) ? ON_MIN_X : 0; - visibleOnFaceX |= (x == maxX && relX == Relative.NEGATIVE) ? ON_MAX_X : 0; - for (int y = minY; y <= maxY; y++) { - byte faceEdgeDataY = faceEdgeDataX; - byte visibleOnFaceY = visibleOnFaceX; - faceEdgeDataY |= (y == minY) ? ON_MIN_Y : 0; - faceEdgeDataY |= (y == maxY) ? ON_MAX_Y : 0; - visibleOnFaceY |= (y == minY && relY == Relative.POSITIVE) ? ON_MIN_Y : 0; - visibleOnFaceY |= (y == maxY && relY == Relative.NEGATIVE) ? ON_MAX_Y : 0; - for (int z = minZ; z <= maxZ; z++) { - byte faceEdgeData = faceEdgeDataY; - byte visibleOnFace = visibleOnFaceY; - faceEdgeData |= (z == minZ) ? ON_MIN_Z : 0; - faceEdgeData |= (z == maxZ) ? ON_MAX_Z : 0; - visibleOnFace |= (z == minZ && relZ == Relative.POSITIVE) ? ON_MIN_Z : 0; - visibleOnFace |= (z == maxZ && relZ == Relative.NEGATIVE) ? ON_MAX_Z : 0; - if(skipList.get(id)) { // was checked and it wasn't visible - id++; - continue; - } - - if (visibleOnFace != 0) { - targetPos.set(x, y, z); - if (isVoxelVisible(viewerPosition, targetPos, faceEdgeData, visibleOnFace)) { - return true; - } - } - id++; - } - } - } - - return false; - } catch (Throwable t) { - // Failsafe - t.printStackTrace(); - } - return true; - } - - /** - * @param viewerPosition - * @param position - * @param faceData contains rather this Block is on the outside for a given face - * @param visibleOnFace contains rather a face should be concidered - * @return - */ - private boolean isVoxelVisible(Vec3d viewerPosition, Vec3d position, byte faceData, byte visibleOnFace) { - int targetSize = 0; - Arrays.fill(dotselectors, false); - if((visibleOnFace & ON_MIN_X) == ON_MIN_X){ - dotselectors[0] = true; - if((faceData & ~ON_MIN_X) != 0) { - dotselectors[1] = true; - dotselectors[4] = true; - dotselectors[5] = true; - } - dotselectors[8] = true; - } - if((visibleOnFace & ON_MIN_Y) == ON_MIN_Y){ - dotselectors[0] = true; - if((faceData & ~ON_MIN_Y) != 0) { - dotselectors[3] = true; - dotselectors[4] = true; - dotselectors[7] = true; - } - dotselectors[9] = true; - } - if((visibleOnFace & ON_MIN_Z) == ON_MIN_Z){ - dotselectors[0] = true; - if((faceData & ~ON_MIN_Z) != 0) { - dotselectors[1] = true; - dotselectors[4] = true; - dotselectors[5] = true; - } - dotselectors[10] = true; - } - if((visibleOnFace & ON_MAX_X) == ON_MAX_X){ - dotselectors[4] = true; - if((faceData & ~ON_MAX_X) != 0) { - dotselectors[5] = true; - dotselectors[6] = true; - dotselectors[7] = true; - } - dotselectors[11] = true; - } - if((visibleOnFace & ON_MAX_Y) == ON_MAX_Y){ - dotselectors[1] = true; - if((faceData & ~ON_MAX_Y) != 0) { - dotselectors[2] = true; - dotselectors[5] = true; - dotselectors[6] = true; - } - dotselectors[12] = true; - } - if((visibleOnFace & ON_MAX_Z) == ON_MAX_Z){ - dotselectors[2] = true; - if((faceData & ~ON_MAX_Z) != 0) { - dotselectors[3] = true; - dotselectors[6] = true; - dotselectors[7] = true; - } - dotselectors[13] = true; - } - - if (dotselectors[0])targetPoints[targetSize++].setAdd(position, 0.05, 0.05, 0.05); - if (dotselectors[1])targetPoints[targetSize++].setAdd(position, 0.05, 0.95, 0.05); - if (dotselectors[2])targetPoints[targetSize++].setAdd(position, 0.05, 0.95, 0.95); - if (dotselectors[3])targetPoints[targetSize++].setAdd(position, 0.05, 0.05, 0.95); - if (dotselectors[4])targetPoints[targetSize++].setAdd(position, 0.95, 0.05, 0.05); - if (dotselectors[5])targetPoints[targetSize++].setAdd(position, 0.95, 0.95, 0.05); - if (dotselectors[6])targetPoints[targetSize++].setAdd(position, 0.95, 0.95, 0.95); - if (dotselectors[7])targetPoints[targetSize++].setAdd(position, 0.95, 0.05, 0.95); - // middle points - if (dotselectors[8])targetPoints[targetSize++].setAdd(position, 0.05, 0.5, 0.5); - if (dotselectors[9])targetPoints[targetSize++].setAdd(position, 0.5, 0.05, 0.5); - if (dotselectors[10])targetPoints[targetSize++].setAdd(position, 0.5, 0.5, 0.05); - if (dotselectors[11])targetPoints[targetSize++].setAdd(position, 0.95, 0.5, 0.5); - if (dotselectors[12])targetPoints[targetSize++].setAdd(position, 0.5, 0.95, 0.5); - if (dotselectors[13])targetPoints[targetSize++].setAdd(position, 0.5, 0.5, 0.95); - - return isVisible(viewerPosition, targetPoints, targetSize); - } - - private boolean rayIntersection(int[] b, Vec3d rayOrigin, Vec3d rayDir) { - Vec3d rInv = new Vec3d(1, 1, 1).div(rayDir); - - double t1 = (b[0] - rayOrigin.x) * rInv.x; - double t2 = (b[0] + 1 - rayOrigin.x) * rInv.x; - double t3 = (b[1] - rayOrigin.y) * rInv.y; - double t4 = (b[1] + 1 - rayOrigin.y) * rInv.y; - double t5 = (b[2] - rayOrigin.z) * rInv.z; - double t6 = (b[2] + 1 - rayOrigin.z) * rInv.z; - - double tmin = Math.max(Math.max(Math.min(t1, t2), Math.min(t3, t4)), Math.min(t5, t6)); - double tmax = Math.min(Math.min(Math.max(t1, t2), Math.max(t3, t4)), Math.max(t5, t6)); - - // if tmax > 0, ray (line) is intersecting AABB, but the whole AABB is behind us - if (tmax > 0) { - return false; - } - - // if tmin > tmax, ray doesn't intersect AABB - if (tmin > tmax) { - return false; - } - - return true; - } - - /** - * returns the grid cells that intersect with this Vec3d
- * http://playtechs.blogspot.de/2007/03/raytracing-on-grid.html - *

- * Caching assumes that all Vec3d's are inside the same block - */ - private boolean isVisible(Vec3d start, Vec3d[] targets, int size) { - // start cell coordinate - int x = cameraPos[0]; - int y = cameraPos[1]; - int z = cameraPos[2]; - - for (int v = 0; v < size; v++) { - // ray-casting target - Vec3d target = targets[v]; - - double relativeX = start.x - target.getX(); - double relativeY = start.y - target.getY(); - double relativeZ = start.z - target.getZ(); - - if(allowRayChecks && rayIntersection(lastHitBlock, start, new Vec3d(relativeX, relativeY, relativeZ).normalize())) { - continue; - } - - // horizontal and vertical cell amount spanned - double dimensionX = Math.abs(relativeX); - double dimensionY = Math.abs(relativeY); - double dimensionZ = Math.abs(relativeZ); - - // distance between horizontal intersection points with cell border as a - // fraction of the total Vec3d length - double dimFracX = 1f / dimensionX; - // distance between vertical intersection points with cell border as a fraction - // of the total Vec3d length - double dimFracY = 1f / dimensionY; - double dimFracZ = 1f / dimensionZ; - - // total amount of intersected cells - int intersectCount = 1; - - // 1, 0 or -1 - // determines the direction of the next cell (horizontally / vertically) - int x_inc, y_inc, z_inc; - - // the distance to the next horizontal / vertical intersection point with a cell - // border as a fraction of the total Vec3d length - double t_next_y, t_next_x, t_next_z; - - if (dimensionX == 0f) { - x_inc = 0; - t_next_x = dimFracX; // don't increment horizontally because the Vec3d is perfectly vertical - } else if (target.x > start.x) { - x_inc = 1; // target point is horizontally greater than starting point so increment every - // step by 1 - intersectCount += MathUtilities.floor(target.x) - x; // increment total amount of intersecting cells - t_next_x = (float) ((x + 1 - start.x) * dimFracX); // calculate the next horizontal - // intersection - // point based on the position inside - // the first cell - } else { - x_inc = -1; // target point is horizontally smaller than starting point so reduce every step - // by 1 - intersectCount += x - MathUtilities.floor(target.x); // increment total amount of intersecting cells - t_next_x = (float) ((start.x - x) - * dimFracX); // calculate the next horizontal - // intersection point - // based on the position inside - // the first cell - } - - if (dimensionY == 0f) { - y_inc = 0; - t_next_y = dimFracY; // don't increment vertically because the Vec3d is perfectly horizontal - } else if (target.y > start.y) { - y_inc = 1; // target point is vertically greater than starting point so increment every - // step by 1 - intersectCount += MathUtilities.floor(target.y) - y; // increment total amount of intersecting cells - t_next_y = (float) ((y + 1 - start.y) - * dimFracY); // calculate the next vertical - // intersection - // point based on the position inside - // the first cell - } else { - y_inc = -1; // target point is vertically smaller than starting point so reduce every step - // by 1 - intersectCount += y - MathUtilities.floor(target.y); // increment total amount of intersecting cells - t_next_y = (float) ((start.y - y) - * dimFracY); // calculate the next vertical intersection - // point - // based on the position inside - // the first cell - } - - if (dimensionZ == 0f) { - z_inc = 0; - t_next_z = dimFracZ; // don't increment vertically because the Vec3d is perfectly horizontal - } else if (target.z > start.z) { - z_inc = 1; // target point is vertically greater than starting point so increment every - // step by 1 - intersectCount += MathUtilities.floor(target.z) - z; // increment total amount of intersecting cells - t_next_z = (float) ((z + 1 - start.z) - * dimFracZ); // calculate the next vertical - // intersection - // point based on the position inside - // the first cell - } else { - z_inc = -1; // target point is vertically smaller than starting point so reduce every step - // by 1 - intersectCount += z - MathUtilities.floor(target.z); // increment total amount of intersecting cells - t_next_z = (float) ((start.z - z) - * dimFracZ); // calculate the next vertical intersection - // point - // based on the position inside - // the first cell - } - - boolean finished = stepRay(start, x, y, z, - dimFracX, dimFracY, dimFracZ, intersectCount, x_inc, y_inc, - z_inc, t_next_y, t_next_x, t_next_z); - provider.cleanup(); - if (finished) { - cacheResult(targets[0], true); - return true; - } else { - allowRayChecks = true; - } - } - cacheResult(targets[0], false); - return false; - } - - private boolean stepRay(Vec3d start, int currentX, int currentY, - int currentZ, double distInX, double distInY, - double distInZ, int n, int x_inc, int y_inc, - int z_inc, double t_next_y, double t_next_x, - double t_next_z) { - allowWallClipping = true; // initially allow rays to go through walls till they are on the outside - // iterate through all intersecting cells (n times) - for (; n > 1; n--) { // n-1 times because we don't want to check the last block - // towards - where from - - - // get cached value, 0 means uncached (default) - int cVal = getCacheValue(currentX, currentY, currentZ); - - if (cVal == 2 && !allowWallClipping) { - // block cached as occluding, stop ray - lastHitBlock[0] = currentX; - lastHitBlock[1] = currentY; - lastHitBlock[2] = currentZ; - return false; - } - - if (cVal == 0) { - // save current cell - int chunkX = currentX >> 4; - int chunkZ = currentZ >> 4; - - if (!provider.prepareChunk(chunkX, chunkZ)) { // Chunk not ready - return false; - } - - if (provider.isOpaqueFullCube(currentX, currentY, currentZ)) { - if (!allowWallClipping) { - cache.setLastHidden(); - lastHitBlock[0] = currentX; - lastHitBlock[1] = currentY; - lastHitBlock[2] = currentZ; - return false; - } - } else { - // outside of wall, now clipping is not allowed - allowWallClipping = false; - cache.setLastVisible(); - } - } - - if(cVal == 1) { - // outside of wall, now clipping is not allowed - allowWallClipping = false; - } - - - if (t_next_y < t_next_x && t_next_y < t_next_z) { // next cell is upwards/downwards because the distance to - // the next vertical - // intersection point is smaller than to the next horizontal intersection point - currentY += y_inc; // move up/down - t_next_y += distInY; // update next vertical intersection point - } else if (t_next_x < t_next_y && t_next_x < t_next_z) { // next cell is right/left - currentX += x_inc; // move right/left - t_next_x += distInX; // update next horizontal intersection point - } else { - currentZ += z_inc; // move right/left - t_next_z += distInZ; // update next horizontal intersection point - } - - } - return true; - } - - // -1 = invalid location, 0 = not checked yet, 1 = visible, 2 = occluding - private int getCacheValue(int x, int y, int z) { - x -= cameraPos[0]; - y -= cameraPos[1]; - z -= cameraPos[2]; - if (Math.abs(x) > reach - 2 || Math.abs(y) > reach - 2 - || Math.abs(z) > reach - 2) { - return -1; - } - - // check if target is already known - return cache.getState(x + reach, y + reach, z + reach); - } - - - private void cacheResult(int x, int y, int z, boolean result) { - int cx = x - cameraPos[0] + reach; - int cy = y - cameraPos[1] + reach; - int cz = z - cameraPos[2] + reach; - if (result) { - cache.setVisible(cx, cy, cz); - } else { - cache.setHidden(cx, cy, cz); - } - } - - private void cacheResult(Vec3d vector, boolean result) { - int cx = MathUtilities.floor(vector.x) - cameraPos[0] + reach; - int cy = MathUtilities.floor(vector.y) - cameraPos[1] + reach; - int cz = MathUtilities.floor(vector.z) - cameraPos[2] + reach; - if (result) { - cache.setVisible(cx, cy, cz); - } else { - cache.setHidden(cx, cy, cz); - } - } - - public void resetCache() { - this.cache.resetCache(); - } - - private enum Relative { - INSIDE, POSITIVE, NEGATIVE; - - public static Relative from(int min, int max, int pos) { - if (max > pos && min > pos) { - return POSITIVE; - } else if (min < pos && max < pos) { - return NEGATIVE; - } - return INSIDE; - } - } -} diff --git a/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/cache/ArrayOcclusionCache.java b/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/cache/ArrayOcclusionCache.java deleted file mode 100644 index 1b7d1c9..0000000 --- a/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/cache/ArrayOcclusionCache.java +++ /dev/null @@ -1,55 +0,0 @@ -package com.logisticscraft.occlusionculling.cache; - -import java.util.Arrays; - -public class ArrayOcclusionCache implements OcclusionCache { - private final int reachX2; - private final byte[] cache; - private int positionKey; - private int entry; - private int offset; - - public ArrayOcclusionCache(int reach) { - this.reachX2 = reach * 2; - this.cache = new byte[(reachX2 * reachX2 * reachX2) / 4]; - } - - @Override - public void resetCache() { - Arrays.fill(cache, (byte) 0); - } - - @Override - public void setVisible(int x, int y, int z) { - positionKey = x + y * reachX2 + z * reachX2 * reachX2; - entry = positionKey / 4; - offset = (positionKey % 4) * 2; - cache[entry] |= 1 << offset; - } - - @Override - public void setHidden(int x, int y, int z) { - positionKey = x + y * reachX2 + z * reachX2 * reachX2; - entry = positionKey / 4; - offset = (positionKey % 4) * 2; - cache[entry] |= 1 << offset + 1; - } - - @Override - public int getState(int x, int y, int z) { - positionKey = x + y * reachX2 + z * reachX2 * reachX2; - entry = positionKey / 4; - offset = (positionKey % 4) * 2; - return cache[entry] >> offset & 3; - } - - @Override - public void setLastVisible() { - cache[entry] |= 1 << offset; - } - - @Override - public void setLastHidden() { - cache[entry] |= 1 << offset + 1; - } -} diff --git a/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/cache/OcclusionCache.java b/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/cache/OcclusionCache.java deleted file mode 100644 index d939357..0000000 --- a/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/cache/OcclusionCache.java +++ /dev/null @@ -1,15 +0,0 @@ -package com.logisticscraft.occlusionculling.cache; - -public interface OcclusionCache { - void resetCache(); - - void setVisible(int x, int y, int z); - - void setHidden(int x, int y, int z); - - int getState(int x, int y, int z); - - void setLastHidden(); - - void setLastVisible(); -} diff --git a/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/util/MathUtilities.java b/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/util/MathUtilities.java deleted file mode 100644 index 57572ac..0000000 --- a/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/util/MathUtilities.java +++ /dev/null @@ -1,19 +0,0 @@ -package com.logisticscraft.occlusionculling.util; - -public final class MathUtilities { - private MathUtilities() { } - - public static int floor(double d) { - int i = (int) d; - return d < (double) i ? i - 1 : i; - } - - public static int fastFloor(double d) { - return (int) (d + 1024.0) - 1024; - } - - public static int ceil(double d) { - int i = (int) d; - return d > (double) i ? i + 1 : i; - } -} diff --git a/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/util/Vec3d.java b/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/util/Vec3d.java deleted file mode 100644 index 28e7ba4..0000000 --- a/divinemc-server/src/main/java/com/logisticscraft/occlusionculling/util/Vec3d.java +++ /dev/null @@ -1,85 +0,0 @@ -package com.logisticscraft.occlusionculling.util; - -public class Vec3d { - public double x; - public double y; - public double z; - - public Vec3d(double x, double y, double z) { - this.x = x; - this.y = y; - this.z = z; - } - - public double getX() { - return x; - } - - public double getY() { - return y; - } - - public double getZ() { - return z; - } - - public void set(double x, double y, double z) { - this.x = x; - this.y = y; - this.z = z; - } - - public void setAdd(Vec3d vec, double x, double y, double z) { - this.x = vec.x + x; - this.y = vec.y + y; - this.z = vec.z + z; - } - - public Vec3d div(Vec3d rayDir) { - this.x /= rayDir.x; - this.z /= rayDir.z; - this.y /= rayDir.y; - return this; - } - - public Vec3d normalize() { - double mag = Math.sqrt(x*x+y*y+z*z); - this.x /= mag; - this.y /= mag; - this.z /= mag; - return this; - } - - public boolean equals(Object other) { - if (this == other) { - return true; - } - if (!(other instanceof Vec3d)) { - return false; - } - Vec3d vec3d = (Vec3d) other; - if (Double.compare(vec3d.x, x) != 0) { - return false; - } - if (Double.compare(vec3d.y, y) != 0) { - return false; - } - return Double.compare(vec3d.z, z) == 0; - } - - @Override - public int hashCode() { - long l = Double.doubleToLongBits(x); - int i = (int) (l ^ l >>> 32); - l = Double.doubleToLongBits(y); - i = 31 * i + (int) (l ^ l >>> 32); - l = Double.doubleToLongBits(z); - i = 31 * i + (int) (l ^ l >>> 32); - return i; - } - - @Override - public String toString() { - return "(" + x + ", " + y + ", " + z + ")"; - } -} diff --git a/divinemc-server/src/main/java/dev/tr7zw/entityculling/CullTask.java b/divinemc-server/src/main/java/dev/tr7zw/entityculling/CullTask.java deleted file mode 100644 index 93cb42b..0000000 --- a/divinemc-server/src/main/java/dev/tr7zw/entityculling/CullTask.java +++ /dev/null @@ -1,136 +0,0 @@ -package dev.tr7zw.entityculling; - -import ca.spottedleaf.moonrise.common.util.TickThread; -import com.logisticscraft.occlusionculling.OcclusionCullingInstance; -import com.logisticscraft.occlusionculling.util.Vec3d; -import dev.tr7zw.entityculling.versionless.access.Cullable; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.entity.decoration.ArmorStand; -import net.minecraft.world.entity.player.Player; -import net.minecraft.world.phys.AABB; -import net.minecraft.world.phys.Vec3; -import org.bxteam.divinemc.config.DivineConfig; -import org.bxteam.divinemc.util.NamedAgnosticThreadFactory; - -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.Executor; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; - -public class CullTask implements Runnable { - private volatile boolean requestCull = false; - private volatile boolean scheduleNext = true; - private volatile boolean inited = false; - - private final OcclusionCullingInstance culling; - private final Player checkTarget; - - private final int hitboxLimit; - - public long lastCheckedTime = 0; - - private final Vec3d lastPos = new Vec3d(0, 0, 0); - private final Vec3d aabbMin = new Vec3d(0, 0, 0); - private final Vec3d aabbMax = new Vec3d(0, 0, 0); - - private static final Executor backgroundWorker = Executors.newFixedThreadPool(DivineConfig.MiscCategory.retThreads, new NamedAgnosticThreadFactory<>("Raytrace Entity Tracker Thread", TickThread::new, DivineConfig.MiscCategory.retThreadsPriority)); - - private final Executor worker; - - public CullTask( - OcclusionCullingInstance culling, - Player checkTarget, - int hitboxLimit, - long checkIntervalMs - ) { - this.culling = culling; - this.checkTarget = checkTarget; - this.hitboxLimit = hitboxLimit; - this.worker = CompletableFuture.delayedExecutor(checkIntervalMs, TimeUnit.MILLISECONDS, backgroundWorker); - } - - public void requestCullSignal() { - this.requestCull = true; - } - - public void signalStop() { - this.scheduleNext = false; - } - - public void setup() { - if (!this.inited) - this.inited = true; - else - return; - this.worker.execute(this); - } - - @Override - public void run() { - try { - if (this.checkTarget.tickCount > 10) { - Vec3 cameraMC = this.checkTarget.getEyePosition(0); - if (requestCull || !(cameraMC.x == lastPos.x && cameraMC.y == lastPos.y && cameraMC.z == lastPos.z)) { - long start = System.currentTimeMillis(); - - requestCull = false; - - lastPos.set(cameraMC.x, cameraMC.y, cameraMC.z); - culling.resetCache(); - - cullEntities(cameraMC, lastPos); - - lastCheckedTime = (System.currentTimeMillis() - start); - } - } - } finally { - if (this.scheduleNext) { - this.worker.execute(this); - } - } - } - - private void cullEntities(Vec3 cameraMC, Vec3d camera) { - for (Entity entity : this.checkTarget.level().getEntities().getAll()) { - if (!(entity instanceof Cullable cullable)) { - continue; - } - - if (entity.getType().skipRaytracingCheck) { - continue; - } - - if (!cullable.isForcedVisible()) { - if (entity.isCurrentlyGlowing() || isSkippableArmorstand(entity)) { - cullable.setCulled(false); - continue; - } - - if (!entity.position().closerThan(cameraMC, DivineConfig.MiscCategory.retTracingDistance)) { - cullable.setCulled(false); - continue; - } - - AABB boundingBox = entity.getBoundingBox(); - if (boundingBox.getXsize() > hitboxLimit || boundingBox.getYsize() > hitboxLimit - || boundingBox.getZsize() > hitboxLimit) { - cullable.setCulled(false); - continue; - } - - aabbMin.set(boundingBox.minX, boundingBox.minY, boundingBox.minZ); - aabbMax.set(boundingBox.maxX, boundingBox.maxY, boundingBox.maxZ); - - boolean visible = culling.isAABBVisible(aabbMin, aabbMax, camera); - - cullable.setCulled(!visible); - } - } - } - - private boolean isSkippableArmorstand(Entity entity) { - if (!DivineConfig.MiscCategory.retSkipMarkerArmorStands) return false; - - return entity instanceof ArmorStand && entity.isInvisible(); - } -} diff --git a/divinemc-server/src/main/java/dev/tr7zw/entityculling/DefaultChunkDataProvider.java b/divinemc-server/src/main/java/dev/tr7zw/entityculling/DefaultChunkDataProvider.java deleted file mode 100644 index fe8b71a..0000000 --- a/divinemc-server/src/main/java/dev/tr7zw/entityculling/DefaultChunkDataProvider.java +++ /dev/null @@ -1,41 +0,0 @@ -package dev.tr7zw.entityculling; - -import com.logisticscraft.occlusionculling.DataProvider; -import net.minecraft.core.BlockPos; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.Blocks; -import net.minecraft.world.level.chunk.ChunkAccess; - -public class DefaultChunkDataProvider implements DataProvider { - private final Level level; - - public DefaultChunkDataProvider(Level level) { - this.level = level; - } - - @Override - public boolean prepareChunk(int chunkX, int chunkZ) { - return this.level.getChunkIfLoaded(chunkX, chunkZ) != null; - } - - @Override - public boolean isOpaqueFullCube(int x, int y, int z) { - BlockPos pos = new BlockPos(x, y, z); - - final ChunkAccess access = this.level.getChunkIfLoaded(pos); - if (access == null) { - return false; - } - - if (this.level.isOutsideBuildHeight(pos)) { - return Blocks.VOID_AIR.defaultBlockState().isSolidRender(); - } else { - return access.getBlockState(pos).isSolidRender(); - } - } - - @Override - public void cleanup() { - DataProvider.super.cleanup(); - } -} diff --git a/divinemc-server/src/main/java/dev/tr7zw/entityculling/versionless/access/Cullable.java b/divinemc-server/src/main/java/dev/tr7zw/entityculling/versionless/access/Cullable.java deleted file mode 100644 index 2d7f312..0000000 --- a/divinemc-server/src/main/java/dev/tr7zw/entityculling/versionless/access/Cullable.java +++ /dev/null @@ -1,15 +0,0 @@ -package dev.tr7zw.entityculling.versionless.access; - -public interface Cullable { - public void setTimeout(); - - public boolean isForcedVisible(); - - public void setCulled(boolean value); - - public boolean isCulled(); - - public void setOutOfCamera(boolean value); - - public boolean isOutOfCamera(); -} diff --git a/divinemc-server/minecraft-patches/features/0056-Raytrace-Entity-Tracker.patch b/patches/removed/1.21.11/server/0056-Raytrace-Entity-Tracker.patch similarity index 99% rename from divinemc-server/minecraft-patches/features/0056-Raytrace-Entity-Tracker.patch rename to patches/removed/1.21.11/server/0056-Raytrace-Entity-Tracker.patch index f0c67cb..274eb41 100644 --- a/divinemc-server/minecraft-patches/features/0056-Raytrace-Entity-Tracker.patch +++ b/patches/removed/1.21.11/server/0056-Raytrace-Entity-Tracker.patch @@ -9,6 +9,8 @@ Original license: Custom License Original project: https://github.com/LogisticsCraft/OcclusionCulling Original license: MIT +Will be rewrited later, currently not ready for production use. + diff --git a/net/minecraft/world/entity/Entity.java b/net/minecraft/world/entity/Entity.java index 65a72cedfd3f3da0323b553afe0e9a515d4f3986..5893372688c9355759602645577cdbab7e6e3716 100644 --- a/net/minecraft/world/entity/Entity.java