diff --git a/patches/server/0002-Rebrand-to-Luminol.patch b/patches/server/0002-Rebrand-to-Luminol.patch index b332dfa..4e5f65e 100644 --- a/patches/server/0002-Rebrand-to-Luminol.patch +++ b/patches/server/0002-Rebrand-to-Luminol.patch @@ -122,531 +122,538 @@ diff --git a/src/main/resources/logo.png b/src/main/resources/logo.png index c06126b92e36566c93b901637926703bbfcc42ff..2b6037aab645e303df6edbbc8af34dc4b4a55bc5 100644 GIT binary patch literal 32775 -zcmeFZ`9IYA`#(O?zNsup8mH5tER&{?sX?W33OOZX7+d2+8tY8T7+am95G7korgBi2 -zL1B!&Y#D2bu@hz{dkn@{Kab~h&inQHer}&X;QPb-hjZL+T#xH8(W;QPy2M|V0IbV@PY3^p!DcY)pdT-pYS0f@i3RjW*mpW45bTtP1@r^vo3RG^ -z(TtOYegyUY@6!K;>3?0~eq#Q)zO97mqbbIQuPsVn`)E0pqf@tHLiP(eP$6$MnF+F?L=P%IsyC_)oN* -zs|!N=9IdnfH -zygcGSZ0l8iqEgP}cmU0-(OYsNYct@Q?UAFHw1UV?^_2>FZ|Ded4O)J*N`Ira;SE1{ -zYv9~1fh9xT)8OYH9&*FeYqDoOw#3=k_Xmi#5`+1c37hCR^!UZL3 -z@-3ip;uajWR@Frj_3t{UI^!wcx#4eG_aoQY{YXQtk8uaEr6z!`I0 -z<2WYK# -z{zjUg(%o?g>7ZD5=~a?z_Pax?-OnqDP8>@9nWMp^(zt(CZ^_ZRsh=zBX}ThMU%*{K -zL_Tn_nOd) -z+4a_UbcIj7Q2w7~7hMByw@&)iap0yJ+cK!fNkzQHt*&X1G5s*P2JeTB8?XKLt$enm -zkVo0}&+n_biZ4~Q#`**0YkanAl&xbRvfRp`U*Q6Yzwq+bB;4N@c3+itAI0G${U?+3R&wGk|D_z6|-uM0ZP!QFE5{)96W&eB%cPl&Qure9app3TN=@>4f- -z-%`xIWmOyFUo^yr{UhCr?|1qavPyZyzG0r6Ch6tO@XKNpy`Wb==#=fYdE)h?mRlH5gT#?YrJ>hybwpO92y -zw`C9-v(n@a`9u#JY -zwiFKQN(cT@j;wkY`X(X%&Q*-oa*SY%8(SxgQA9D){)b?yGQO+#FsjMUo#kg+8|hfY -zyG6i&I+qRj8CL&Pbmi#{kDsQ(N? -zPer6t#m&DhF!}4IPx6w?O~@_-(dE-BakDT?!f|{^ZK9JVotT%-@HGphDrhiZ5OJ&YMZuYmq1dFnTJz;EQEznNrZ1dynA_6 -z+PTkKB}qrPDIg^`t{R+1ldx|+S$06 -zO~M=O{HikI1pR>prnpDdz@Xe8${P+!_$9ZyRgR5CdD-kx;c)Mt50b^~mhcg7ch3o# -z*<$*pr6rgU$`wJZDzth?65vyX&cko*6C7LHEj~kTGHXZdk>%+xnFU<3?Q_@2@3_X2 -zJlys^%jtW4q6FIhpP4(m!1NEZ9M|_0mo>Hm+MWhPjevcYa#aeo8jE*18~ay3$u3*X -zz_8pOvWD(!Z2qH|U^6SSph&V_Nzk|VLVfFf(NlrPcx(kTrnvu3p}~7kEht_i`gJ6h -zcNw<~)HJlP*LpW7uTq~@+TZ{nt8D}0!hN9=T~^<2K!A+3x_uF8#~!cp&$aTZH6Y34 -zXniA=9#~Y5e3gRD58zSzwWUO;H4_<|0jNpQkDN5rpX9ge+^IDPltDIq8$Bmqj4K^o1A&DnEWL;Vwxao{8$nJZJ*VUIfK)1Yi%RK5%; -z6>p`n?Gc6k8pR!b{EL2RPflDfPI6y)BgMbAX{To(q>PhnU1%~QUt*1v4_%=o_#X0#vScLQ>)mRhBSIZcn)_l2AzuHz# -zY-%FgOzy0E-%|YT=^YaPl;)K(UTpi?6^ -zKF(nJ*5^rfLYe1C0#>Ety7ASdtNFJY$g{fuxi5S0hH9+yA-+~v4LYf5Ga&!I@CA0N -zWiu@3L(C(`@Xvpf>shlq>OOR#n0wH?oLm_}+c*whhrzqp=+SMS-A(xF`6q<-`JKke -z*X{>fc-4w#cL;R$G?FzCJ&e_YsFv@IWJO$9iYhhB_^(dMKr!TNKMR-AwbQ7MgdD{) -zG(kd@A>7OuY5#tbTH~pS>~*Fy(`*jBj8p@R^{U=ocd4{MN})JyuUA=iO0#$1#>UK1 -zgUlhVcO-a)URAM2a&eq7V`sAwr6dVHvGzT(z#NH(1V&WNZ_8ltk+Mk6T)wsx*#to! -zIu^BG0duaN;?#*b%u+dJ4Eb)4NI8$4FPS<+L3Qlx@ODhLt6J<0j7#YF5b1Xumva!dwL+vDn<-Y -z!Zv(_VWqu550J{g52(-v+}y?7u0q@>p^p?W#|?-p^s4!;gR4V0xVbUX?ts&$V2hn3 -z55whfW5&88!H_P(T_muU1UCeL2in%U=%k?;v6$&$m!aTRdvy`~gE^oSSJ%QF0zk>Y -z1-o-rbD~;Y;nM}yk8%`{6*`%r?M8pi94Jh(+EC2c46;TW9%bT}@8-@yN5tYYgX==L -zUU@Qu#VF73V1LJ?Wp59T%?1Yz2%~%%5?J5sjBF@4idcMJ(|RTRa>X76Owo-e0p-oY -zbZl4A(EN$K8lL%>qdw6}e -zI&)h_8agQ!Z=h~psI#6uYe~F$JvO+tg2X_r>QO=)`K=NjP&)5_&%XbI$7lcPC0CM& -zIN(a?`luX92k2+1qwt@e(IAO)slIM><7GwWYz-wBc1{lc-x-dR4mT1k%y!|##|T(KMZl~tEgbM -zd0W(7)E6GbRos-y*xxsbQqoO8wXe#H?CwTHlhLP{Fj>;sA$i**l`Mzc|xmm-FpfM_1K3Z^)Cg0G3J^ -zVkg^mTgE&8qR -z8W>}csfenTM#VxNGCx16#o45Fqbf_EPp$D<GyoiqJ26Y*BF&ZU6{HVnR})%nJ7Tp@}MUxQB60ldNkT -zy0LA5WU3DKjF$E8mDzamDsZ4*ih%tXCNjbyBRC1rkv<+KQ|U2^m}%cFfbs_RLxfm3 -zi|0G4R}NOjp(kSTw2bzDi58>*k%@O!kPu24KQh{#4V6!Fy_hnKX!WtEnhxvYzz6+T -zO`k-Kl0fD*I?`IQMn4t8FU)84??6mX{_Yq;*3kP6ap<WdrERW#`XZwV#rIPDa8TZW`2JYgXUa<3GEmV-8t_p^ -z=+rlosare6XRp1fUXhg_8tHMD+M&#Ol|o#Oq24|a$qd0_-n(EMUM+18_%sWPfXX^W -z(_9xtGiDPIrkY^TVY#X^?@))?M(J$LWqrIkO7pXC_4vDH=BVrPu#0b-Z;!UjEEV{8p=J+LAwVp -z_1w}lLt@{<yzUb|(*2+~!s_5{>p9rH;#%YD@P -zko|YwV)}jD_OzJph_M91*DH#n0XBkp;o-T@*=nZl8RPz_S3G-q3Bquyf88ak18l~ESelJtVOZBB*ff{p1* -z?i=j)@LtRN1EQ9ODi#vln7~woW2Vovq~{qkJ|tBZY|Dsh(T?TQGbc#;vPWXnfbF7= -z)`p_?V$KOS;epvsrrBfw2~0DTSnDaES4;11nI?};Esmt1EEua_Uiy9_uc?O;arm!1 -zcdQ<7Dp$^U`Mk|C@}4=v(%7pwwRH#XIxaNjsdog|ZuMcx+nE8El=Fmu<&)<`R#i-_ -zf_a*sZIB-1wFe#oM58RjpEq4c4KKI`m7d?XVvSK)+`5`o3(? -zkQ7*lIqID2)!=00>GGCEQKK+e79>SUrM?1&gJ!h3qtKZ{RhnRZn4}J!xXr;hC-d+! -ze70?Rx~z^rzDu(B7fBx)#L-a0qa$6VQ2GQvCr_@f62bquYEYZL(x@HO6q<6{KH;)Q -zfbq?hJ>s!27z@&XS6IUB2~!c9x-WAR^5kj=*0!W={mFQ;l@S93`g0SOugpfC#a*M?21aOioub}b_~hJ;_`xYda&es8!h+dx|062$Wj<=8+(pK(R{ -zd_qloCn7{io&0pDP`rWOkU}}7a=I@J5m5GGx@o<*@Uwn+eNB{9{R=DMG0I1YF^^aR -z$J)<5<&!I1F#k=@y{VbmKB1(0NyL{Ngc3KRQomPbKBETI9r)+%++yrgK;P(GbCJYY -zM0wP!>X*rSKBlK1c?y8>^tk>d`{>j7o{cz3W>WV!hG9!U(O#&jJC+XRRM0Bl-Mke> -z4*=C6;H94FZ=ooCpC75lzq5A@(WbXNSi5q^LWuM8cd!AD(Qk(@^Dud@ -z?Rk_H0OgFc6`^+?xk*_ChE0@Z-DN@@~l(0^Y8m`^u)Gji`U})wQa`o}?Jk -zj7vV{{Iy>J9|r;`Z8Gi9ys3P-{Pm?c#x+R5=Int;e8+k$1~YpDBWs2_=->*`f+H5t -z-s-!#Ygr|zg{|$1;2%S6Q@4|KYs&O(K=IdyLl;`EsuRM_>B~zoHQiU*73TM|B7lG@ -zY1gXKyWUTE3gnj)Evn2LrNm`&`$dheQ`42#%mRjxOdvqO?+iyEz@ry}_FrNV-;$UA -zs#4`|3Wq97*Zr}9*Ob25b0&wWH9gk<;q2WwI8g9azRnNLA+ee-V> -ztu)0@oxBktKQZllAe>sYE?oDB1GYBmq`8 -z7#qNhJ1;WX#`$t}bm86BeiGyg&XryYs%hvsP}~lTUt%R8s;H(JB>09!Ig(C#z^r!U -zCh_4l|K{jv>~pQL&wb=EdX?8rf6X+TmRNjgYAY)8u74=FgP25mB#(fRSkW4qB?u<{ -zUt^CO#n9!+1KCDB2Mu#f)JS$tcG+2+N(XogS8IInV(}3` -zbiQ6XRslnE8H!!JjM0pBYE)fava0&>@`OR8Td=eH7N`-mgM7M#{oA$c1KE~lkQ7HZ -zHIS$DZ7uPY^R(xnNWMBH3T~Z5R}pE4r@HGyPg^?a@#khyoOky|;Ir|ktx$7MMkVW^ -z(yG`(jF?>{{oP#=m)e%~n7*5K!u;*h@{GWa -zA$WK5=8*H7-5y)+zko95p#UB7-hNq4NrkYV^!`G7c^u2_71E0Is-zrmw2E>wi>PI|%*S7JkS6Z`7hG*YA2)f}zNh`FK=&NgzJ{0}k&4gz0%;m(#GCasc~ -zWZD=eEE?*}ht5cIO+K~n&6$c&YfhXROgyYw`7MIQPXDft+KhXhPpr*zdutP@oCa@1 -zF)u#|md%@3eFE!-a_jsv-HDsD3EUsRD;*EB^2J5f*G?2)JH0vk^_)y&&b=NelVm-T -zR9c%v_-w6_RgyJ5U|7g#ez*esx6$S5t83@zXsMpnoe~AmCEt$(c>&!SVM9WI)eVl`ZPh50iEIzPWOBdk&*C^?3=ST~}sYtY47e$(y&Sx9Rbm*R?}8so5$K -zi`C`3dz#FwY9B=w@fPxB#uG7oY6XOlH)kmmwg|;dTV;-=)$&13a^8);q4pvI!^`;d -zTtJdw)<{+XlexGDbb%pI7x?a|)k8;J#vrK-A`18JDyOQPfz#xNFjX0MWr$7~Wi#fJr-}?(f(n=S$gkxL)r#S<7rk5G3 -z8fvyvNTt1E`MA%&2gLr;EVhkBZdbL|J9CCH0R+@FL?FTt5aB7@y6rB(Y*s*Kl5_G2j_*Kg|w2WkHy(Ob(;#V=v -z`bLq$KT1ffLPeEbw~ADsrHZT(slnR?47aZpus4@DM(6(=41ybhF+fy<7xQ>96iN$)}+p7sMomkODBU0H{I)hk4n^O6P10 -zwfz)>M3`a$r&=u*J2WxCLfA(ypHBxbu5{-YSBE-t<$4u;%xtCnBO=Sb_frGgAb2|+ -zZ>@|;2%wCgGmdLWjU}{L->~j!QRNh+%wtLO)WAlFEb!gF9X^mRDdIGw8_*rP=>&!u -zVJfG3y$6Xs>#o`x=mGQ%2l~#ZjW!qtT!O9q4OFg?Q|fz{Ys9gkwGAvk-qt%2J=$}n -zc(ON1(5D1!Hf6v?&BxMq1~Gw4m*?o29i6Tmd~=wkPp{%{ALV(c*-XX`jDw(BDT0t* -z;TvIX*ZExm2t|zQe3&mhI;H#0m~ol#%Ej9ZqJ`#Z>_*Y#V+eQjIewE|wh~Aax(saZ -zNc6#9jN1Hhbr&zW@*yc$D;F=7o#2;2A@~tAVP)#a7VdDk1&r)8v-AKRXtf$nD6O`8;HFdIJS$u!*6oTA?YXQig`$-_*| -zupJf-io^2X@h;e&#q!xcwrH%@&96`3BMKoftc*YZ7|WL|8Y+~84T21GBvjtvOA@K` -z+4uK7L=}$B`&c|#+N$xtMLw;O1#gnBZ)2dc^sM%1uHI_UCa7xBtqcC;(TvjyFzi<^ -z<#*5hN{yQVh%;kBEBwHiaS|rJFVL&f-Ig)1pU>QltiG84*_PDv|J7*5GZDQayWG2@ -zfQRH49K7zQ?#QDtSnh}isTSa&%RkUqhk;9WuG<4CRFmGLoDn^c4sph>a@s#CbN0dH -z!F3RL_wlS+6KN;O#Wj*VFx4jG38QV|qys$ZA6QPQgNlZoo{D}tHk=^nPW0Tkh_fY) -zTSH^t|5EzKesK35ST_n0C7% -zj{p@o2lKsay*I$B!Dy#H3Ev$IYK}t7S9_*09GfC>y8JJ5PjGckFDW?cWFAIw^l*C& -zM*m+MRk#s-?4BQq=tuGkotabmnO}pvIW}egH?Mp-1x&?8kL`Yu1ctphh33$+{&gBx -z)oM5Fa=2u%>XD+yqIXxewCQmd@?;V)2UB1|4k#e$k1=Iq7vfxi;>uG*_>f0Jbe10%PV*b@I;|3<#(+Ux;7MeAF` -z-N{%&JJ`Ob>l$;DWVr_LeZRBMVbx%|lIGb@WEu5gZdRxhx8Xo|P<+|5>tWU4E~UQ& -z-*Fq$`zh{VaB}wR0fW^Nv$&YfAE7oCz$r(PO8LG`Je}YWY;Uu*J|{8o?I(zD4R~n;qLhLTeA-~|Zsavj$_$Wo?915C1uPRV!s&Q|ULjUNCMkp*U45Bl -zkJ~eRN7&M!YLE;QUIALt@f|0glr={TOlEK6Dq(I`DnYW;{h7ypWTslS8&0Gf$AubonPDHL6!aB<2%nRzc92H2nA|EK7}cL -zQa%6dZ5s9Xst0Y&_vadi>xWjip9agBBPLbW=~N6fq~ei(}vh2Pz2bC!=YEAUfp9t>bmynK7DglBe>^4X|(bfT}CcRauL!pRN^@ -z+Rl)vL)}$i*Mp}tZen`y#;8m+`w-vN6nT0)<*RdwdvSv*=Y33b?!v4eOGSVA+|eXqs0L0$A%IYP+2#oH+3nA3>@;@6Dctr0l&|v3WuCltvPhL?C!B -zo;JjZO!YkLw@Og`=&Ib!WHx8tD{T~6ZGfQeFTg*)%GLb)fSPofs!IBSg4U76i`&SF -z<_u@`S1z*$6)??xGPKiBhaBXnW{-AEvdp59R+jAAo#ytW*)%~YY6Bt~{cd>=kSgM> -zpU6gZ=EQ3n>WCdGPwK5$v;+DoFyFp^> -zm&bRs#g;vc7~3EDDs5hXa^Ni8@h#wbS=T;h77Zoj@0zehnpcbzM;VMgw!oY+2OBJ_ -z+w0QGe0ZA4$-ecD-&K3_6Yvk2iow-2&d?^CgrK{sCN(x0lm+#B{C7CfH{&%SlJ58 -z1#MY-)^rMq8}|JZTp;hu;!f|Fbe-qYJ{#V!_Wvn_omhz3Ck7i}2oOGVs=O{aEV$71 -zeRMp@aW-S=nD0YTqvqZQNMfu)3MgH^WZ(0$o#w+{f>y44rIOmUCX1{HZb3w)QGGb- -zbkj}xS1)Bv@P3QX`Q@TM#L6Tx5H9{0s2;)7^8=mMl=xB8X!2nZpD817-?^_=o0BK*tDGQV7WYU}4{mw_ -zaOcU9;H7p;FCgw+zZDG8`o4@Wq{UEuXaoj9Ty!)*Xr^6Tw-sQ2BrBeB-Bc*q?zp(H -z{E2e|l#Tg6jsec`MJ_3TZz7MhSrL-kj;Waxsc!$f^XFw_l55$;@r10;P@?}8(1PbL -zd_NUr!&zOeOkIYHewx?;crv8phYA@^##-ForS#7TyO*?e)4ux<=wP4{m&jknP+~NBtpR^ -zeo1Bbd77#3<*yU^!Ns#a!afZY=ACB&JV-Nfj0levEANOm0cs!iqRE~?c=st_Gl%jX -z0eQf+R!uWd0la9zH9DUH0a!}7ft8R3y?VVe&+fVfdI*^(ccRF&_5azRCV~ -zLEP8p;qSD6xF|E}w-UdGq_$#wdn+!BQ$RiqS?eqVT>}N7z$MNuDY6ZiioR+fyA4NY -zbzB@9+_UF{DkndNI3DBY3kFO%{!)BPiIbrGmA4liRS=j}p6^hYcT;8}UQBD_HkoG7 -z!IVXuL(>j|T*NWIwdB9fQwp%3s?tx`X{fk$Z{6M)qC4&cmyo|}(dW{6Pj;Rg_x5-Q -z;143(%gT1$7&x#T{Bj~|vBFvp4fQsn9quH5G=CQ;Pf*-W5T<5QQ1YUE7Tu8%r_bu! -zi$q^L(U%j6Wr6~bn5Vpfrnb}GVmU&DCx0#?fJI5uRGPpU=HLNxfn(TW=`bUv2F-w9 -zgsZdM#-p;jF0$q>>KFF`jX~~A`Mb>n`{awji=P=PZ$rCx%jx7_D-18%~a{ArMY=ycC3=8ZBT -zE3m*+SjH^@93jn(P1pbfv#IBj-@&NjNNiVJXBnpSN8^ZUWLC(H?)qAehq6K>sRk0K -zYB>=DUOU-E`#F*mM;yoa>tx3)$>;0dTZ8vx>5|1z#?|;dQT{^?+@kqDTs$tZvfsW8 -zlvtf?WnhnjNr5%S4?RR^Oby>38+@w6$)Y;CW)mXj{EtX%QfwII-us2 -zH_~{Pxy1Ex>S6wJu1k=)qRwvyg_#>SfzWlOo3B4ncrEV%HvgB{zTM~CePY&E&F*HE -zj#*lrvzQ>0x3fv#NNYWffGA#-%NXpfrvT~hG>IPvZ4dT)RvqF@F{3!tC)|~OP-fQ~=@|1`A(k14N$q(B5 -zj(x4u22i$7=-CrR@kux_SH5ce~esCxR+*Q1gi!~MBZ@B -zqw5nYG6&o*d!w@CE}`P&@I_8Fpw9Mnb3TluQQ!ppZ7Rw0WS8Xb=(5S-oP&484h*WVU59~{r-Sxp -zVWD!Z_n&+~SU=OsRuz6Zvym?MtR_EYzJ2jf_8J%l49lA>O%gkKo4$9xnD)w-Q%aoI -z;bZJ7v)H -ztP#D_wgkv$vsf@xs!#|~GDG$)orWmgeo|5arBY6hk!0YICR)zGLSYcK%4QZ+e+IsN_m5Bh=l-B -ze<0C}KBPaNZ3yqeunA2w=B3zE4(nj9))ugrCG8W*cdPa*c@Q}8OUL}RV<T_19#Z4)L70Bv&IME(aKl7nR5zrI;$2F1b -zvM?A4SP?i~Ze*C8byoS5_!PXFA}GamTW$#Hw%l^e{|7Pzoeu-|R$zDf=%4dmPWOuU -zh`@8H;hgkzX7zSfmYmZ{q*{i{?or^>83@GSC&&x7A0Z%$pD*b?{~9< -zKYKyi8gJZB=R=5{1w(383+@#)4=m;-dC3U{|SYLnmPp+p6ghhCUm -zJpg4v=>+GwolluDysPBV^4gbXQzvE?29qPmAk40V%e4v3xg1*SDtB;Vf9eJ2R-6=z -zDThzEYFYBb9i##ZQEx?1AOC}JU3nZaqju3}<>(AMqhxGy9Sn**p%8ty_8GOIwx-8$ -zBmF+6u3#vqCu|3H_J>TCVb(M}I(w8S5BFN@u;C~1rrKxGV&bh@ZD5}>H}c}a9y``# -zWn@x7>?Z{?X@638v -z*JOS7w3T!)fY!|VJ)<4mh`Uu=(`z{Fn98)<&MJd^QF6M#-NM9P<}zmFsw2$fi6wdY -z=npm@4qnzt1TFfOx-=aZ{l8aT-k5n~QZ?1Wzb1RX9_)eza0I;X*I)Z`Jw7WdQKUHf -zD=&uWafTCF51#AK2ca1_={4%rf2=%~agg`{9t)TISIywKe$PtJ#rcgv8L`C?kjkqU -z;OKyM7ofe0aqwojuQ?J7h?gt1koCv8IPcn;J}6FJ5CajF*vQ`*7&wQ%@viKk`iDhk -zhNfs~odfh~l~8)I14?y+lh;zSk}d&N0hSK|-yLhz+tM;IE3r-2Vfi3Oc^V-7DOXA* -z`qGW{SKv+yBg4^)g#Gt1VV?#IZ|~2>mqdvC);lErKUv~^GgX8i7s2O+g--uNTJ%4p -zy4;_;9|pVQ?bVkixKTCU^fL}szWW5Ct>w_SVH3{0^?r4iMDvvR;fyq6pg*wVHwv7i -zz4@-}=v5s&bJNN4?GWLCxx7sjFScVdq`WOq-o{=yYNA=(q#8NedA~f=dlyz>3=3?a -zj}QFtK{fKU)G`0rTeZu1I~KQ?OnyT~jwV1|E^Hx)@dSGLIkyQO|fx -z&JozJ;wR-tci~Y8ZWHjfOwU|sZ(Vgjdh!!Na?BaNpNDRB -zi6E}62ixq}@lhOjecf!mk-lwQVDThz>9 -zZQzr>?BeHp=WRdz6f~`P!bG!PU3%=BVJxV%IwuP)A -zh7-7mSL$w_f9>G$gdJF9>8@xgrIj^D@&Tsr@b&$FKSIj^pd42b0H|=3+yR9Ei{Ce9 -z%6FkK@01i_gTU|_qrQR_Z(eG^?rChUoa1`!xNheyNFFwvN3C(w0#cfAk>w2!ERg=a -z>^y;d3pbOz_(*Wr?JCnb+$L}w(L}AFk5{xI_$2_;2AC9UaoJH#KL|QEd -zGk<(cpZ4fZg-eD<`Zuy^N-Ll7L3yAT&`?k9tLG(l*?w~T3@l{#eE7iyD^_m$g*zq` -zZj3B^@&&eH*I~;VKRfr+eiMCTy9VeZ)@zOwinS|bH670{dQ$TmSghn|%NF&mneXD) -zWSX0B6e711HI;usoE|pR-@yDOmNGL(4b*`tf!7RJj0Q=%7z4f?0grqQGgj;T^LL%x -z{zu?9YR!!>{DNY4bWPI5a&Pl94~cf&V -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 -z<4@>9_ -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 -zBbC{>nuJTeqPK7}@r@A=8)3OA0t@ -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 -zCO@@n-Lv5rISCRq)5)l7cf -zhEi$q9$RC3A`pHW7U{N7+$!de2%6&i>~!`IgN~goXGPnqQZhF>C?1Z1`9%*S9h2%3 -zA(c@_u1jZzcdB9g-Vbm1n0}!Px^7`X*AHd&&`LD%#%Jg5W^!Fsb2Y20cEPn^xE3mF -zc$KdW?~IW3R~StVwCw1DWf7!*42u7G0ZZ4|DITiU;X!3Yu2;@A>!;J|ercb!`1B}1 -zb!M=Lf2InpuDfwqT<(}hMKNPnlUCX`uTb53-EJIEHUj(ll=Pq|oFwJ#3!V-et$+pf -z2`6mD%?N_Q?Sg>w)W$)vbK?2S*}+av{A(1Xs`FC6R6UO}mJmQX6#)g1us^IcD9S47 -zTWaq0SqG)aQ<67clF8*t2*c5+`>;bcRUN@MNm)c10348UtmlB8*r^HJo;w@WqIi8Y -z!uzJ`tAqDDOku331ALZ+g<0auHtkO0woJIa-JKh0U8dfthUwDj7NcDeKr;3a1)fD( -zkSWvqls=M5vu^HC()fDKy3*5wc5b}ad0}1A(vAc@r40>g?1gvuEushq^;vK4ITY?G -zOzQJpXDwxRH6w`^n5kbjC^?iANafcp9p~%y#eDcX$Tv+8&h`V8)P9(%JMzu&>uoL-(zJcb=x4&KGC72-rsjzBI*4}6wD4ROz -z?(8G+4`af6y7m@=$b)W;I;Zj|GcCi2GQAe(^5sgS%r>>=7^;Dz0Ai5~OD00n!sUx+ -z*uBg&UgY9|-bqkt(`a`gp2G5i%dc{3;TsfLZ<4vVhGpvGX#5NZGMS{#P`pKMh0W*^x*LT_%1;5MBby> -z{5jD1e0m^5x7%a=ub$WdFK-F%*T>Sx^aO9y@A&u$zA(b^fhp2a&UkT4k}|F{^G*=4 -z$V@@*-{yo0lnx@*+XBHOOE3au2?abuxAe -zZ@M%Qcol~CG_?ObeVy{A28Shx4F;@-VH}N}Dw|VTX7CTRBum;2e>Tel6@3}fbb>ua -zNL*iqt5Szq>hrt-X|OPn%cqFQOe$f)j{azlY9K!Q)JxIM2CANxo2Qv^7urEw6^Q~Z -z>2Ml`igOvVB@L~~EGJ?Fc8$WTZ;b!w}*d -zhGNPjtUV)T)SN4MP5>E#)0i{cg-Bz{%B5Ck)#*1#M37vzD%tKAQnCp!+;2Rz~XB$&P)VyQAK*oKR6}WMUnZl&?v;o|MCB5^hS(x -zt+ZoVzjTT?r6aqg@n0>^LC?Yc*Z~jCy(!cYh(be2Q8CVbXzBY@^v*HQnnma^19or= -z_UwED+YZkV#(2OaAg5&lrth+sb!r2Rw(0h^10m0Vj)F2DlBJ@@C^WcgCKKR^y--g$ -zxED?@$ipwT&~rf<^qe3Xa?HI34?Q1*k$K*AgJZRHdgUVQ${aZ5%Q7d-TlQpJ6hb4< -zNIS$w24(!0Jz_+|d;k-GVEPpxCtX$}3r?QFH|3RY*nfSy0N-+B$6l{qVOIih!V}2k -z;hwQaFhS?q^6WgHpIVRI^gul%77;cum3V# -zA!8E}9k5e2QS_mE-d_^GelrI?2Lls62@y=NaV3DQz`hLbR?fDO`51~QYpE(-6n-)R -z&g7KR!8rn;0fOm(iCs3`C4U|&vaAMq$NRci^uoY#nkl`{<;hR0M-A>1HgZCD0%SZ8CzHSX9W`c5co<59Rf}TAf@ky(qzHc +z4vY%;LLU6z(Eri&zm)jj&iS88{7(`8e_J??JX+*dRrOQWhOO7as(Yk0YffnW=vz3E +zv=Bm!SP+eyQ@>vmjgI%VT2z`HNsv}R@h)qN3A}#m%NeHa{)uBv#qDsrXI0XVs5{q} +z#BNN(+(X2(XYE^Do^30I@XKT(rY9NVgH$vA-36s@$5 +zJzX5Lu?ycuS~-Q0meg2uhQk#VWbX)9)c?vALbN4cmpa&>(rlHNW&EleF|ID-Cmo)! +zKefw&|3s5HGaX3{Y73SV6oAFKFo3C%xdzS83Edv^#=--%N?yIUPJgMp=_NnKQ% +zB1eW^p!tsv?(*XE8VctFwx(g-h9jj@iQ=vxQ>LT(!rm8e6l8%WkL03Rfa|-wys*%g +z;7xzOmxkVkT8CsHp~>ne`xMk)f}KFib3;3v4~kc>AfAT~ZFLWmPQtw7N3K|H5pU>m +z1sQS2GBpYrPF+J5mB*`D(kVypMXfF?4{kI`B34@d^WNPndc&huowq9?q6%3S5^P7# +zDXlMw)6gjO3eOt>*UIjH!}lnd=<=Q4J_YM8c@XDwCZ+4FonGs$A<}zuFVq$NIRlQ=(2!rv*4%>P=i{zYA*VHGMbL{?+}M2m9l-WK*q$onlUmnOhrLPfzfO9Hp)8Z +z=(ce}qgb`)0?1X5vu|L>k|tJUWU123dT&SlQn%xMPPH$BAX*%Rl+%f{PiBDl&ib&ARRKuV1R?D@w=16#ss| +z-tU)nqtE^~%f>a%?NUdDU2hfd{b6qLWy#Ft$tq$KDgGD3`~^YA47~6unEKycKSZ7! +zj=Q|weY+xUf64grwjZ|28~jEhV_AJNZis=E6w#j3-spXGMnhrlC&7dmroWikJ9`06 +z-FZ8@>mgROy6Fd1gTE{pdqwxFszu<>gmG7X0)9|bz_I{WlOl8h5y!a-ZiJj +zl!&r1KJd49Pru$6UMi>@FAt5Y?ECc_KZz>;VG);KHpg%mqrSXwR +z$rxYe$H@1%_-G_&&7zH-tCn?mj@a0~;qSO;XjbL@j&#mge`qYvw}4QIYI`(VGRBwv +zF)(E3D5YyInK%huqE4TU%3Z9Ap>yK3UwtO=*yD@ +zfNEIX>)4kW={FouhN~%}DPC%`I7I`_$o)59wl=+Q@G!jH)t?jY(wOK`HqPJBg939Y +zLA%};t@x%XZ)}!g*Y?mOtfgI{kPa@RhGl%%g-&h$=VoY{rk>=jwz=MqO&F*F^Q^i0 +z7ZSyi7oOy=l>g&I|AB!-J*C;5SOUZJw%^TiK{9oZyHvn>s`_p(_ci?*zF|N8^-^V$ +z=89vaD|s5+eC|WIDQG|%C15)naY2vsHZFIi1?U6Y#p=j`1AW_Jf>icHl+*o??%ks$ +z<6awosKtU#eT4mRTmyx;9VX~LUmw)iu2@(BdOc+yANGAIE`~zHfB7CfI8LGN`yn_z +z)T52Ak3$m2EZaCS7)V-5|If=w|NbydZCQi1JC||;&-|prm+u{t^ve8@wB=nMR1YMA +zM+v(-%eFfjjgP!eUIuloIp(c;#W*tMKNaEkfZR{ +zkR*eu^+UM}OKg9)WBR@c^O1ECQTMb$8$?aNg*j}8uczXCeoOsxnCM!lYi>~;0j`G0 +z3pDFqO0=C5NmM4+qA42Md%mUXw&bBGU^=yiol-u0qtyIOpdq+l6NZgtR(Dxo>mrJrf*Q?<%1pyAgv$NP +zdWp}o(X7aE%COOP30zh{QviVK%;bBX`g#voJ;pa0&7+iI?O!I(iv3VbLj$7g_mk#e +z^lmBuKsLR5g?F)cDeWMY8q~zyb6Q{TJ%O?RBp+6!+}!I1KN!-gZEjh;3I>(#q_21{ +zjQ#@7o4o(CS>*sTZ4e{3uevQPqOpBvU=$dPr%H2d7L+Bk)~4h3hK(K!Nf&82iTzO8 +zG5^HuAcZM4Pvp_rvJ5y6FIH|Ynd$wjEQS%_9>hd&^V_%aV_^d?wZ8{c#COGZbqB7+;q*LTUJTsb#&pn$X@(!p`h$ +ze$!e0<>aeNGmef-88KK=-5oxN5ic$e{;W!5yw-&X(ay1)Cq~-h7(`Cu=KC~uXiKr& +zXHa>LWS|f9Ua@w_bYNX;CC%?5GG2!^je6^(dL7~$#x)=^+ZFE9*k6}E0;f6^0P@?E +zdmiy0{vx$-=65u|?Sr%TAjX+R%A)RR45S%_^TC?Zv5#(Md#WPSqme<4 +zlKCAX<2`L8edqvVy(FpgYa2-e6PK++DX{+Yvs{#v@(mxvD|tq_6c0R8;|x`lQD*_M +zvxd37nV~cU8o&m<=P+fUNQ~YsStFOEA}5as4&VsRRbSuD`E@K|(<5uzaVd#5L&cE|h_lNKk;){M&Ht +zYjw}sXyk0V$d5i&n8ejT45BrP^;(mNZ51i$WjdwV)(k~y6G-mHQI2m|YvWRg*0A*j +z`r!QD;yp_*`uhyvGu@e@_ndwAkfhIkvm(VApH%LRv^{)zJdwP+M+}n|?dG%}2S$FhADhdS{cap4#tV +zP^!4hE{h5_t2MH_!zl4pcHevzea!IIb9K~NjWVC$#(7`~RN=q?m|e|;Ib7V0OR%VQ +z6PYHy%2s<5S!0wRYvM1p<^Wm?i@m3gI&Mx_qt`9=9b6y7K^a||!2 +zSb4M@9{4pHxzi(aH8_Ba-Q=zha>P<58t2Cjdcj&tjzX6oH*{T!zgV+J9aZN2AhNnc +zEZm+;Yn&bJgU)^#crIlT~LY{yTVeVd; +zug_PcCk)GW*U!VssK617u?`}l?*D!;af|_4JRR~AT;Z=RJC;u{DARbzPC(^UO +ziZt3j6)u$~tq-og4+iSN{W^RMr>U66z{KFp`-(4+e4%HTPqck1%pffbEK_E$ulmZ( +zNaxP-S9%wqr&QOA{Si-5QfK}JQaF@8MzrfR%#TeETNYRbyPV!qF4fq?LrU*b&X2?& +z1}zTN)UdmQkLz6JBjG7cFF16iURU64te=1ybj@?HmH+tZqeB!}3 +zM)?bc>cWc57eqOgMQJY2Ts-jS^AE4@p|3je3~7kU)EBl;FFg9GV}0O;&i?(wR50xF +z2EQ|l9#@h~Xn2U5HM1b+-4H1pTDRK1v9mCvhK=3o4guG4aKc!tJl|%Q*Y!pZU!8?u +zFp~?i`{p%KgwIXBinP}e#}mJ7jvR9ah+tp+T{UPuMcEtGbV@xe75Snvx|_An}Rv8v5}e +zL7hD$z?#{v;+uwO>mDK6>M7Dl$tuBv%9~F*$OFL7Wwx8E7&gk{F-r*1n%Pc#cbG(> +zr)Z#rp<5McByaTF1gUe#$2;oR4%Vh21gSVGt>+)ml9D2gWD{IK7K4)Uoz~-Jp?#7U +z#8zHL=uIUx^g5SE-5GYUeULOsY$It{9_gx(HOm3{iwjx*D+)Eh+MR+g7<;oR4bj~_ +z65(~nwrj&b?AZ_K4Ud8;p&S(NceBnO5@tPHS>I$+$!D^zH-EXTU0`HyblQs14(A7H +zymb&OEK5n=H9!w6x{1XxDdn$UW&Eto0bR +znc-{*RdM%+@+l68o1i29Z& +zAbl+Ha@o6EPcl^pI+xU7<*$ws9TMBsC~V790D$jNwEJyL-vQl6Ik_o~pD@?VAMLSFd4yNYfdg>mIfQgs0!@EZHxM{dvcBoo_F-EPP1sor+% +zpQ*SZuNW6mNZ8#dW4dAf_$-twXOan`9hmu{Bn07ItXBw;Y@Mr*LQ&cgC| +z^?K9jv{tIhBW+DZ8ax?BC76;uz^ZSl+`M6y-?ZVXUQGcjHZkBPrB|E#Je#nZLb<*_ +zksX6Zz41Y}K3~}u`FugvF(u2OH~jxLMgfq)y%Z3{skjXH8zbn1Yx29fa<`%hP|} +z{iw#i&0|AQ6|vm2qxfM-Qu`o9nC`T@!57`TZF4!uZj0Bkti3r3+vb}0Uru(9=}E9K%jL(#5iSP90NJN +zuH1k}r*t7ZDX@)mpzbalsyFdoNfJ%yBz!O=wHk5%$~HN-YC!5=vD2VkM%I%Wjerna +z6#(dY^tEi?k>w20q)z=SYl9)8t#d3){gt@8xPE_}hf#jhOhyb=j%*I9RM^f@TLn9K +z!;iDtjQ3&AVQ9)^!C298F2X;0W#F2D9Sr>jl5P#!{S!U7E&br{6;BD76}3knw@CKc +zavQH{jMDFO5rV8Z55s(4`3=Sw2*_JTqOZ)qnB3bk^0O_iqk6HRC#oiI#pA67 +zjj%sOe_8hCd`RQ^>*Lq{I4|HLmda+9$=UUN4E(1{8k3P&(W3b9!iPd# +zTYp*}nE@LAip!Mtax+>9qMTCpMCg%74Vuq96|rU-$JvX@zBmu1Amx90p#T8!6UGmh +zCP|l44m$6jj0D0o@=puTrD1bZM?%D7T3q);Tw8QkV#iC_jbPrK1ACBC%>|cQtX`)x +zXY53=1EVUbGxI4yapAzY4?1NiYiM*hAb7+0?;u(U>{y5pYdl*6f)bwT%qzBLyv?jF +zQKThx8m02-`2wPu%8?Xs?UIf*#=`fa&Wg9-&{yV9=3;57BO$glP0q%!UDlm>{hdP6 +z<6m@Amr?1#Y# +zJlFNR*{|kCe6r8sBUewJl{nS0(dzcO;VxuTFl+bU&qcE}J%=83YbA1kJ>Yvfo%?D1@kO2$~- +zI)%{c9P43BzrfiBe9zDYfDZeXp+a4-5sdRNK0Bz-r4^fuuS$|80iXc%qN3JJ9mPd3 +zy8YpZ{INO%LaTF}oH3oC=x)u-KfDT=?-mNHn)%baY-;I0R!z)KW#B-h7yc(>CjAeL0i;h{9O5lBZ-jRo3X$ZLTvGC}_^nuM7 +zId*3MG>YMZhf|;G>UmU-F>9!`udiN}TTSeZdw$!UqT&Qq1vlBCVu*J% +zSH0jj)8q6*by@R^8+Ya#rD4GN +zKbC{rMn_6stdo!hobm9RaByQmlh40vs=XWl5tc|B%X{o^rP+Sk)Lx1x-6RK%LYguV +z`}dRHljMk?2vSv+hg8ukEu;R>gp2$zI4_iSt!%A5h2k01Hu?pP^GSEZwIGqb+WhS; +z;6;D!{pNIpN5HGDtOff +zsq5q-7P?V{k?9MZOlTd&mPUkZT2>_*=S9vNC2o-xuf>-~Pop0jPJI|6P0{Ouu0|N- +zVmniDl{sDT#G4VZy!gBsSU}dqSuwjzmg*=E0A|0W9=A-PtC2BvC(g=xp{ZK~g7yd(zMZT4Nd-WuJn49hDnqPCL3ytbY9&7|?I}N;Qa} +z9$Eltgj;7t2k>CFFF$`KEbjbrjWSEOq%J${^LVO=o?@ +zsqW*m6XuD2(O&*r!GowPn9~(azh1sFQs`(0dU141D{0ou#SvG#NPSFfBRR}UqPu1g +zbp-0++5VQ;(~h2|{DpZq_w}s_$b9-~C-}mHNx2rVwJNvNm^t;m0sCjS)iyoStXUf9 +z$Q0vC8KT!$ua0@W+#Rs>_ES(fXLdHg +z!&mFz+-JomuB|g)k|sZ2ith_F;bSdTR@G7Qua>tSmEPEr*|AryoX#|v8n9qk{0KfW +z4cnKBYw05JDg2i>IPH8*?C$J`>#tJ$s?$NbFv(laOo?0Vt3=6@9nKm7C&w$W1V3r6 +zzRD%G1vxMc^Ai@zVz`Q=Znf_ukQ^wk{QQlr18iz7A=9=kPFyzjnFZEJdjmdY=;fK3 +zSZ8jUE+Dkoi_P+J!tnFy{@ +z1(@Gagb|O!9G0}H`t%vjH_GcMe6gV1#=JEEDoMdTIn523_z%wd1r-It5sOkr$K5qs +z8nMmC;rZpWbj0?7^_?;$;6uLe8EPWB7Zgi`I>&ib(q~;6oJ#1~A&~oHc^!qg0l2wd +zwHZD|lTh$(;P~L)2$sT$d +zItoWd8Jv3P*(Yi06j89$VrSv4KS3s)On?;(<2;_N!O$bk2HA1y!NYbov2sxAAMf$k +z$kd-Zq-%pL>Z><=ZO^dA>%nKwbL#25aN}!jTy>;3nt7o{VX*+Do7PwRrJ?Eeh)0xyi}P06fZ!J?W@DQ~{qG=T*1@LA +zwg15OA;$wMmc-UzpXt<^E7}HTI$Tb1&q96)aZU0M7Hq1%|6-%RHDFu+D=fboS5`CM +zF7Zm#HOxng)2S+Cu=!JFpRXld!3F)6hJDhFD;wWf^*-1i%HkC8SBO$V%Er9phtH}2 +zz#-g|E%Oix!OwZC(rOuqGF#tsl23($DTvC9Ax5HrNU%eECo@$wvG#dBh0=41LB!8; +za=PH_<SdqhHF)z@K4R5wWPXOC-ZQ!*k@ +z@tM<@)|^y)r?a>7K&KA3EPD}6T%<&`fv~98`*wtYxuk*7S87G{n&jabcKBIl{l)-d +z)4adVU{pZ6#4BFcFn=+3vehE;0!N{ +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 +zO460xWX;kzRB$Y`+7>cm{D*aQCw!xqv +z3IF+{m08$dm*q#*M{G-~gFreCj${2qMu}N5i~Xu}`!y2%PEMEC>U$$UA8l&Ihr(M- +z+gZtm1)2g-XfVsku{N+HX_(f&J~Qp3UBy1ZqxL$3jvH}{vQxqreydTazuridCxaQe +zyptMGI!9>p_@-r63H@HDv)^%J&-mf@v&-@xdejdwDJZG0Zn%_?YEN6JT7Kc>GW)!;^GTh;E!d#*nB(>-yVkj}TlivD15B +zL2ZuhJWMjH3cW|`)x=V;v6^4-l)nAf0}xx^Qsbu0j&$SrTH9q +zr`^sE7pb|=PY%2ESU7wCg2@m~Hcq_=sMSkj%3g8~jOl(Ap8w2$9x(TkB +zll)26t_&0g&il+NO0wGyiWl{Ro3Su+)zj +z@yQ>9@am`|nL-Lx)$5ZV +z??ZtpQvwiKA(JFJIYa-K)==(n%0TVc+X?IVG0sGBTMg!NP +z=*g7pe@}89tRLPp*%yuKytY3p2H`JSF#>1O`%ygfvwv~<_#_)#1P`lWdBVTP{&V@G*F%~JnS{t7R| +zbAbKx**;PJnjXKy%G=qGmx1rQ)Xz5)lwK~rgJ%7lI<)(&e@M#4y7}Fl$|*;uvq%An +zw5^Hwg}5Qm5($ulYFAO{YY!W^7X7(0-w(QE1b^_#54+Y{?5D%3N>oSPaJag69s6Y- +znlH#e`u}b^wyY@qK5+f-l^O-%H#2*U5}7eyJ2xYE2P)))J_{BoC-rOa=74 +zhbJZq|G#OJDKAk11yEDy?$Ettew%!xlk2*<(EgIt6wl}*>`$!df%>qX$QDlAp!Cl +z4qo=F9U?cip~pgheU}@ryL#Pg#y_F&T&XcR=ZMy!4KdX_lw~afH~;ij>&VSl!U@Kn +zTNWKxyC1z3GdGRkzZv^ZZkqB3yn^y_1U(~Xm2Q7XRByExWZy|&@NBI39+`$X_fAGU8rY&<_O*-O_XExJSA2qPD7kicu70Lpr0$rfP(dNnL@hx9JKNSYCR5hP0 +z8t^E~K3Yo+d&01_uv40lLc05uODxVeBbcdd9LqvMafvC^Ih?seJkfc_oipEsuh5quraEd8*xn!(Ty%a>UWA?3_29bV0kd!>&lqPe)QZ8!DWBSYIhN@!~#UHQy +zG~#!8Q@{f-7Lha-<5#*sho!IhL$$S8cQ?ay#i-NKo|CIO(tdeUz>W8#eO9FD$C3UU +zP(ZaONKHs)`1qD@suUrUrCLRuJN_{2s@BHMlg48Y8rUhq&&O7k!Du@3WP$0r>za!C +zmE)s+(4|P?a1_CgK4!L9XaVU%HR0Rm>?_fy+~omZXC&~fqDPQ*vrbDh0MCV7I2K`) +z5_VNv{5EEvu!nWYb(s_M+Mo}fPP0L +z@QgnB$6}D@t@1sRkg&Von0a~Z`fZ#7RnMhij|7sh3{X;#2b{vdrY}A^_#P9~*w9yF +z<7TQsaD&!fuS$7cY!ATzfPkh8bfDsy3SV6hOF}SlL69m0Z_xQJ406B!)_)KeZ1(E& +z8)s7~A{blMyoy9;+Y9J-b~rmJcRHFxJgn`UIJY0OmAOjHPx+7ewwBruJOs2on(w)s8HWF|R667t`en6} +z$CL+#EAwOlzgiPLvf$f;#Ijs10<_mcj&Lstrh>-kaA3)YqGk`hc@(3vOJ0{R^_{vub9)NnnKF&aqO^W@>?O28eg +zsp8$89!8|s#c)YU*xevhktuJ`xujCSee4=iWew@8xVO6DnceJ(xuwyp1X4agzTzMc +z2n-gO)UI{js6Z>{yjK@yJBO``%W!b4`0k&EV1*G(*F-Jp-|<(pr=fGYRv~Lg=bC60 +zQ#0}axbwtf#LdP>l-9^keFy{|KlZlgg|(RgVx@VkVqW-Qxs1KT +z8G0aby8BM`)ppm7t|YsH*LH*JvISoQUF6)&!7=mUkEjPXW3Dwe3|f5i$YHx~<5YpU +zC?_oON7}e4UqnqfcmM$p97(H3zc=wAz#m8%@^WaUPy2Dn|2^vB=6vrNog8FDL!p)_ +za2^Q^SK>lH{W4S(@IhNMY&+L%?ddmqnuVa?&SSGhGJ=6olGUsKeeJ%oyUcfL9#9=o +zH;3VcKdL;N7Cr?kVyB0o;EtMJ35JefV0Ovs)jOcvgE{`PN22q9>eX69Sj%x9Cb+R- +z2;3)62~p5mbmG4lCUUzOjYAv<>3cz}$3j~_OBEl|J$_(XMo2@}SmnOa?FXOdtqvGC=mR{E?#8o6n +z!Z*4<`9DqKLh}!Z-z~4aA1(F#H?-{EP!ryd*$;E7RB>*4D*|3pLooe}dtK;0k>sap +z@V8+CuknrH%@-t#Vd>v!xz>ULaL;}TgK&)$ZmLW=7~|MmPF8ONf%_MVw}b^Xd31om +zyAYzFSU2&cjX`<4PU7U}+tsnbyU;RIXe2OfhKqXpRwwcF_G1zA*BV!gcPwwUnfU@s +zoXh}Gy8J0OFd%74>|E~qX*sFkSuuV)h@J}&Fs1WrB~Chn;3bHx9(jPK0Q5J^k1ro3 +z+E-plLu{nikuTc{n0M3yHBjR^iQj%eK|U8iJ~d&}%?|@w*i)ckwIlhBrmUppVV5=% +zg8TCZRKA_$hA~x~9EUz%`;27-KgLr{n?E +zLR|ItziwJXV!ClHK{H2no_zb0{q6PkUa#BLvGeelRT_|fQ3XH`&U>zy5Fb?rry;h{ +z>(ZZhX^DH!Y=)UlP#Oq-XcgjInnuYqOylNLCy_E_o=ZTJ-Ld17m>Z3w9nPESYX=v^ +zX8~){dk=Wt4m9&HFXNA36`%^K0-#-O+y<#L2umGr2#1xY;q0zU=$ANQxmslY~PXQ2CY;`GhVcQ0{~T+)1!iPxw%I +zz<_q51s>+<9o!Vb`rY+L&hE(Rak9DZH_e?xob-#Kf@?V?t)%xJ5*P0r@C`|#-p9~eP +z1&`-M?iQkpR6RBtrS*Glg^i=*$0-edhFXO<8y>8>^$rpiG1ycrQtNDD65`Xw`no*U +z$^iW=U7#?Zzjq+~PpL<7us<`b1#eOwyDol9YQX;nGaZ*0cAC%q{w_}#(4Pa5i%*Pb +zYocndeZY~6Unv0kdO1Ta<4^ir-g|s--b{CW{O!(pCr(k``5QK2yc8A4%u{sDuEUNE +z;jaFt!v#ZAyGG~}&ay{JrO}mg+K;o!9yGit-r-zvv~#Q8Px-IYW%KQAxax`92nO0e +zLr;IRFx$lbIW=rpz3#Gw34!5My +zpWKjXRUK@9<}Sgte@YU1mY%P1qM=^wTM8Mn(7z#Ae-dT(!%%mN;&i5lFr>)AH7X}p +zK%mlZcT8jxA(~fVw&TtGujBagZ52)M;5VQCqE=?&ET6krp&dv*s5 +z!qeYVJoca=D_gj9%rrP{*_XHUd5CCmGPup7MtEkpSXH}FhZ`+iLyU=oXt)yxsh;&7 +zTXI)Ifp8ln;0}k`eipV)Woii1|Kmk%LRF*i4iU1uUMYAuIG%fx3wMoiwKEv>h%DG} +z`^rjFxZ&?V6@1!4KaMCJF#%Iaw*b{&rWHfm5!X;9_K)BcLA~h@EVN_c)7lFXc +zvo8-?*xbBA`srvQzXD6x{!f?#hxku=P2poOpI7B;Hg@|>##}Ln3Ql%5Lo`Hapl^4l +z(TvY{Mqof%|5iZLUIjp32+^2)(D0X(*89T`!u+0tTMBcdWfbtm*o3`E>GGF^b~K6m +zmHx(Wre7f0IL8KAWOxXQ@AM4qmeUZa0ez~SRb^03d5XwLEMMIKZa}4J^uxm^ +z-+VR<5vcT9R(qp|nX7vk&iU-J$GCdOlZtgDSHm%=Fk5}xq0)Uv#{f +zPOiGdIJ=z_1*C$S-qzAOJ%|;i7a4bU?jTUD!vXj%czvVh%rkUw-Y=M +zz#SCeE46d~vZ&+?Jh6tPb$f=YpAo!CL9df^3UA$y)p3Z*kn|@`Sek7FQbAcimv63t +zey5#ijX!3ps3q>T%3m&5M!(%ycg@Aw9vwUyx*^a@YO}QFW;Rw>@{bF(MRqn_?FyUo +z-92ziH-tw;B)329%^*N3C?MxH(_{ahyv{;UobuT9+`+@&e4r>w!9!8=xvnrTsL>1@YdV9B1aESWPGSg +zMN9!n1Mtq(1q$QUj;VcpJ_-35CK#JY4)e<{U$8MZr5`Sg^+`GZxZ1qlFw^N(+Im#y +zJQ2{G4Hu+}NS`LZRy-A@105(N;JydudZeRSE78^(Cir7AOi-MnHu(hVsD!Rlc1URt +z?tK8)YzRyCILzm@vKRMUkGQ}4vZFvozzeO6xc4onieMJGpfPkylN1kl7l7{Ua30VQ +z_7o|PMx)aD@p`Ze-o-i9dHEFG)o~B+Z;q$A%}5v2wOPw{e$%W3p+2wPYrkbWJQdjZ +zy9(f}d;E?gKg4uTc2N{;0~GgIN}kC#kspExp>}&sOm}o#{G-x{sFo +z*VU7W>p9p&|E6WPeB6qpL$|?sP%H?<(5p`lHYfW +zwLSZ{KJRJ;L)I$FFzU3krae}!50#^db!W~?@|Csw4{-}d@S8c&sKGS8IJex5H`FAA +zn4MjPh`eYVW0|S5NWlAfzp~ko#`xZPb9jT*JKDd)j@%ceF3+xJ{Qqa+ujeLr}$HTb6$voTjpEYB<^K)Voko=rZeH{&8{VLPCRuAYdq +z1IIm1j86i9$4do3tlSy7SK>K)Ec)r@2E)gVtAY}aUIeBL7$Vf>>KZsu@PU$~eY8{;2~ +z(ZZE*1{g|Z@?msB3(iML>R+)Qo%T5jVIj +zo6U_ueGh-i?>Ga^B??bDTj-1N%kVSlYuk8So<*j=mpB8ysl6=i`QZiYOX0n!kedt9 +zaPP~tl;+cMOBRnH>8W-0hFkQckSKd}IZ-%Mkv9wsokD^nH6QV-kO5usC+9frq=Nrw +zV$e7}bxN@K%32kUY0soor~}SU0*riAbi=Pt@8$JTx_ou}*`qee=KBn)+Q;7Mi@$ur +zTk7~VSYG|vLm$+G9n`~!_*E&l*UkBM{=550JA*Gc$L4p%jB&e?zE2%^k6mey4p3HT +zr?Qj{f-G(8;e{pE^0xntrZfILsSXX~-jVdj>&Xx~#-gd^tt3U@$Yuae!ccq<$;ddt +zAh6so9_lImA892EeWh9(a+|X3BpugAI+Hh92xx&!1hC_O +zH9N>8q1l$r%^6x#O;Q>AR>bfTJifM+250T5E*)qP +zZR;4Srgsh4Y@8KR9s`SThe=mSm@1AhC#vK@ +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 +zSj8d?KuLAZUmDb{r^H=lBVpMbmn_C$g=hfn` +zP-3&)A@sHB#fcPH_j3l|6!dG3nAd8&F%frI#g&h>;T}zD44;x`bsMF-BQ93-Hnpl( +zPXCy5VXqT)wI9E;3P1^gs*<#Ll0O?)S@N{A{Lz%g@bQh;QvG1dtTTqMEjz*tvAEsK +zA4z{anrvD{D}Poai!uS@@0h|YmLvLvX@aXeGGKHS{u2KU1$C;iI}8L7Ew!6vcf<^3^9At1*y +z;Cx(V3GDHK7rMc}&zvke&(8lsvl?7+NfLcM*LS=y|JKEJ)5TqT7OzuT7O}aBL(pR)6CFQG| +z1nGia6l&6Y75^cWY`TSYht)^_K)f4!GfFkYa7uiV4qs3^9 +z0$ma+yqyvr**w|xHeeJ6TK|&fwpLEvq?hzsP;X)deQrA?b57Yg4xwT3ZExDRWnG2^ +zk61=`R-zc~lD=+im|MC>b${m-+$dnV5I{+Cie90_qqJCu+k|o#;&`Lq?$a~EV!c{w +z4aQ5?h31lir)^Kpyq$7P@T;Y?yrqn;2CdJ~KxjAp+H2*xkfNN=_EjnC?TKl+8B*n- +z5J{3FRdF9tYcI8BA~9#b7q<_f2)rrtoxx?!rlNE}Hh^SZHT^{#YW4Mt)#$63)QY0P +z`*iIi>jD8$D^uxBtjpZYCloO%k;B&V-gs@jiu3WknQ=C8eio1XeE~TE81in@O5Y)fht2Qgz}Z@VHLQ6 +zt2Z1asy)Xqk5*;z`F)jY%kd@dvv;Yo|9~`S>PfOnvu#H6V^UDtYRi2->gt&BA0F=V +zUA>qq!~oV&0w^g?xj4$y9J-V4PsdeGyUYu}^!4`0IWklBx#&nfjs}cw{5hm9cw>pA +zx|AuT7-E0;4sMvC@{$fD@UphlI*&HIUYw%8Guy`Om2 +zV>4THHh>EU2;jVa^?dGZn~#*%X+O$Rn0vJ>k#Qa{NFebXcFtoK*5>E)gXVG*ki{3KQtSnA| +z_WKO*!8vZqC)k!-?3Py^nla$(b3#%AoNo^#Z*fs%#!@VZp#32OeCU{|Uii|`7_@;~ +z?B@QEOjydT*{Y+u-v%3IH4@x6Um%+uS_U|W39u)HLyh8|hPAofC? +z^LFGXw^L@1l{K76EBgM3z7Z5L&|rF3fL&)jR@`cZr?PuHTlrc1{Q(nG>-g&*_78nZ +zIy0HSil0P~rJ?HL=NcM=m9vE|hWQn>$$Z3lbXH=iOZ%#EgSurpF(1ys5MWPYhT`Yi +zQZ=VhJ0T)nRr6a`6S27$%@(6>{j%oS8E^LvML%y%=E@yDg67IV09@rBg<9hQoVlno +zWWf6I?MXj9jxp%TO+~rHqqD_x9zGwCd0obwCHRdp0^DT>kj+wd2;4n(@;n5 +z=q5#JlBB$H^MiXr2gCe3jqUZmD-K4fvHC32CM|25bMO$w*Rh{$6-qC<$+PJ(}dV*1zzbBsn+3cX<@Y +zuT^zbY8|7voYHlUFbnIuHfEvJ|p=hV`TE6 +z!uC3DXh6`L9$U@XMN}8@^hj`F4^?aGH#pyoAWKVkpEn4ti1Z!N7q{5N6>eO>ij7}> +z8f(Drs>lw~4ockoTE^8_WHezZ3Cqst7yl(=-=8vDRzGGCaiyUL0jNYI2)PZ@Gvj8v +zxj$-br*n(%C5C(6i3|(c7=$e54E6CiL)T+Mm&d)at`F);5}O=1HtnvqJ;hTl>%!8F +z!LTa<{KyrSGzlAuuhfLitPk53E%Hkj2%Br%#%h$|TXLTbrh{LE=J`H7xo^YG +zbL@Q;^ns6qi=J+1%c+DjZZ){(_gGRrpdBRujRVulIw!c^;0NM{ +zQ`qMK-Ab{b}@du>KMd|Kicdl-ng(!FuhHe18>bf^J=-S +z%?NZaG2r~1ya%+H)Y>=YkNtJZD|a&+?@0RZpk;{sd3hEfA0WWUf3(%|i&Kxj#ku+` +zmsj>1Q!M*3pkrCEp#Y^wB-p_~gE$sm-n|3!tF8K|NMHQHZoo53Q2bk8#@?S`?;#mY +zG2r|kc@M7jG(>+(zaeQ14!vMBOIbF_L{qfk7_#dfiL;#aKmzMP!PkVPyChz6(2B>f +zVA1FZ5_(_9=xPbgmj$d-1mJk>{A>LMeO|cXL`7peT{1?8C@xK~F68xkZv-3`18~$Q +zmI>B6f$!O0ZOU*gvp$}gl$g_b4)4tODFGKE614UPPu|_8X0vdQRGd9Gb!570vTGwj +zo<$2Z=^xSnmn;b|^6@;?n}$XYVyi@LBl_XIj5d=M$*Jpngkv&WVk##+TI`s%`(8@w +znH?i{NyW)?Gn9M%i=NgH&A7V3R;!9TFd%k7g4XTfy!rDA?-p+?b=3FZBcwN5NP!9m +zbx8ss-EG-ar53&D#m;Wh@W{x?F{W7dTN+8p_Iuy93p~kX01mNDq57=Hr~Cw)@bYxG +z>A?3ZzV^_lK3#Ro}2C-qBZ$wC=(Hh!y!z3usD?)o=aW*psN_8!=vnam4CN&sVr1V!7k_KUncewlLHN6Aaj|J%MzJx3XbJ}rc>DzdP}k`w +z=Upk^NQDSbF#H_U(1r$NXnv(v3Zj@c%O+Hav>jb}%XQEjO$MCbS-EhH88Ow=er-2) +zO(b&Hjh7!wmtF@24BTICCQl2DR~wxd}sax +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 diff --git a/patches/server/0015-Added-linear-region-format-from-LinearPurpur.patch b/patches/server/0015-Added-linear-region-format-from-LinearPurpur.patch new file mode 100644 index 0000000..6b27c92 --- /dev/null +++ b/patches/server/0015-Added-linear-region-format-from-LinearPurpur.patch @@ -0,0 +1,1003 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: MrHua269 +Date: Thu, 27 Jun 2024 18:25:12 +0800 +Subject: [PATCH] Added linear region format from LinearPurpur + +Diff from linear purpur: + Run I/O operations on region file I/O threads instead of using their own linear flusher + Use a simple long to calc if it need to flush to the disk + More simpler linear file checks + +diff --git a/build.gradle.kts b/build.gradle.kts +index ab07c307bea0d3b79a6239bdcca9714e1ddf3b28..0f543eccedc7191f8c391583af30231c8b68b2a4 100644 +--- a/build.gradle.kts ++++ b/build.gradle.kts +@@ -31,6 +31,10 @@ dependencies { + alsoShade(log4jPlugins.output) + implementation("io.netty:netty-codec-haproxy:4.1.97.Final") // Paper - Add support for proxy protocol + // Paper end ++ // LinearPaper start ++ implementation("com.github.luben:zstd-jni:1.5.6-3") ++ implementation("org.lz4:lz4-java:1.8.0") ++ // LinearPaper end + implementation("org.apache.logging.log4j:log4j-iostreams:2.22.1") // Paper - remove exclusion + implementation("org.ow2.asm:asm-commons:9.7") + implementation("org.spongepowered:configurate-yaml:4.2.0-SNAPSHOT") // Paper - config files +diff --git a/src/main/java/io/papermc/paper/chunk/system/io/RegionFileIOThread.java b/src/main/java/io/papermc/paper/chunk/system/io/RegionFileIOThread.java +index 2096e57c025858519e7c46788993b9aac1ec60e8..9c8a3749c09ca4f5389cc9d240f713f0a12badee 100644 +--- a/src/main/java/io/papermc/paper/chunk/system/io/RegionFileIOThread.java ++++ b/src/main/java/io/papermc/paper/chunk/system/io/RegionFileIOThread.java +@@ -1077,9 +1077,9 @@ public final class RegionFileIOThread extends PrioritisedQueueExecutorThread { + return this.getCache().doesRegionFileNotExistNoIO(new ChunkPos(chunkX, chunkZ)); + } + +- public T computeForRegionFile(final int chunkX, final int chunkZ, final boolean existingOnly, final Function function) { ++ public T computeForRegionFile(final int chunkX, final int chunkZ, final boolean existingOnly, final Function function) { // LinearPaper + final RegionFileStorage cache = this.getCache(); +- final RegionFile regionFile; ++ final org.stupidcraft.linearpaper.region.AbstractRegionFile regionFile; // LinearPaper + synchronized (cache) { + try { + regionFile = cache.getRegionFile(new ChunkPos(chunkX, chunkZ), existingOnly, true); +@@ -1092,19 +1092,19 @@ public final class RegionFileIOThread extends PrioritisedQueueExecutorThread { + return function.apply(regionFile); + } finally { + if (regionFile != null) { +- regionFile.fileLock.unlock(); ++ regionFile.getFileLock().unlock(); // LinearPaper + } + } + } + +- public T computeForRegionFileIfLoaded(final int chunkX, final int chunkZ, final Function function) { ++ public T computeForRegionFileIfLoaded(final int chunkX, final int chunkZ, final Function function) { // LinearPaper + final RegionFileStorage cache = this.getCache(); +- final RegionFile regionFile; ++ final org.stupidcraft.linearpaper.region.AbstractRegionFile regionFile; // LinearPaper + + synchronized (cache) { + regionFile = cache.getRegionFileIfLoaded(new ChunkPos(chunkX, chunkZ)); + if (regionFile != null) { +- regionFile.fileLock.lock(); ++ regionFile.getFileLock().lock(); // LinearPaper + } + } + +@@ -1112,7 +1112,7 @@ public final class RegionFileIOThread extends PrioritisedQueueExecutorThread { + return function.apply(regionFile); + } finally { + if (regionFile != null) { +- regionFile.fileLock.unlock(); ++ regionFile.getFileLock().unlock(); // LinearPaper + } + } + } +diff --git a/src/main/java/me/earthme/luminol/config/modules/misc/RegionFormatConfig.java b/src/main/java/me/earthme/luminol/config/modules/misc/RegionFormatConfig.java +new file mode 100644 +index 0000000000000000000000000000000000000000..e0adfc6422f8db2c2bb81cbe8257f049a5334c93 +--- /dev/null ++++ b/src/main/java/me/earthme/luminol/config/modules/misc/RegionFormatConfig.java +@@ -0,0 +1,52 @@ ++package me.earthme.luminol.config.modules.misc; ++ ++import com.electronwill.nightconfig.core.file.CommentedFileConfig; ++import com.mojang.logging.LogUtils; ++import me.earthme.luminol.config.ConfigInfo; ++import me.earthme.luminol.config.DoNotLoad; ++import me.earthme.luminol.config.EnumConfigCategory; ++import me.earthme.luminol.config.IConfigModule; ++import org.slf4j.Logger; ++import org.stupidcraft.linearpaper.region.EnumRegionFileExtension; ++ ++public class RegionFormatConfig implements IConfigModule { ++ @ConfigInfo(baseName = "region_format") ++ public static String regionFormatTypeName = "MCA"; ++ @DoNotLoad ++ public static EnumRegionFileExtension regionFormatType = EnumRegionFileExtension.LINEAR; ++ @ConfigInfo(baseName = "linear_compress_level") ++ public static int linearCompressionLevel = 1; ++ @ConfigInfo(baseName = "thrown_on_unknown_extension_detected") ++ public static boolean throwOnUnknownExtension = false; ++ @ConfigInfo(baseName = "flush_every_seconds") ++ public static int linearFlushFrequency = 5; ++ ++ @DoNotLoad ++ private static final Logger logger = LogUtils.getLogger(); ++ ++ @Override ++ public EnumConfigCategory getCategory() { ++ return EnumConfigCategory.MISC; ++ } ++ ++ @Override ++ public String getBaseName() { ++ return "region_format_settings"; ++ } ++ ++ @Override ++ public void onLoaded(CommentedFileConfig configInstance) { ++ regionFormatType = EnumRegionFileExtension.fromName(regionFormatTypeName); ++ if (regionFormatType == EnumRegionFileExtension.UNKNOWN){ ++ logger.error("Unknown region file type {} !Falling back to MCA file.", regionFormatTypeName); ++ regionFormatType = EnumRegionFileExtension.MCA; ++ } ++ ++ if (linearCompressionLevel > 23 || linearCompressionLevel < 1) { ++ logger.error("Linear region compression level should be between 1 and 22 in config: {}", linearCompressionLevel); ++ logger.error("Falling back to compression level 1."); ++ linearCompressionLevel = 1; ++ } ++ ++ } ++} +diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java +index ac0312d5d496ee5599ff6b002196d98b42385309..e60c8fd49d01a5acb1054b8eebc85612b8192884 100644 +--- a/src/main/java/net/minecraft/server/MinecraftServer.java ++++ b/src/main/java/net/minecraft/server/MinecraftServer.java +@@ -923,7 +923,7 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop> progressMap = Reference2FloatMaps.synchronize(new Reference2FloatOpenHashMap()); + volatile Component status = Component.translatable("optimizeWorld.stage.counting"); +- static final Pattern REGEX = Pattern.compile("^r\\.(-?[0-9]+)\\.(-?[0-9]+)\\.mca$"); ++ static final Pattern REGEX = Pattern.compile("^r\\.(-?[0-9]+)\\.(-?[0-9]+)\\.(linear | mca)$"); // LinearPaper + final DimensionDataStorage overworldDataStorage; + + public WorldUpgrader(LevelStorageSource.LevelStorageAccess session, DataFixer dataFixer, RegistryAccess dynamicRegistryManager, boolean eraseCache, boolean recreateRegionFiles) { +@@ -344,7 +344,7 @@ public class WorldUpgrader { + if (flag1) { + this.onFileFinished(worldupgrader_e.file); + } else { +- WorldUpgrader.LOGGER.error("Failed to convert region file {}", worldupgrader_e.file.getPath()); ++ WorldUpgrader.LOGGER.error("Failed to convert region file {}", worldupgrader_e.file.getRegionFile()); // LinearPaper + } + } + } +@@ -406,7 +406,7 @@ public class WorldUpgrader { + + private static List getAllChunkPositions(RegionStorageInfo key, Path regionDirectory) { + File[] afile = regionDirectory.toFile().listFiles((file, s) -> { +- return s.endsWith(".mca"); ++ return s.endsWith(".linear") || s.endsWith(".mca"); // LinearPaper + }); + + if (afile == null) { +@@ -426,7 +426,7 @@ public class WorldUpgrader { + List list1 = Lists.newArrayList(); + + try { +- RegionFile regionfile = new RegionFile(key, file.toPath(), regionDirectory, true); ++ org.stupidcraft.linearpaper.region.AbstractRegionFile regionfile = org.stupidcraft.linearpaper.region.AbstractRegionFileFactory.getAbstractRegionFile(key, file.toPath(), regionDirectory, true); // LinearPaper + + try { + for (int i1 = 0; i1 < 32; ++i1) { +@@ -489,13 +489,13 @@ public class WorldUpgrader { + + protected abstract boolean tryProcessOnePosition(T storage, ChunkPos chunkPos, ResourceKey worldKey); + +- private void onFileFinished(RegionFile regionFile) { ++ private void onFileFinished(org.stupidcraft.linearpaper.region.AbstractRegionFile regionFile) { // LinearPaper + if (WorldUpgrader.this.recreateRegionFiles) { + if (this.previousWriteFuture != null) { + this.previousWriteFuture.join(); + } + +- Path path = regionFile.getPath(); ++ Path path = regionFile.getRegionFile(); // LinearPaper + Path path1 = path.getParent(); + Path path2 = WorldUpgrader.resolveRecreateDirectory(path1).resolve(path.getFileName().toString()); + +@@ -514,7 +514,7 @@ public class WorldUpgrader { + } + } + +- static record FileToUpgrade(RegionFile file, List chunksToUpgrade) { ++ static record FileToUpgrade(org.stupidcraft.linearpaper.region.AbstractRegionFile file, List chunksToUpgrade) { // LinearPaper + + } + +diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java +index 1362a47943cf1a51a185a15094b1f74c94bf40ef..340b9d9fdfa54b7bef05b8ca47b8f3c2a6e31f17 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java ++++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFile.java +@@ -28,7 +28,7 @@ import net.minecraft.nbt.NbtIo; // Paper + import net.minecraft.world.level.ChunkPos; + import org.slf4j.Logger; + +-public class RegionFile implements AutoCloseable { ++public class RegionFile implements AutoCloseable, org.stupidcraft.linearpaper.region.AbstractRegionFile { // LinearPaper + + private static final Logger LOGGER = LogUtils.getLogger(); + private static final int SECTOR_BYTES = 4096; +@@ -59,6 +59,15 @@ public class RegionFile implements AutoCloseable { + long sign = -remainingBytes; // sign is 1 if nonzero + return sectors + (sign >>> 63); + } ++ ++ // LinearPaper start - Abstract getters ++ public Path getRegionFile() { ++ return this.path; ++ } ++ public java.util.concurrent.locks.ReentrantLock getFileLock() { ++ return this.fileLock; ++ } ++ // LinearPaper end + + private static final CompoundTag OVERSIZED_COMPOUND = new CompoundTag(); + +@@ -130,7 +139,7 @@ public class RegionFile implements AutoCloseable { + } + + // note: only call for CHUNK regionfiles +- boolean recalculateHeader() throws IOException { ++ public boolean recalculateHeader() throws IOException { // LinearPaper + if (!this.canRecalcHeader) { + return false; + } +@@ -972,10 +981,10 @@ public class RegionFile implements AutoCloseable { + private static int getChunkIndex(int x, int z) { + return (x & 31) + (z & 31) * 32; + } +- synchronized boolean isOversized(int x, int z) { ++ public synchronized boolean isOversized(int x, int z) { // LinearPaper + return this.oversized[getChunkIndex(x, z)] == 1; + } +- synchronized void setOversized(int x, int z, boolean oversized) throws IOException { ++ public synchronized void setOversized(int x, int z, boolean oversized) throws IOException { // LinearPaper + final int offset = getChunkIndex(x, z); + boolean previous = this.oversized[offset] == 1; + this.oversized[offset] = (byte) (oversized ? 1 : 0); +@@ -1014,7 +1023,7 @@ public class RegionFile implements AutoCloseable { + return this.path.getParent().resolve(this.path.getFileName().toString().replaceAll("\\.mca$", "") + "_oversized_" + x + "_" + z + ".nbt"); + } + +- synchronized CompoundTag getOversizedData(int x, int z) throws IOException { ++ public synchronized CompoundTag getOversizedData(int x, int z) throws IOException { // LinearPaper + Path file = getOversizedFile(x, z); + try (DataInputStream out = new DataInputStream(new java.io.BufferedInputStream(new InflaterInputStream(Files.newInputStream(file))))) { + return NbtIo.read((java.io.DataInput) out); +diff --git a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java +index 1090b7e36e3c1c105bc36135b82751c651f237d4..329d4f5b5123d9d02b7c60046e28d1241e66425b 100644 +--- a/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java ++++ b/src/main/java/net/minecraft/world/level/chunk/storage/RegionFileStorage.java +@@ -21,7 +21,7 @@ public class RegionFileStorage implements AutoCloseable { + + public static final String ANVIL_EXTENSION = ".mca"; + private static final int MAX_CACHE_SIZE = 256; +- public final Long2ObjectLinkedOpenHashMap regionCache = new Long2ObjectLinkedOpenHashMap(); ++ public final Long2ObjectLinkedOpenHashMap regionCache = new Long2ObjectLinkedOpenHashMap(); // LinearPaper + private final RegionStorageInfo info; + private final Path folder; + private final boolean sync; +@@ -72,7 +72,7 @@ public class RegionFileStorage implements AutoCloseable { + @Nullable + public static ChunkPos getRegionFileCoordinates(Path file) { + String fileName = file.getFileName().toString(); +- if (!fileName.startsWith("r.") || !fileName.endsWith(".mca")) { ++ if (!fileName.startsWith("r.") || !fileName.endsWith(".linear") || !fileName.endsWith(".mca")) { // LinearPaper + return null; + } + +@@ -94,29 +94,29 @@ public class RegionFileStorage implements AutoCloseable { + // Paper end + + // Paper start +- public synchronized RegionFile getRegionFileIfLoaded(ChunkPos chunkcoordintpair) { ++ public synchronized org.stupidcraft.linearpaper.region.AbstractRegionFile getRegionFileIfLoaded(ChunkPos chunkcoordintpair) { // LinearPaper + return this.regionCache.getAndMoveToFirst(ChunkPos.asLong(chunkcoordintpair.getRegionX(), chunkcoordintpair.getRegionZ())); + } + + public synchronized boolean chunkExists(ChunkPos pos) throws IOException { +- RegionFile regionfile = getRegionFile(pos, true); ++ org.stupidcraft.linearpaper.region.AbstractRegionFile regionfile = getRegionFile(pos, true); // LinearPaper + + return regionfile != null ? regionfile.hasChunk(pos) : false; + } + +- public synchronized RegionFile getRegionFile(ChunkPos chunkcoordintpair, boolean existingOnly) throws IOException { // CraftBukkit ++ public synchronized org.stupidcraft.linearpaper.region.AbstractRegionFile getRegionFile(ChunkPos chunkcoordintpair, boolean existingOnly) throws IOException { // CraftBukkit // LinearPaper + return this.getRegionFile(chunkcoordintpair, existingOnly, false); + } +- public synchronized RegionFile getRegionFile(ChunkPos chunkcoordintpair, boolean existingOnly, boolean lock) throws IOException { ++ public synchronized org.stupidcraft.linearpaper.region.AbstractRegionFile getRegionFile(ChunkPos chunkcoordintpair, boolean existingOnly, boolean lock) throws IOException { // LinearPaper + // Paper end + long i = ChunkPos.asLong(chunkcoordintpair.getRegionX(), chunkcoordintpair.getRegionZ()); final long regionPos = i; // Paper - OBFHELPER +- RegionFile regionfile = (RegionFile) this.regionCache.getAndMoveToFirst(i); ++ org.stupidcraft.linearpaper.region.AbstractRegionFile regionfile = (org.stupidcraft.linearpaper.region.AbstractRegionFile) this.regionCache.getAndMoveToFirst(i); // LinearPaper + + if (regionfile != null) { + // Paper start + if (lock) { + // must be in this synchronized block +- regionfile.fileLock.lock(); ++ regionfile.getFileLock().lock(); // LinearPaper + } + // Paper end + return regionfile; +@@ -127,28 +127,37 @@ public class RegionFileStorage implements AutoCloseable { + } + // Paper end - cache regionfile does not exist state + if (this.regionCache.size() >= io.papermc.paper.configuration.GlobalConfiguration.get().misc.regionFileCacheSize) { // Paper - Sanitise RegionFileCache and make configurable +- ((RegionFile) this.regionCache.removeLast()).close(); ++ ((org.stupidcraft.linearpaper.region.AbstractRegionFile) this.regionCache.removeLast()).close(); // LinearPaper + } + + // Paper - only create directory if not existing only - moved down + Path path = this.folder; + int j = chunkcoordintpair.getRegionX(); +- Path path1 = path.resolve("r." + j + "." + chunkcoordintpair.getRegionZ() + ".mca"); // Paper - diff on change +- if (existingOnly && !java.nio.file.Files.exists(path1)) { // Paper start - cache regionfile does not exist state +- this.markNonExisting(regionPos); +- return null; // CraftBukkit ++ // LinearPaper start ++ Path path1; ++ if (existingOnly) { ++ Path linear = path.resolve("r." + j + "." + chunkcoordintpair.getRegionZ() + ".linear"); ++ Path anvil = path.resolve("r." + j + "." + chunkcoordintpair.getRegionZ() + ".mca"); ++ path1 = java.nio.file.Files.exists(linear) ? linear : java.nio.file.Files.exists(anvil) ? anvil : null; ++ if (path1 == null) { ++ this.markNonExisting(regionPos); ++ return null; // CraftBukkit ++ } + } else { ++ String extension = me.earthme.luminol.config.modules.misc.RegionFormatConfig.regionFormatType.getExtensionName(); ++ path1 = path.resolve("r." + j + "." + chunkcoordintpair.getRegionZ() + extension); ++ // LinearPaper end + this.createRegionFile(regionPos); + } + // Paper end - cache regionfile does not exist state + FileUtil.createDirectoriesSafe(this.folder); // Paper - only create directory if not existing only - moved from above +- RegionFile regionfile1 = new RegionFile(this.info, path1, this.folder, this.sync, this.isChunkData); // Paper - allow for chunk regionfiles to regen header ++ org.stupidcraft.linearpaper.region.AbstractRegionFile regionfile1 = org.stupidcraft.linearpaper.region.AbstractRegionFileFactory.getAbstractRegionFile(this.info, path1, this.folder, this.sync, this.isChunkData); // Paper - allow for chunk regionfiles to regen header // LinearPaper + + this.regionCache.putAndMoveToFirst(i, regionfile1); + // Paper start + if (lock) { + // must be in this synchronized block +- regionfile1.fileLock.lock(); ++ regionfile1.getFileLock().lock(); // LinearPaper + } + // Paper end + return regionfile1; +@@ -160,7 +169,7 @@ public class RegionFileStorage implements AutoCloseable { + org.apache.logging.log4j.LogManager.getLogger().fatal(msg + " (" + file.toString().replaceAll(".+[\\\\/]", "") + " - " + x + "," + z + ") Go clean it up to remove this message. /minecraft:tp " + (x<<4)+" 128 "+(z<<4) + " - DO NOT REPORT THIS TO PAPER - You may ask for help on Discord, but do not file an issue. These error messages can not be removed."); + } + +- private static CompoundTag readOversizedChunk(RegionFile regionfile, ChunkPos chunkCoordinate) throws IOException { ++ private static CompoundTag readOversizedChunk(org.stupidcraft.linearpaper.region.AbstractRegionFile regionfile, ChunkPos chunkCoordinate) throws IOException { // LinearPaper + synchronized (regionfile) { + try (DataInputStream datainputstream = regionfile.getChunkDataInputStream(chunkCoordinate)) { + CompoundTag oversizedData = regionfile.getOversizedData(chunkCoordinate.x, chunkCoordinate.z); +@@ -195,14 +204,14 @@ public class RegionFileStorage implements AutoCloseable { + @Nullable + public CompoundTag read(ChunkPos pos) throws IOException { + // CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing +- RegionFile regionfile = this.getRegionFile(pos, true, true); // Paper ++ org.stupidcraft.linearpaper.region.AbstractRegionFile regionfile = this.getRegionFile(pos, true, true); // Paper // LinearPaper + if (regionfile == null) { + return null; + } + // Paper start - Add regionfile parameter + return this.read(pos, regionfile); + } +- public CompoundTag read(ChunkPos pos, RegionFile regionfile) throws IOException { ++ public CompoundTag read(ChunkPos pos, org.stupidcraft.linearpaper.region.AbstractRegionFile regionfile) throws IOException { // LinearPaper + // We add the regionfile parameter to avoid the potential deadlock (on fileLock) if we went back to obtain a regionfile + // if we decide to re-read + // Paper end +@@ -212,7 +221,7 @@ public class RegionFileStorage implements AutoCloseable { + + // Paper start + if (regionfile.isOversized(pos.x, pos.z)) { +- printOversizedLog("Loading Oversized Chunk!", regionfile.getPath(), pos.x, pos.z); ++ printOversizedLog("Loading Oversized Chunk!", regionfile.getRegionFile(), pos.x, pos.z); // LinearPaper + return readOversizedChunk(regionfile, pos); + } + // Paper end +@@ -226,12 +235,12 @@ public class RegionFileStorage implements AutoCloseable { + if (this.isChunkData) { + ChunkPos chunkPos = ChunkSerializer.getChunkCoordinate(nbttagcompound); + if (!chunkPos.equals(pos)) { +- net.minecraft.server.MinecraftServer.LOGGER.error("Attempting to read chunk data at " + pos + " but got chunk data for " + chunkPos + " instead! Attempting regionfile recalculation for regionfile " + regionfile.getPath().toAbsolutePath()); ++ net.minecraft.server.MinecraftServer.LOGGER.error("Attempting to read chunk data at " + pos + " but got chunk data for " + chunkPos + " instead! Attempting regionfile recalculation for regionfile " + regionfile.getRegionFile().toAbsolutePath()); // LinearPaper + if (regionfile.recalculateHeader()) { +- regionfile.fileLock.lock(); // otherwise we will unlock twice and only lock once. ++ regionfile.getFileLock().lock(); // otherwise we will unlock twice and only lock once. // LinearPaper + return this.read(pos, regionfile); + } +- net.minecraft.server.MinecraftServer.LOGGER.error("Can't recalculate regionfile header, regenerating chunk " + pos + " for " + regionfile.getPath().toAbsolutePath()); ++ net.minecraft.server.MinecraftServer.LOGGER.error("Can't recalculate regionfile header, regenerating chunk " + pos + " for " + regionfile.getRegionFile().toAbsolutePath()); // LinearPaper + return null; + } + } +@@ -265,13 +274,13 @@ public class RegionFileStorage implements AutoCloseable { + + return nbttagcompound; + } finally { // Paper start +- regionfile.fileLock.unlock(); ++ regionfile.getFileLock().unlock(); // LinearPaper + } // Paper end + } + + public void scanChunk(ChunkPos chunkPos, StreamTagVisitor scanner) throws IOException { + // CraftBukkit start - SPIGOT-5680: There's no good reason to preemptively create files on read, save that for writing +- RegionFile regionfile = this.getRegionFile(chunkPos, true); ++ org.stupidcraft.linearpaper.region.AbstractRegionFile regionfile = this.getRegionFile(chunkPos, true); // LinearPaper + if (regionfile == null) { + return; + } +@@ -302,7 +311,7 @@ public class RegionFileStorage implements AutoCloseable { + + protected void write(ChunkPos pos, @Nullable CompoundTag nbt) throws IOException { + // Paper start - rewrite chunk system +- RegionFile regionfile = this.getRegionFile(pos, nbt == null, true); // CraftBukkit ++ org.stupidcraft.linearpaper.region.AbstractRegionFile regionfile = this.getRegionFile(pos, nbt == null, true); // CraftBukkit // LinearPaper + if (nbt == null && regionfile == null) { + return; + } +@@ -357,7 +366,7 @@ public class RegionFileStorage implements AutoCloseable { + // Paper end - Chunk save reattempt + // Paper start - rewrite chunk system + } finally { +- regionfile.fileLock.unlock(); ++ regionfile.getFileLock().unlock(); // LinearPaper + } + // Paper end - rewrite chunk system + } +@@ -367,7 +376,7 @@ public class RegionFileStorage implements AutoCloseable { + ObjectIterator objectiterator = this.regionCache.values().iterator(); + + while (objectiterator.hasNext()) { +- RegionFile regionfile = (RegionFile) objectiterator.next(); ++ org.stupidcraft.linearpaper.region.AbstractRegionFile regionfile = (org.stupidcraft.linearpaper.region.AbstractRegionFile) objectiterator.next(); // LinearPaper + + try { + regionfile.close(); +@@ -383,7 +392,7 @@ public class RegionFileStorage implements AutoCloseable { + ObjectIterator objectiterator = this.regionCache.values().iterator(); + + while (objectiterator.hasNext()) { +- RegionFile regionfile = (RegionFile) objectiterator.next(); ++ org.stupidcraft.linearpaper.region.AbstractRegionFile regionfile = (org.stupidcraft.linearpaper.region.AbstractRegionFile) objectiterator.next(); // LinearPaper + + regionfile.flush(); + } +diff --git a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +index 0a14c9ae6dc9daeeb370eee1da7fc5fc2472d480..53d0481d349b4c9c0ddbe8242532f7195866421b 100644 +--- a/src/main/java/org/bukkit/craftbukkit/CraftWorld.java ++++ b/src/main/java/org/bukkit/craftbukkit/CraftWorld.java +@@ -611,7 +611,7 @@ public class CraftWorld extends CraftRegionAccessor implements World { + world.getChunk(x, z); // make sure we're at ticket level 32 or lower + return true; + } +- net.minecraft.world.level.chunk.storage.RegionFile file; ++ org.stupidcraft.linearpaper.region.AbstractRegionFile file; // LinearPaper + try { + file = world.getChunkSource().chunkMap.regionFileCache.getRegionFile(chunkPos, false); + } catch (java.io.IOException ex) { +diff --git a/src/main/java/org/stupidcraft/linearpaper/region/AbstractRegionFile.java b/src/main/java/org/stupidcraft/linearpaper/region/AbstractRegionFile.java +new file mode 100644 +index 0000000000000000000000000000000000000000..1325ac1d603bc65224860170b5ffad3f8cca2e9c +--- /dev/null ++++ b/src/main/java/org/stupidcraft/linearpaper/region/AbstractRegionFile.java +@@ -0,0 +1,30 @@ ++package org.stupidcraft.linearpaper.region; ++ ++import java.io.DataInputStream; ++import java.io.DataOutputStream; ++import java.io.IOException; ++import java.nio.file.Path; ++import java.util.concurrent.locks.ReentrantLock; ++import net.minecraft.nbt.CompoundTag; ++import net.minecraft.world.level.ChunkPos; ++import net.minecraft.world.level.chunk.status.ChunkStatus; ++ ++public interface AbstractRegionFile { ++ void flush() throws IOException; ++ void clear(ChunkPos pos) throws IOException; ++ void close() throws IOException; ++ void setStatus(int x, int z, ChunkStatus status); ++ void setOversized(int x, int z, boolean b) throws IOException; ++ ++ boolean hasChunk(ChunkPos pos); ++ boolean doesChunkExist(ChunkPos pos) throws Exception; ++ boolean isOversized(int x, int z); ++ boolean recalculateHeader() throws IOException; ++ ++ DataOutputStream getChunkDataOutputStream(ChunkPos pos) throws IOException; ++ DataInputStream getChunkDataInputStream(ChunkPos pos) throws IOException; ++ CompoundTag getOversizedData(int x, int z) throws IOException; ++ ChunkStatus getStatusIfCached(int x, int z); ++ ReentrantLock getFileLock(); ++ Path getRegionFile(); ++} +diff --git a/src/main/java/org/stupidcraft/linearpaper/region/AbstractRegionFileFactory.java b/src/main/java/org/stupidcraft/linearpaper/region/AbstractRegionFileFactory.java +new file mode 100644 +index 0000000000000000000000000000000000000000..3d0f1a7a926253f87a5c35bddb56bce0d261bd8c +--- /dev/null ++++ b/src/main/java/org/stupidcraft/linearpaper/region/AbstractRegionFileFactory.java +@@ -0,0 +1,51 @@ ++package org.stupidcraft.linearpaper.region; ++ ++import java.io.IOException; ++import java.nio.file.Path; ++ ++import me.earthme.luminol.config.modules.misc.RegionFormatConfig; ++import net.minecraft.world.level.chunk.storage.RegionFile; ++import net.minecraft.world.level.chunk.storage.RegionFileVersion; ++import net.minecraft.world.level.chunk.storage.RegionStorageInfo; ++import org.jetbrains.annotations.Contract; ++import org.jetbrains.annotations.NotNull; ++ ++public class AbstractRegionFileFactory { ++ @Contract("_, _, _, _ -> new") ++ public static @NotNull AbstractRegionFile getAbstractRegionFile(RegionStorageInfo storageKey, Path directory, Path path, boolean dsync) throws IOException { ++ return getAbstractRegionFile(storageKey, directory, path, RegionFileVersion.getCompressionFormat(), dsync); ++ } ++ ++ @Contract("_, _, _, _, _ -> new") ++ public static @NotNull AbstractRegionFile getAbstractRegionFile(RegionStorageInfo storageKey, Path directory, Path path, boolean dsync, boolean canRecalcHeader) throws IOException { ++ return getAbstractRegionFile(storageKey, directory, path, RegionFileVersion.getCompressionFormat(), dsync, canRecalcHeader); ++ } ++ ++ @Contract("_, _, _, _, _ -> new") ++ public static @NotNull AbstractRegionFile getAbstractRegionFile(RegionStorageInfo storageKey, Path path, Path directory, RegionFileVersion compressionFormat, boolean dsync) throws IOException { ++ return getAbstractRegionFile(storageKey, path, directory, compressionFormat, dsync, true); ++ } ++ ++ @Contract("_, _, _, _, _, _ -> new") ++ public static @NotNull AbstractRegionFile getAbstractRegionFile(RegionStorageInfo storageKey, @NotNull Path path, Path directory, RegionFileVersion compressionFormat, boolean dsync, boolean canRecalcHeader) throws IOException { ++ final String fullFileName = path.getFileName().toString(); ++ final String extensionName = fullFileName.split("\\.")[1]; ++ switch (EnumRegionFileExtension.fromExtension(extensionName)){ ++ case UNKNOWN -> { ++ if (RegionFormatConfig.throwOnUnknownExtension){ ++ throw new IllegalArgumentException("Unknown region file extension for file: " + fullFileName +"!"); ++ } ++ ++ return new RegionFile(storageKey, path, directory, compressionFormat, dsync, canRecalcHeader); ++ } ++ ++ case LINEAR ->{ ++ return new LinearRegionFile(path, RegionFormatConfig.linearCompressionLevel); ++ } ++ ++ default -> { ++ return new RegionFile(storageKey, path, directory, compressionFormat, dsync, canRecalcHeader); ++ } ++ } ++ } ++} +diff --git a/src/main/java/org/stupidcraft/linearpaper/region/EnumRegionFileExtension.java b/src/main/java/org/stupidcraft/linearpaper/region/EnumRegionFileExtension.java +new file mode 100644 +index 0000000000000000000000000000000000000000..d51ec3faeb6a78992d440a7996739f4a5f0a5387 +--- /dev/null ++++ b/src/main/java/org/stupidcraft/linearpaper/region/EnumRegionFileExtension.java +@@ -0,0 +1,55 @@ ++package org.stupidcraft.linearpaper.region; ++ ++ ++import org.jetbrains.annotations.Contract; ++import org.jetbrains.annotations.NotNull; ++ ++public enum EnumRegionFileExtension { ++ LINEAR(".linear"), ++ MCA(".mca"), ++ UNKNOWN(null); ++ ++ private final String extensionName; ++ ++ EnumRegionFileExtension(String extensionName) { ++ this.extensionName = extensionName; ++ } ++ ++ public String getExtensionName() { ++ return this.extensionName; ++ } ++ ++ @Contract(pure = true) ++ public static EnumRegionFileExtension fromName(@NotNull String name){ ++ switch (name){ ++ default -> { ++ return UNKNOWN; ++ } ++ ++ case "MCA" -> { ++ return MCA; ++ } ++ ++ case "LINEAR" -> { ++ return LINEAR; ++ } ++ } ++ } ++ ++ @Contract(pure = true) ++ public static EnumRegionFileExtension fromExtension(@NotNull String name){ ++ switch (name){ ++ default -> { ++ return UNKNOWN; ++ } ++ ++ case ".mca" -> { ++ return MCA; ++ } ++ ++ case ".linear" -> { ++ return LINEAR; ++ } ++ } ++ } ++} +diff --git a/src/main/java/org/stupidcraft/linearpaper/region/LinearRegionFile.java b/src/main/java/org/stupidcraft/linearpaper/region/LinearRegionFile.java +new file mode 100644 +index 0000000000000000000000000000000000000000..97092e1d419cb565466a25795966f6cc989f7898 +--- /dev/null ++++ b/src/main/java/org/stupidcraft/linearpaper/region/LinearRegionFile.java +@@ -0,0 +1,316 @@ ++package org.stupidcraft.linearpaper.region; ++ ++import com.github.luben.zstd.ZstdInputStream; ++import com.github.luben.zstd.ZstdOutputStream; ++import com.mojang.logging.LogUtils; ++import java.io.BufferedOutputStream; ++import java.io.ByteArrayInputStream; ++import java.io.ByteArrayOutputStream; ++import java.io.DataInputStream; ++import java.io.DataOutputStream; ++import java.io.File; ++import java.io.FileInputStream; ++import java.io.FileOutputStream; ++import java.io.IOException; ++import java.io.InputStream; ++import java.nio.ByteBuffer; ++import java.nio.file.Files; ++import java.nio.file.Path; ++import java.nio.file.StandardCopyOption; ++import java.util.ArrayList; ++import java.util.Arrays; ++import java.util.List; ++import java.util.concurrent.TimeUnit; ++import java.util.concurrent.atomic.AtomicBoolean; ++import java.util.concurrent.locks.ReentrantLock; ++import javax.annotation.Nullable; ++ ++import me.earthme.luminol.config.modules.misc.RegionFormatConfig; ++import net.jpountz.lz4.LZ4Compressor; ++import net.jpountz.lz4.LZ4Factory; ++import net.jpountz.lz4.LZ4FastDecompressor; ++import net.minecraft.nbt.CompoundTag; ++import net.minecraft.world.level.ChunkPos; ++import net.minecraft.world.level.chunk.status.ChunkStatus; ++import org.slf4j.Logger; ++ ++public class LinearRegionFile implements AbstractRegionFile, AutoCloseable { ++ private static final long SUPERBLOCK = -4323716122432332390L; ++ private static final byte VERSION = 2; ++ private static final int HEADER_SIZE = 32; ++ private static final int FOOTER_SIZE = 8; ++ private static final Logger LOGGER = LogUtils.getLogger(); ++ private static final List SUPPORTED_VERSIONS = Arrays.asList((byte) 1, (byte) 2); ++ public final ReentrantLock fileLock = new ReentrantLock(true); ++ private final byte[][] buffer = new byte[1024][]; ++ private final int[] bufferUncompressedSize = new int[1024]; ++ private final int[] chunkTimestamps = new int[1024]; ++ private final ChunkStatus[] statuses = new ChunkStatus[1024]; ++ private final LZ4Compressor compressor; ++ private final LZ4FastDecompressor decompressor; ++ private final int compressionLevel; ++ public boolean closed = false; ++ public Path path; ++ private volatile long lastFlushed = System.nanoTime(); ++ ++ ++ public LinearRegionFile(Path file, int compression) throws IOException { ++ this.path = file; ++ this.compressionLevel = compression; ++ this.compressor = LZ4Factory.fastestInstance().fastCompressor(); ++ this.decompressor = LZ4Factory.fastestInstance().fastDecompressor(); ++ ++ File regionFile = new File(this.path.toString()); ++ ++ Arrays.fill(this.bufferUncompressedSize, 0); ++ ++ if (!regionFile.canRead()) return; ++ ++ try (FileInputStream fileStream = new FileInputStream(regionFile); ++ DataInputStream rawDataStream = new DataInputStream(fileStream)) { ++ ++ long superBlock = rawDataStream.readLong(); ++ if (superBlock != SUPERBLOCK) ++ throw new RuntimeException("Invalid superblock: " + superBlock + " in " + file); ++ ++ byte version = rawDataStream.readByte(); ++ if (!SUPPORTED_VERSIONS.contains(version)) ++ throw new RuntimeException("Invalid version: " + version + " in " + file); ++ ++ // Skip newestTimestamp (Long) + Compression level (Byte) + Chunk count (Short): Unused. ++ rawDataStream.skipBytes(11); ++ ++ int dataCount = rawDataStream.readInt(); ++ long fileLength = file.toFile().length(); ++ if (fileLength != HEADER_SIZE + dataCount + FOOTER_SIZE) ++ throw new IOException("Invalid file length: " + this.path + " " + fileLength + " " + (HEADER_SIZE + dataCount + FOOTER_SIZE)); ++ ++ rawDataStream.skipBytes(8); // Skip data hash (Long): Unused. ++ ++ byte[] rawCompressed = new byte[dataCount]; ++ rawDataStream.readFully(rawCompressed, 0, dataCount); ++ ++ superBlock = rawDataStream.readLong(); ++ if (superBlock != SUPERBLOCK) ++ throw new IOException("Footer superblock invalid " + this.path); ++ ++ try (DataInputStream dataStream = new DataInputStream(new ZstdInputStream(new ByteArrayInputStream(rawCompressed)))) { ++ ++ int[] starts = new int[1024]; ++ for (int i = 0; i < 1024; i++) { ++ starts[i] = dataStream.readInt(); ++ dataStream.skipBytes(4); // Skip timestamps (Int): Unused. ++ } ++ ++ for (int i = 0; i < 1024; i++) { ++ if (starts[i] > 0) { ++ int size = starts[i]; ++ byte[] b = new byte[size]; ++ dataStream.readFully(b, 0, size); ++ ++ int maxCompressedLength = this.compressor.maxCompressedLength(size); ++ byte[] compressed = new byte[maxCompressedLength]; ++ int compressedLength = this.compressor.compress(b, 0, size, compressed, 0, maxCompressedLength); ++ b = new byte[compressedLength]; ++ System.arraycopy(compressed, 0, b, 0, compressedLength); ++ ++ this.buffer[i] = b; ++ this.bufferUncompressedSize[i] = size; ++ } ++ } ++ } ++ } ++ } ++ ++ private static int getChunkIndex(int x, int z) { ++ return (x & 31) + ((z & 31) << 5); ++ } ++ ++ private static int getTimestamp() { ++ return (int) (System.currentTimeMillis() / 1000L); ++ } ++ ++ public Path getRegionFile() { ++ return this.path; ++ } ++ ++ public ReentrantLock getFileLock() { ++ return this.fileLock; ++ } ++ ++ public void flush() throws IOException { ++ flushWrapper(); // sync ++ } ++ ++ public void flushWrapper() { ++ try { ++ save(); ++ } catch (IOException e) { ++ LOGGER.error("Failed to flush region file " + path.toAbsolutePath(), e); ++ } ++ } ++ ++ public boolean doesChunkExist(ChunkPos pos) throws Exception { ++ throw new Exception("doesChunkExist is a stub"); ++ } ++ ++ private synchronized void save() throws IOException { ++ long timestamp = getTimestamp(); ++ short chunkCount = 0; ++ ++ File tempFile = new File(path.toString() + ".tmp"); ++ ++ try (FileOutputStream fileStream = new FileOutputStream(tempFile); ++ ByteArrayOutputStream zstdByteArray = new ByteArrayOutputStream(); ++ ZstdOutputStream zstdStream = new ZstdOutputStream(zstdByteArray, this.compressionLevel); ++ DataOutputStream zstdDataStream = new DataOutputStream(zstdStream); ++ DataOutputStream dataStream = new DataOutputStream(fileStream)) { ++ ++ dataStream.writeLong(SUPERBLOCK); ++ dataStream.writeByte(VERSION); ++ dataStream.writeLong(timestamp); ++ dataStream.writeByte(this.compressionLevel); ++ ++ ArrayList byteBuffers = new ArrayList<>(); ++ for (int i = 0; i < 1024; i++) { ++ if (this.bufferUncompressedSize[i] != 0) { ++ chunkCount += 1; ++ byte[] content = new byte[bufferUncompressedSize[i]]; ++ this.decompressor.decompress(buffer[i], 0, content, 0, bufferUncompressedSize[i]); ++ ++ byteBuffers.add(content); ++ } else byteBuffers.add(null); ++ } ++ for (int i = 0; i < 1024; i++) { ++ zstdDataStream.writeInt(this.bufferUncompressedSize[i]); // Write uncompressed size ++ zstdDataStream.writeInt(this.chunkTimestamps[i]); // Write timestamp ++ } ++ for (int i = 0; i < 1024; i++) { ++ if (byteBuffers.get(i) != null) ++ zstdDataStream.write(byteBuffers.get(i), 0, byteBuffers.get(i).length); ++ } ++ zstdDataStream.close(); ++ ++ dataStream.writeShort(chunkCount); ++ ++ byte[] compressed = zstdByteArray.toByteArray(); ++ ++ dataStream.writeInt(compressed.length); ++ dataStream.writeLong(0); ++ ++ dataStream.write(compressed, 0, compressed.length); ++ dataStream.writeLong(SUPERBLOCK); ++ ++ dataStream.flush(); ++ fileStream.getFD().sync(); ++ fileStream.getChannel().force(true); // Ensure atomicity on Btrfs ++ } ++ Files.move(tempFile.toPath(), this.path, StandardCopyOption.REPLACE_EXISTING); ++ this.lastFlushed = System.nanoTime(); ++ } ++ ++ public void setStatus(int x, int z, ChunkStatus status) { ++ this.statuses[getChunkIndex(x, z)] = status; ++ } ++ ++ public synchronized void write(ChunkPos pos, ByteBuffer buffer) { ++ try { ++ byte[] b = toByteArray(new ByteArrayInputStream(buffer.array())); ++ int uncompressedSize = b.length; ++ ++ int maxCompressedLength = this.compressor.maxCompressedLength(b.length); ++ byte[] compressed = new byte[maxCompressedLength]; ++ int compressedLength = this.compressor.compress(b, 0, b.length, compressed, 0, maxCompressedLength); ++ b = new byte[compressedLength]; ++ System.arraycopy(compressed, 0, b, 0, compressedLength); ++ ++ int index = getChunkIndex(pos.x, pos.z); ++ this.buffer[index] = b; ++ this.chunkTimestamps[index] = getTimestamp(); ++ this.bufferUncompressedSize[getChunkIndex(pos.x, pos.z)] = uncompressedSize; ++ } catch (IOException e) { ++ LOGGER.error("Chunk write IOException " + e + " " + this.path); ++ } ++ ++ if ((System.nanoTime() - this.lastFlushed) >= TimeUnit.NANOSECONDS.toSeconds(RegionFormatConfig.linearFlushFrequency)){ ++ this.flushWrapper(); ++ } ++ } ++ ++ public DataOutputStream getChunkDataOutputStream(ChunkPos pos) { ++ return new DataOutputStream(new BufferedOutputStream(new ChunkBuffer(pos))); ++ } ++ ++ private byte[] toByteArray(InputStream in) throws IOException { ++ ByteArrayOutputStream out = new ByteArrayOutputStream(); ++ byte[] tempBuffer = new byte[4096]; ++ ++ int length; ++ while ((length = in.read(tempBuffer)) >= 0) { ++ out.write(tempBuffer, 0, length); ++ } ++ ++ return out.toByteArray(); ++ } ++ ++ @Nullable ++ public synchronized DataInputStream getChunkDataInputStream(ChunkPos pos) { ++ if (this.bufferUncompressedSize[getChunkIndex(pos.x, pos.z)] != 0) { ++ byte[] content = new byte[bufferUncompressedSize[getChunkIndex(pos.x, pos.z)]]; ++ this.decompressor.decompress(this.buffer[getChunkIndex(pos.x, pos.z)], 0, content, 0, bufferUncompressedSize[getChunkIndex(pos.x, pos.z)]); ++ return new DataInputStream(new ByteArrayInputStream(content)); ++ } ++ return null; ++ } ++ ++ public ChunkStatus getStatusIfCached(int x, int z) { ++ return this.statuses[getChunkIndex(x, z)]; ++ } ++ ++ public void clear(ChunkPos pos) { ++ int i = getChunkIndex(pos.x, pos.z); ++ this.buffer[i] = null; ++ this.bufferUncompressedSize[i] = 0; ++ this.chunkTimestamps[i] = getTimestamp(); ++ this.flushWrapper(); ++ } ++ ++ public boolean hasChunk(ChunkPos pos) { ++ return this.bufferUncompressedSize[getChunkIndex(pos.x, pos.z)] > 0; ++ } ++ ++ public void close() throws IOException { ++ if (closed) return; ++ closed = true; ++ flush(); // sync ++ } ++ ++ public boolean recalculateHeader() { ++ return false; ++ } ++ ++ public void setOversized(int x, int z, boolean something) { ++ } ++ ++ public CompoundTag getOversizedData(int x, int z) throws IOException { ++ throw new IOException("getOversizedData is a stub " + this.path); ++ } ++ ++ public boolean isOversized(int x, int z) { ++ return false; ++ } ++ ++ private class ChunkBuffer extends ByteArrayOutputStream { ++ private final ChunkPos pos; ++ ++ public ChunkBuffer(ChunkPos chunkcoordintpair) { ++ super(); ++ this.pos = chunkcoordintpair; ++ } ++ ++ public void close() throws IOException { ++ ByteBuffer bytebuffer = ByteBuffer.wrap(this.buf, 0, this.count); ++ LinearRegionFile.this.write(this.pos, bytebuffer); ++ } ++ } ++} diff --git a/patches/server/0015-Try-fixing-folia-spector-teleportation.patch b/patches/server/0016-Try-fixing-folia-spector-teleportation.patch similarity index 100% rename from patches/server/0015-Try-fixing-folia-spector-teleportation.patch rename to patches/server/0016-Try-fixing-folia-spector-teleportation.patch diff --git a/patches/server/0016-Teleport-async-if-entity-was-moving-to-another-regio.patch b/patches/server/0017-Teleport-async-if-entity-was-moving-to-another-regio.patch similarity index 100% rename from patches/server/0016-Teleport-async-if-entity-was-moving-to-another-regio.patch rename to patches/server/0017-Teleport-async-if-entity-was-moving-to-another-regio.patch diff --git a/patches/server/0017-Try-fixing-folia-off-region-POI-accessing-issue.patch b/patches/server/0018-Try-fixing-folia-off-region-POI-accessing-issue.patch similarity index 100% rename from patches/server/0017-Try-fixing-folia-off-region-POI-accessing-issue.patch rename to patches/server/0018-Try-fixing-folia-off-region-POI-accessing-issue.patch diff --git a/patches/server/0018-Prevent-teleportAsync-calling-during-moving-event-be.patch b/patches/server/0019-Prevent-teleportAsync-calling-during-moving-event-be.patch similarity index 100% rename from patches/server/0018-Prevent-teleportAsync-calling-during-moving-event-be.patch rename to patches/server/0019-Prevent-teleportAsync-calling-during-moving-event-be.patch diff --git a/patches/server/0019-Kaiiju-Don-t-pathfind-outside-region.patch b/patches/server/0020-Kaiiju-Don-t-pathfind-outside-region.patch similarity index 100% rename from patches/server/0019-Kaiiju-Don-t-pathfind-outside-region.patch rename to patches/server/0020-Kaiiju-Don-t-pathfind-outside-region.patch diff --git a/patches/server/0020-Kaiiju-Vanilla-end-portal-teleportation.patch b/patches/server/0021-Kaiiju-Vanilla-end-portal-teleportation.patch similarity index 100% rename from patches/server/0020-Kaiiju-Vanilla-end-portal-teleportation.patch rename to patches/server/0021-Kaiiju-Vanilla-end-portal-teleportation.patch diff --git a/patches/server/0021-Petal-Reduce-sensor-work.patch b/patches/server/0022-Petal-Reduce-sensor-work.patch similarity index 96% rename from patches/server/0021-Petal-Reduce-sensor-work.patch rename to patches/server/0022-Petal-Reduce-sensor-work.patch index 5fefee4..c88f99a 100644 --- a/patches/server/0021-Petal-Reduce-sensor-work.patch +++ b/patches/server/0022-Petal-Reduce-sensor-work.patch @@ -33,7 +33,7 @@ index 0000000000000000000000000000000000000000..dd45cf1fde5ee4cf8347064f106c64b8 + } +} diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index ef5cd008de4d145b67c70e48ae21ea969aedb1f0..8345d8431e1c05639f14919b9bad1029249a5f50 100644 +index bb5de770b6659379a68c077ff1cfc8d95d149c5c..a6c1d59085e0c58d9d1996d9e905bc24a3678e0c 100644 --- a/src/main/java/net/minecraft/world/entity/Mob.java +++ b/src/main/java/net/minecraft/world/entity/Mob.java @@ -983,12 +983,12 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti diff --git a/patches/server/0022-Pufferfish-Optimize-entity-coordinate-key.patch b/patches/server/0023-Pufferfish-Optimize-entity-coordinate-key.patch similarity index 100% rename from patches/server/0022-Pufferfish-Optimize-entity-coordinate-key.patch rename to patches/server/0023-Pufferfish-Optimize-entity-coordinate-key.patch diff --git a/patches/server/0023-Pufferfish-Cache-climbing-check-for-activation.patch b/patches/server/0024-Pufferfish-Cache-climbing-check-for-activation.patch similarity index 100% rename from patches/server/0023-Pufferfish-Cache-climbing-check-for-activation.patch rename to patches/server/0024-Pufferfish-Cache-climbing-check-for-activation.patch diff --git a/patches/server/0024-Pufferfish-Improve-fluid-direction-caching.patch b/patches/server/0025-Pufferfish-Improve-fluid-direction-caching.patch similarity index 100% rename from patches/server/0024-Pufferfish-Improve-fluid-direction-caching.patch rename to patches/server/0025-Pufferfish-Improve-fluid-direction-caching.patch diff --git a/patches/server/0025-Pufferfish-Optimize-suffocation.patch b/patches/server/0026-Pufferfish-Optimize-suffocation.patch similarity index 97% rename from patches/server/0025-Pufferfish-Optimize-suffocation.patch rename to patches/server/0026-Pufferfish-Optimize-suffocation.patch index 7a362d8..a492090 100644 --- a/patches/server/0025-Pufferfish-Optimize-suffocation.patch +++ b/patches/server/0026-Pufferfish-Optimize-suffocation.patch @@ -31,7 +31,7 @@ index 0000000000000000000000000000000000000000..3e48cd297b4869e5c89b6abc43c726d3 + } +} diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 89ff6f509a59b484977ffbdb4e4132a46ca4bbaa..2a7172c987812347e308ae1ed86b3fd430ef04e9 100644 +index b3f0de04a7448a31a87d50f630dd4d929a6b6f37..216af15f706f777bd6350cdd2187a8e7c98dfa21 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java @@ -442,7 +442,7 @@ public abstract class LivingEntity extends Entity implements Attackable { diff --git a/patches/server/0026-Pufferfish-Early-return-optimization-for-target-find.patch b/patches/server/0027-Pufferfish-Early-return-optimization-for-target-find.patch similarity index 100% rename from patches/server/0026-Pufferfish-Early-return-optimization-for-target-find.patch rename to patches/server/0027-Pufferfish-Early-return-optimization-for-target-find.patch diff --git a/patches/server/0027-Pufferfish-Reduce-chunk-loading-lookups.patch b/patches/server/0028-Pufferfish-Reduce-chunk-loading-lookups.patch similarity index 100% rename from patches/server/0027-Pufferfish-Reduce-chunk-loading-lookups.patch rename to patches/server/0028-Pufferfish-Reduce-chunk-loading-lookups.patch diff --git a/patches/server/0028-Pufferfish-Fix-Paper-6045-block-goal-shouldn-t-load-.patch b/patches/server/0029-Pufferfish-Fix-Paper-6045-block-goal-shouldn-t-load-.patch similarity index 100% rename from patches/server/0028-Pufferfish-Fix-Paper-6045-block-goal-shouldn-t-load-.patch rename to patches/server/0029-Pufferfish-Fix-Paper-6045-block-goal-shouldn-t-load-.patch diff --git a/patches/server/0029-Pufferfish-Reduce-entity-fluid-lookups-if-no-fluids.patch b/patches/server/0030-Pufferfish-Reduce-entity-fluid-lookups-if-no-fluids.patch similarity index 100% rename from patches/server/0029-Pufferfish-Reduce-entity-fluid-lookups-if-no-fluids.patch rename to patches/server/0030-Pufferfish-Reduce-entity-fluid-lookups-if-no-fluids.patch diff --git a/patches/server/0030-Pufferfish-Only-check-for-spooky-season-once-an-hour.patch b/patches/server/0031-Pufferfish-Only-check-for-spooky-season-once-an-hour.patch similarity index 100% rename from patches/server/0030-Pufferfish-Only-check-for-spooky-season-once-an-hour.patch rename to patches/server/0031-Pufferfish-Only-check-for-spooky-season-once-an-hour.patch diff --git a/patches/server/0031-Pufferfish-Entity-TTL.patch b/patches/server/0032-Pufferfish-Entity-TTL.patch similarity index 100% rename from patches/server/0031-Pufferfish-Entity-TTL.patch rename to patches/server/0032-Pufferfish-Entity-TTL.patch diff --git a/patches/server/0032-Pufferfish-Reduce-projectile-chunk-loading.patch b/patches/server/0033-Pufferfish-Reduce-projectile-chunk-loading.patch similarity index 100% rename from patches/server/0032-Pufferfish-Reduce-projectile-chunk-loading.patch rename to patches/server/0033-Pufferfish-Reduce-projectile-chunk-loading.patch diff --git a/patches/server/0033-Pufferfish-Dynamic-Activation-of-Brain.patch b/patches/server/0034-Pufferfish-Dynamic-Activation-of-Brain.patch similarity index 100% rename from patches/server/0033-Pufferfish-Dynamic-Activation-of-Brain.patch rename to patches/server/0034-Pufferfish-Dynamic-Activation-of-Brain.patch diff --git a/patches/server/0034-Pufferfish-Throttle-goal-selector-during-inactive-ti.patch b/patches/server/0035-Pufferfish-Throttle-goal-selector-during-inactive-ti.patch similarity index 96% rename from patches/server/0034-Pufferfish-Throttle-goal-selector-during-inactive-ti.patch rename to patches/server/0035-Pufferfish-Throttle-goal-selector-during-inactive-ti.patch index 5785127..6effd60 100644 --- a/patches/server/0034-Pufferfish-Throttle-goal-selector-during-inactive-ti.patch +++ b/patches/server/0035-Pufferfish-Throttle-goal-selector-during-inactive-ti.patch @@ -31,7 +31,7 @@ index 0000000000000000000000000000000000000000..acc032f727e605e79b688efb4873ff47 + } +} diff --git a/src/main/java/net/minecraft/world/entity/Mob.java b/src/main/java/net/minecraft/world/entity/Mob.java -index 208f0995479df5741ff780df607451f27c6f91af..78619c2ce66c34c4866755aa8c6c9ae18d594498 100644 +index fae60501284a68238c53ffc19075d46ac49cfdaa..03cf4ef6fd09de13709400dc508266c2b3d99330 100644 --- a/src/main/java/net/minecraft/world/entity/Mob.java +++ b/src/main/java/net/minecraft/world/entity/Mob.java @@ -245,11 +245,13 @@ public abstract class Mob extends LivingEntity implements EquipmentUser, Targeti diff --git a/patches/server/0035-Pufferfish-Reduce-entity-allocations.patch b/patches/server/0036-Pufferfish-Reduce-entity-allocations.patch similarity index 100% rename from patches/server/0035-Pufferfish-Reduce-entity-allocations.patch rename to patches/server/0036-Pufferfish-Reduce-entity-allocations.patch diff --git a/patches/server/0036-Pufferfish-Improve-container-checking-with-a-bitset.patch b/patches/server/0037-Pufferfish-Improve-container-checking-with-a-bitset.patch similarity index 100% rename from patches/server/0036-Pufferfish-Improve-container-checking-with-a-bitset.patch rename to patches/server/0037-Pufferfish-Improve-container-checking-with-a-bitset.patch diff --git a/patches/server/0037-Gale-Variable-entity-wake-up-duration.patch b/patches/server/0038-Gale-Variable-entity-wake-up-duration.patch similarity index 100% rename from patches/server/0037-Gale-Variable-entity-wake-up-duration.patch rename to patches/server/0038-Gale-Variable-entity-wake-up-duration.patch diff --git a/patches/server/0038-Gale-Don-t-load-chunks-to-activate-climbing-entities.patch b/patches/server/0039-Gale-Don-t-load-chunks-to-activate-climbing-entities.patch similarity index 100% rename from patches/server/0038-Gale-Don-t-load-chunks-to-activate-climbing-entities.patch rename to patches/server/0039-Gale-Don-t-load-chunks-to-activate-climbing-entities.patch diff --git a/patches/server/0039-Gale-Optimize-sun-burn-tick.patch b/patches/server/0040-Gale-Optimize-sun-burn-tick.patch similarity index 100% rename from patches/server/0039-Gale-Optimize-sun-burn-tick.patch rename to patches/server/0040-Gale-Optimize-sun-burn-tick.patch diff --git a/patches/server/0040-Gale-Check-frozen-ticks-before-landing-block.patch b/patches/server/0041-Gale-Check-frozen-ticks-before-landing-block.patch similarity index 93% rename from patches/server/0040-Gale-Check-frozen-ticks-before-landing-block.patch rename to patches/server/0041-Gale-Check-frozen-ticks-before-landing-block.patch index c0d1e93..42d6adc 100644 --- a/patches/server/0040-Gale-Check-frozen-ticks-before-landing-block.patch +++ b/patches/server/0041-Gale-Check-frozen-ticks-before-landing-block.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Gale Check frozen ticks before landing block diff --git a/src/main/java/net/minecraft/world/entity/LivingEntity.java b/src/main/java/net/minecraft/world/entity/LivingEntity.java -index 0eb73b666fe161fc148e0c0dc2da3362f8452187..bae654c209fc423cafe66f10ba35971af7579710 100644 +index 76758de966bba1eab9e10ecf6063303e01e80e49..69a44c8f9b79b9e2b1f7723e3229aab90109d5c6 100644 --- a/src/main/java/net/minecraft/world/entity/LivingEntity.java +++ b/src/main/java/net/minecraft/world/entity/LivingEntity.java @@ -609,11 +609,10 @@ public abstract class LivingEntity extends Entity implements Attackable { diff --git a/patches/server/0041-Gale-Use-platform-math-functions.patch b/patches/server/0042-Gale-Use-platform-math-functions.patch similarity index 100% rename from patches/server/0041-Gale-Use-platform-math-functions.patch rename to patches/server/0042-Gale-Use-platform-math-functions.patch diff --git a/patches/server/0042-Gale-Skip-entity-move-if-movement-is-zero.patch b/patches/server/0043-Gale-Skip-entity-move-if-movement-is-zero.patch similarity index 100% rename from patches/server/0042-Gale-Skip-entity-move-if-movement-is-zero.patch rename to patches/server/0043-Gale-Skip-entity-move-if-movement-is-zero.patch diff --git a/patches/server/0043-Gale-Optimize-world-generation-chunk-and-block-acces.patch b/patches/server/0044-Gale-Optimize-world-generation-chunk-and-block-acces.patch similarity index 100% rename from patches/server/0043-Gale-Optimize-world-generation-chunk-and-block-acces.patch rename to patches/server/0044-Gale-Optimize-world-generation-chunk-and-block-acces.patch diff --git a/patches/server/0044-Gale-Optimize-noise-generation.patch b/patches/server/0045-Gale-Optimize-noise-generation.patch similarity index 100% rename from patches/server/0044-Gale-Optimize-noise-generation.patch rename to patches/server/0045-Gale-Optimize-noise-generation.patch diff --git a/patches/server/0045-Gale-Faster-chunk-serialization.patch b/patches/server/0046-Gale-Faster-chunk-serialization.patch similarity index 100% rename from patches/server/0045-Gale-Faster-chunk-serialization.patch rename to patches/server/0046-Gale-Faster-chunk-serialization.patch diff --git a/patches/server/0046-Gale-Reduce-lambda-and-Optional-allocation-in-Entity.patch b/patches/server/0047-Gale-Reduce-lambda-and-Optional-allocation-in-Entity.patch similarity index 100% rename from patches/server/0046-Gale-Reduce-lambda-and-Optional-allocation-in-Entity.patch rename to patches/server/0047-Gale-Reduce-lambda-and-Optional-allocation-in-Entity.patch diff --git a/patches/server/0047-Gale-Replace-throttle-tracker-map-with-optimized-col.patch b/patches/server/0048-Gale-Replace-throttle-tracker-map-with-optimized-col.patch similarity index 100% rename from patches/server/0047-Gale-Replace-throttle-tracker-map-with-optimized-col.patch rename to patches/server/0048-Gale-Replace-throttle-tracker-map-with-optimized-col.patch diff --git a/patches/server/0048-Sparkly-Paper-Optimize-canSee-checks.patch b/patches/server/0049-Sparkly-Paper-Optimize-canSee-checks.patch similarity index 97% rename from patches/server/0048-Sparkly-Paper-Optimize-canSee-checks.patch rename to patches/server/0049-Sparkly-Paper-Optimize-canSee-checks.patch index 527a4a6..d43095c 100644 --- a/patches/server/0048-Sparkly-Paper-Optimize-canSee-checks.patch +++ b/patches/server/0049-Sparkly-Paper-Optimize-canSee-checks.patch @@ -5,7 +5,7 @@ Subject: [PATCH] Sparkly Paper Optimize canSee checks diff --git a/src/main/java/net/minecraft/server/level/ChunkMap.java b/src/main/java/net/minecraft/server/level/ChunkMap.java -index c547d51eebd965f2be7ac45bc0981626c0515ef1..b7d91b7e8eb31f838cf540246f2d9b9c32b28780 100644 +index 4a0c5afd03dba788c40a71f00bc1fd0d4f0fc7e4..04f5efdc0d5729af5009e51a3e36ed7c34991123 100644 --- a/src/main/java/net/minecraft/server/level/ChunkMap.java +++ b/src/main/java/net/minecraft/server/level/ChunkMap.java @@ -1422,7 +1422,7 @@ public class ChunkMap extends ChunkStorage implements ChunkHolder.PlayerProvider diff --git a/patches/server/0049-Threaded-region-start-tick-and-finished-tick-event.patch b/patches/server/0050-Threaded-region-start-tick-and-finished-tick-event.patch similarity index 100% rename from patches/server/0049-Threaded-region-start-tick-and-finished-tick-event.patch rename to patches/server/0050-Threaded-region-start-tick-and-finished-tick-event.patch diff --git a/patches/server/0050-Purpur-use-alternative-keep-alive.patch b/patches/server/0051-Purpur-use-alternative-keep-alive.patch similarity index 100% rename from patches/server/0050-Purpur-use-alternative-keep-alive.patch rename to patches/server/0051-Purpur-use-alternative-keep-alive.patch diff --git a/patches/server/0051-Fix-MC-2025.patch b/patches/server/0052-Fix-MC-2025.patch similarity index 100% rename from patches/server/0051-Fix-MC-2025.patch rename to patches/server/0052-Fix-MC-2025.patch diff --git a/patches/server/0052-KioCG-Chunk-API.patch b/patches/server/0053-KioCG-Chunk-API.patch similarity index 99% rename from patches/server/0052-KioCG-Chunk-API.patch rename to patches/server/0053-KioCG-Chunk-API.patch index a15c4b9..7e9cf8b 100644 --- a/patches/server/0052-KioCG-Chunk-API.patch +++ b/patches/server/0053-KioCG-Chunk-API.patch @@ -102,7 +102,7 @@ index 0000000000000000000000000000000000000000..53b4397997bc9b9b9d88e48304b37a25 + } +} diff --git a/src/main/java/net/minecraft/server/MinecraftServer.java b/src/main/java/net/minecraft/server/MinecraftServer.java -index ac0312d5d496ee5599ff6b002196d98b42385309..d43831210937108563035ab8137ab27694a7c465 100644 +index e60c8fd49d01a5acb1054b8eebc85612b8192884..08d5e1a81c2a5eda92433ac7bd0ed7250b78e4e2 100644 --- a/src/main/java/net/minecraft/server/MinecraftServer.java +++ b/src/main/java/net/minecraft/server/MinecraftServer.java @@ -1696,6 +1696,17 @@ public abstract class MinecraftServer extends ReentrantBlockableEventLoop