From 2783afda7dee9b91c53f214c237d15843f3ff5c7 Mon Sep 17 00:00:00 2001 From: Space Walker Date: Sun, 2 Nov 2025 19:32:59 +0100 Subject: [PATCH 1/8] gradle 8.14 --- gradle/wrapper/gradle-wrapper.jar | Bin 43583 -> 43764 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 9 ++++----- gradlew.bat | 4 ++-- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index a4b76b9530d66f5e68d973ea569d8e19de379189..1b33c55baabb587c669f562ae36f953de2481846 100644 GIT binary patch delta 34943 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

Gn4F+B~IivciU9^t0j-Mgao3 zSDF_?f~c=V=QJRSDTG0SibzjML$_?2eqZ;J*7Sv$*0SQ|ck$fX&LMyXFj}UH(!X;; zB_rKmM-taavzEk&gLSiCiBQajx$z%gBZY2MWvC{Hu6xguR`}SPCYt=dRq%rvBj{Fm zC((mn$ribN^qcyB1%X3(k|%E_DUER~AaFfd`ka)HnDr+6$D@YQOxx6KM*(1%3K(cN)g#u>Nj zSe+9sTUSkMGjfMgDtJR@vD1d)`pbSW-0<1e-=u}RsMD+k{l0hwcY_*KZ6iTiEY zvhB)Rb+_>O`_G{!9hoB`cHmH^`y16;w=svR7eT_-3lxcF;^GA1TX?&*pZ^>PO=rAR zf>Bg{MSwttyH_=OVpF`QmjK>AoqcfNU(>W7vLGI)=JN~Wip|HV<;xk6!nw-e%NfZ| zzTG*4uw&~&^A}>E>0cIw_Jv-|Eb%GzDo(dt3%-#DqGwPwTVxB|6EnQ;jGl@ua``AFlDZP;dPLtPI}=%iz-tv8 z0Wsw+|0e=GQ7YrS|6^cT|7SaRiKzV3V^_ao_ zLY3Jnp<0O6yE&KIx6-5V@Xf^n02@G2n5}2Z;SiD4L{RAFnq$Q#yt1)MDoHmEC6mX1 zS^rhw8mZJk9tiETa5*ryrCn&Ev?`7mQWz*vQE!SAF{D@b7IGpKrj^_PC2Cpj!8E{W zvFzy&O4Z-Exr$Z*YH4e|imE`&n<$L-_Bju=Axiik+hBtA4XNDik(G_;6^mQ3bT)Y% z6x=a+LKFZbjyb;`MRk~Dbxyc&L; z8*}!9&j0wewMM#O`c#7HJ|+Gh5%3~W10b6sdmCg3G_v+@H>n*c5H`f+7%{TeSrzt89GYJqm>j-!*dReeu&KHubhzjSy_c~BJcbaFtZWAB}~KP3%*u{zHi zVSUi2H8EsuSb3l7_T1hP!$xTtb{3|ZZNAJ{&Ko;#>^^43b7`eE;`87q81Jp;dZfC< z$BD`h-*j=%uTpG8Me6dF zrH%)Bw-a0}S41ILo*k2zn6P@?USXtC>pX*tzce7A^JD7^^p7K5kh-HO&2haDTL%2^ zSWQb2B6}e*;x?eKq?CdG7F=wHVY)Lb(kQu1R#1Fx|3?>_%cjNM-xJlAg9kr`!>&;E zTYmHhqHh&qbfO`~w3V;BM(q(_Q-5^!esaBI&QbZ^%N-ZDYft#FTS;%{ zKzlSwZIS%zDi#%DMK>`_vmE^krJL5@PmpT2m26Q`O)VRAL>){MN45|7GTk=q^zLpF zjS(Os=`#On$XI#$A5ewac9Ma}mDxSu^5{#jHC+24a2GbfBJ&Zn8W= zm=l7VE0g^z$3ikyU#ysh8b-PH(&-yZL$JV-of-ZM@~N^#DbQ3Ltlq*5@>WzSNxrRK zYl2VS8r;TT`wLfD_O0dhX9vR#S8rMOuUCRkWZE#OjRi$l*#C7}mgGzZBD%Z=p3z|CaVM$$pyW5-pJJDCToY zO3R5)P(Gnd>6wh9Z$Sr@cMXmClU(h-@5kmiBTNTU-|5vq&Fs!ah|o47kW?SO8uWv> zW$=Ud@@|*9p@Rb=!wl;%>k)kH7fPtcD=gd}^IxN^=Cg>zq^jij!f=1PlT|9jh3K9g zF~Z)B;kb^a0hLmJvON8Ho)foq-oC)&E)b|a^|b}6n!8&AIaousO^VnYzYfuijuEo5 z7IcUMbYD=vec4eZX7;p31NB+T9BOMJp9ZI9$dH1kJsJpEtf@}tL4)_*PxgdOge9_EaR!?wWtBx%*f$IGoR>f3Qf2aT0%+fq=1xVEqRl;UaA2Ncs4B1M1#foI2bj4 znX}t7;-FCLK&;>ZGP}{GxK67$Kz&pO%%J>DBMP_zZsLOmdpDUDp&f8=L>(Kcj+S^jA5dco4-7XN z)h;m#54CEy9)Ch-E7gHP@a@TXl=_%&|iUlIrQzn=LqONBu9FCn`3f8aqvRu=RrJ_RH1^Uf=t z%Ir*({+wEeC??C+u!hCi<5m`RsRO6ti7YaEtY0|U)-QfNsdN{=83K_}m$0Z=ElWyt znvo5=%f<;|hNnL-r#v5ab&S2*yK>~a7m(My$cfd*tff?=?7-j3^|&9H7G*W`)m8M7 zzd0+b)c@`bQN1-^dC$_04tK0{mU5tx_zo;&TWou8F(H_J?O+Y)VLXzmU^> zvL!5+1H?opj`?lAktaOu%N#k4;X;UX5LuO`4UCVO$t+kZBYu`1&6IV@J>0}x1ecuH zlD9U=_lk1TIRMm6DeY2;BJJEE%b0z;UdvH_a3%o)Z^wM&<$zhQpv90@0c+t?W`9kolKUklpX5M&Qw06u=>GPCr5Imvh*% zfI`tI-eneDRQo?m*zD1i;!B>*z4Xioa_-S=cbv-k_#Wg=)b$0@{SK>Mr!_T?H`S-?j;3$4)ITn$`g;J$^TppD)^pRz#^l?XgZ2CW z3g5G^iF*GZYQ}{B|H-fqh=_>)E~=3y3Zg=i75G5E)*a>R9bn~cNW{h5&P(vQ6!WHv zw1-89smtY~JnCQS(=9zM)6>UAi%G-r^LA9_HF0Vp3%JF2P%+E&^afy61yxnAyU;Z{ z$~H5X6?sMoUuOT_tU7i5i%5HI{^@#Hx@zhtP55>r_<3LwusK*SC#%i+gn&iRg z_8UN=rLVp*gT(K~{0X0f_=?~bBbfB`=XrTFn3U!)9n*@Uj$-mr^9PNi<22UJKAK&D z|1@Ck3(Ub;>68;)gIn_Zu{uoVRMhAkIqgBS(v2b2{gf?0xd(1sJfY`56mVy>~^w!wmX_kjW8#?_Nk{}zB9ULo>4fO(vnWfC+pG4>%*KZ?JuCdXu%aZ}q7pC%E50@U9+KQZL5 z!*I`SOtNf$Y$CsRsNaf~yyw^>#X_mCiF&*gr=cBb zoPu7PwX(+Wvl~i(XH|)jj@Cu+rzpJMn4kVvCJ~ReCf08viF$q9;CYnv-96k{G?pf_ zQglN`JiS#vok)~^Z2>41#7LPFgd_xrqNO%DQI|!Qs|nWt`co#BwY$&Wm^6#~)`_1k zpwiR~&z#mtSDuYm(=NoLv$%Y}bTjog$RJ8$j1(s})=}su0b?o8i28-|xu58ipFBml z2`4qZ$BbY5>(i2%wmh!+C}$97?X3LgTQ_{(SaFZvq9YCn@BNz z&h#;4h?5#`&_0()uJ;_rR(Q^eY*=&vu)#EeMeaN1puPv5+iQFg1EC(`_99_5v<1r4D ztc(+-eVWf_np;q$M*H49#{R)eIWCI%R&6F34;h9eNG(XNO5ao2MI8;j}y% zZeA>zX{#$;muhtY{_|;bkk~!U~Ih z2QUO}hk~o?sn;#|Mt$0}4=+BRa703n6>fBm(cesk8Cmugg_wi|BWj}V-VuU9jNH+o zgNYGSKPm>qR&nI(2Gu*})AOBfXf0J~CC50C!3KXu6-qZAG!VMZbmnqL6HWG>o$^sjoSLbQxra@WyKV$+_Qe}t7d)c`bpJG++ zw|9D3>XUH^Wplo~MN%WK18n3HeXoe*jKwVRK!=RMtIr1v z;Py~7;eZl&=^UyumN&CecrGBEat}4?mtZ>@`wPjVK@Z)FZ;05^9kztq;qmbxQIJ4kXTk)) zaVfD^K2x7SB6E!Zz@0p|Fkge*0(0?ogmTX8d=?n{2x)}K2$`bjDmcLg3#wU)i)by? zW^G8rRQKBwjke5zHScinRlE|wo0XyhBc9R52IsKWf4-@=l!yO&+l=K`-7Ib9U~hPy z!cH>H)e6$;m&w^0d`axGqDwBgu`B+L4a`xr#5g%b=0?c41`|lx0O9fiIVaFAsO$Ol zayhm4C9X%hzUf&ctylV$%ntuA$(yo*X`gaVX0$|x{#!YK^cvLmNWPZaTd3&xP7ny% zkn}2AdJkpAgmsh}Q$tY3(2RtO;%R*~8r#ZbSbMR4LaL9Sb6O&Ce(GlO${jtl&`n|D z9;zUQPXCHqTm&t^lk9RlZiiquSY_og^?kgVruz%myd95Fr!V z-$OIXSt?(pxN-M{NjA)j1KKIp(&c2RVjd_}7+CbQfw zTRjg}A0~}Ht_?-@wD0bI-;LQwT?mKywmDZ7*j4>4pR6@UVU3mb?-cbQt~aIG&RBjl zs-4UNtOH3+dAF%U=={qB@qijh4J6K?Et zPLlfPlv<+i>ty5rh;Q>iGFoaq4LyBIZl3L{KGUmqPL~ZCosOl;7w2SxcE}pvK;5|6 zly3JjUsvk|d7L3bFs&;q@_|p?vdU_UzhrS$Fw-_NoEdoIT#-0hKC37!>-i6FaO(es zY97)m4YO<|eqGMrYejC&-IFmc{=P7>qFWX;)}q!&e9-F59o>V+`X>J}%Te0$|A>0W z;7*>m4>udzwr$(C?TzhZqi<~6wv&x*+qP}v?C<}aI_Jeq*K|$4>AGurZe5=U>-0IX z>&2?v81(_Tn1tITYDSF@^Enhl9>e1$iAnX!+&YJVi>1uYEWsZ?o*Vyg+K~%XCxQP(WrdtEpc3sgbpTM_ zI7i6|pDr z{=xGh4O=PrB}pkX@o@A(%GfdU!c<$p#T*mLo^*7@bd4rIJ5eS&&A9VB$EhabJ1^TG z+dke8lOG5I(xMYZ`Xw8+olY0y6M)M0rcr%9tZHa=G0zICN@DQ>0rVASCK4=3OeMSv zD!v+POT0`UZEnP~1ro1?HPLqJ)xx0#Pg^yBJz@S6gmFN~cGvl(#fz4oTs7_Pi^+i_ zZP7<#ukx>i%V;uJJ~WwUW7pgq=>yuT+A5w(J5$1no67e(;mIO5>@`(U0{}+kg)B_8 zs=bfBbmZ{U`xjMpkAcEcEeF7^#ka}2zDU-sBt6yQqw&2p<+6Hb(Hi56S!+bU9AJJv*{ep2vD zG;PVwX@NC)+=6@I6J=nW6_99&4R00FKpUPepXoBVN*|V*C{e7X+Q({6O_^@SlI(9Y z8kRO3WDG5u=vmTjZ4DW89H&vNa;i%H@`{%(|J%tVs;1gDadzF0Jy%}C68|k?Zr!B9 z*lBN4{#6p#SQS-q#Ck&x#xhAOu4mK=Jxf+5E$h8l3-F4mQY^qaS5;Z* z-ddglOueLtXJhJ!%yJGk^-iZ_+qLJ zpTZn+6kq81D@^m(v$VFFI1Q!dtczYBt1xSn9~Q=@h%tsf*hCm%fwfx2u(u=-4|qf=I8WR*%`lsQ ziP!-b?(d_`TdA=^<$@(2c77&FowB0vhswM)fS>lYvjK7B_$<0SiQNzL6T?D721Y*( z9nG=@aWvmJMd%j$Jxp3-L4x99-X-9aGkW}yiPAo*9{^6b1>tDg4zIPFiTqVK$xq1rv1*kaE|~T5-jH#8{g31#^7M_uSsmQvNjyk; zbo|yP0w|uD1)wGrSavi=<;=H>IejRQlac$HMkU2rbq1{8UntI;oJ}*o(bXy{JC*l&^W{Y^}<%Nj1Tk z$(9f2a`BoyZZqxWF=hhmc3ldg+8&Ep%fVCSjopduonggw7@?XulP^JPo+_le`o@z)ofi9U%I z=~YZ3?Jok#3NeQ)U&qUqvoyuEMA?b&Ki=s%;_MTDX+8^>z@TOxb3qw~biG4!)XuQp z=>cVLGcp<{Piu-TqWLFz^P0>R1go1M41xFSn~y%8LZ{~t{iz!z$|ne5qkw!VwuI<6 z*6Bsnap!L>JA;B$u$J09!L&_iGdX<&v1jeDcEWM4&2q97^g9gK1%+zl7nY)PUU9<~ z!B??-0oFH5TEpfNW#V1m;(6-=mlUxm699O$g=ZrFZpn(6h%3n#!U7eFnC1BJzLFB) z-)SER^cpQ~AF(`0^?pNYWsz6(suJg4)Ke+|iTo4!8P8ND$ML1a%4|QMYe@SDDH#d& z)P6SOk~%xdQ?i^t{N0)(baSgQ(Fp*daGXR>=Vt-*#@)>A1Sfz0!iqKtjlY4}1i0v0 zyz)Z|vB+_QIX99Q+NFppI1+3`=qUen8NVELr!SOS8Vq1;{<}WKOhe7HMurM4mg~j5 z%|wM0)r4^=uC{9_OTf*An{G}>6hw}C=H|&8MY~l@u zmW-R8h;dJxjKNqEdGf85(5BrR>lY2A= z-_%9;IglQfHBuO%U)bt|g%1h-OMbL9H{TdFgM^rdBTt~gJ%{*c<;b$D13(ac>}*nJ zo@&y3%13-hUh^Oa$9U1ImdNfGO4bPX$I!c!6e;sRC>z{knTf~G5{#4J7y(vbrq-qWk%J5#0Iv((P!QKa6f#3?;#q$+(teR!nw%kOp&_W`3L^Xw}Dw&e2#l zc{fk56;UyHDpT@XdB?u!*)EdIMT8X1&e>VO;M_QH&MXI5|3xTbET#NTfyi14#+0+t zDS(NC?jbc{yIDjm-=9g^4*f1c;0!ytb~iQ;DSTKoa4ow@d-x3HI`EYcAe(li zjajb0cM*@u*kiU{)jd9yTNeRZLL+Y1&q`L>gx^Jj_B%sh2+%Z1d6xNVmTw5Fw!kd@ z+uT`4r(0=PXUZCNn9$VPo=aj+p${a|eqjB{Mf+k&$GEGV(lWHl#1xy1%5E)1KD$bK z0Z1Tsk4LpTn+b-iy}25uN>wvTfN+B~4r!aC19d7}&hDFchbqZ0;e7I0BK}RNujj9n zY8As>D%ez?Fkng~c1L3e^}<%h%!NhB5ZFmv4qmi`am*+A28lE6Pu4ekBJ8DW?YR4c zPeG`sZYLihHq~K3`oYvnQL$26Ojwnj1AOypgX_ca^06&6f`T8bedVhWj1y>F>d-sg zr9@SeL^T`CHIwyKW*F#~AZd==$aA_zOLRP>>S_&HK0s{HcEDpNQm9u|IZ{W%#*w4} zmN;)dX5OA?I{M$KLje0TCiQd&|g9E!YKD5 z)_8>@<$&L)EoO;WhhvUYgEDDJ8PPVpR_u`RN${}`PnjHc-4^~CwIh;mLF+#KK>Wc> zE|Wkj(OZ@zIa8-8rUq=a=x-F%J+$ozWaVUV@yS!{UWJ)}=^jM1_f&XffEjCb6H?Es zrqQ!sdrLtEHq=DIu@B|%&N$@{wC|>I`>>2EXn@+22x7PaM4p3V5XhXp8gSH8{)yq+VsXB@4DmPLA`4Qc`r2Z>3E&lVsUbpRejKO8Xc|ayAI6YT)d!q zrfQj!sa@T&5KPMxDUd4bZwub#5<;yenI>0~Zx=@R*M{S6d|Z3TAEsEW-w#undSQP7 z0ryg{By3CNOC^`$t=P&xCf<~vRz1}|>Oh+v>rBMi?&+;xKSGs;7Ie~^T>J4C9Ke&G zL&{aTYZk-|Pa*unK});DaF?Y=y73~NA0(lMPUz1G>G;8n^cmm2S>twrpU6ynN~J1! zHD!AXWk^D?nq)%#A^&d%DwIkh3Ku$<4{$Bnqe{R^e!E zD6qaK4g^V5kCJH~Ot$Im{2T}8sS28Gk(>QFg9I7A-=nDns|{X8NjAD%l(zhXxPR+i zsaKZiVQjKRN#@N{`Cm?#slb!NghtaUv~`T@mvslIbq5TcS-15muB2Hb$Zs``b(Pmm z>-keg*068f|SD zm-1~aS@!4?{PuWQ(%MlB?$oG~Y0UBQX_Nz{MC3%JvnoK+x5+GR`cIfTOE7r3_Xi|f z(1x{Bqg$A^m57WLbkEAc&hWkBABmV|cqNS(`o`}NaSI8Lm6{l$b%3paaK-^r1yrc* zQM|lY+je@P=AS7fX6VXPV>UYV77X|5G z5Zow(9=j+q0*H%#H}fpu-HF%`(GEbvHmWK({pqfv^b!p^KiWxjYXL)gZO^yLvY!1#{eH$?|l`7XcETF-V>)m#$Y-KUauf z^b+<*r?&Mks6o?n2JrEvgk?j+9|~S~2U~dq^}6M%or)_T?%jaFi!#+q3>YaIG?m3X z;{>&cQSHf29MCWgsDR$xyTZCe^~uYQ{iM+(@1tKCpyDxFoeVGQeW)9uT349)IDK!3 zsmbQfykCr7P5@r7$@N8b6KjN-vAfM%rz7|bveQ2v`Y|)B{2rfRwNw!r&1%%b*lWIy z+l$A~f%;yYgfY6h_(-1nXB!C4(VAsEqS^YKh9a{{_uW8t$M^?gPsm-J}^#E z_uO7hC+?sb1Iw^TeS$QC`8qwrX85eSYLIFX93I>dS^)6QIMdwX$;6F>2_T&M6o;jL zp&W3|Bd8rLlV}iSVY9G7Lo?V2_E`JVM(`rw^}DX9)wk0Q5GJ%esB@}u@C>dZ-byh| zBFz*MoXGGiF}DG?h!UZ#FN`;~1bd*pAWflMa5AtD-+Ut8Ymf#=b`potx5YLf&A%ZwGv$|Si7 z(0)Re$(F;{=Dhtq1%wCl0ijfk+T4jd3}^2Z$Q?L=1_lkM&nIax-Yo%VqZk6#Et%n& z0S9_V?yja0r@wi$m!-JJM2G=aQ@nYectR_Ln*dN6gmAR8L^dIf-bxR>0A)c$?#Ug@ zVlrY8#6Wp4wiP3OZ1@T=EBaaz(jrxuLG%?*J+=c#K7CorpL5*eKWVYiw<>#a7zv(N zO^RpkPM=xn!2?&s^7NCTu~a+aiGwc^_4Rnyqj!-l3-f+;6mkOx5@ynO(YF&u{yH5a z0{{W^{1E}V-LFeZcLzkH=SpZ_y1l&>1S=X`+@!Ai#KmNT?5ox%_;tp9`=F^;&%fxn zpX4I|M!d6`y%-8hequbo4%INVKruc+o|NwhsZB0<&TBCe}v2@CyI^$jlCsTrwmBFnzIMofx8PeKa1Av-Nj zlLtw2SI?rq_1(xc%<3sF%)ZrYIf>Xe7@jPt9BWoU%bg~g+6=1f;eW00nOrbo#*(mjYHCr_?8!#my~|i(0+2j{Uo+J%%rvg+%X5* z4!HCVyg~`t!LBG+X&89L&@QkGXe};GQ^moDsqI%U>#?IVQc53nUukdN%ij?m+%#Fv z*$`n_GFdWHC(!1z-ZhRjEV&n1wt#7VUXkgkW9Q5V;)k`XOO{*>9)xi@4}6zxlm4Ck zPC4Eq^0qB+yLg@{^VCgieuns3B!x#NzSr6q_VlhP>I4gzH4BI}DTx^r5(>Dyhc;-w znWU^i-9$N49%O1eIWyBV{K>wROpYjgCc5b?os*f=l~V;o)CB3G-E7LA7Rg3;!)~m@8(whM7Es zwF%4mEd^gMI<<|N60&DB)!+6-+8@EFbvGs4UP0$q5NEO<7?$NeaVcvz#eXkrXV;$H zPjNrI8gWTpphtwY&md>1N7T|$T^i@CM$EWZ;`6{q__Yr(^B!<>OPXT5%ICC%;4jl=T77^3T z0A$3`@j>`8*wH>vT`en;tj&YA60zbZw2F#^jE;rfTJ}-rcajHddN|Q>g}o$TX~osy`RPP=q0j_f1g@QgXPlY@q1Jh?-r4bB@~25Cj@AmJph{QR^Ya<4r(z*{F~ z=-nsVQY2K`sKEl*CR=AMEDIZD88T(wtjZ_((xf$>SIA*D#|jjfGw84wta;Nk03w~g zI(#i!OQDMse#AO065D@_gm?pQx@{rBjMat|bA$6MfVPq;S5zT5IKK&|LFZXuA zqj(kJK8jP}^ZYm?74hlPtf)m?w!rUP42d;f3Xx1K3raV-*P;*>hmzjAkyfcbEfZVM zJuLMoUQ0*&6p_BS@>f9!k`6HtNO_~}(0Jkg|_f8#- z!m%Jn^dX^G#qp$LnY0H)6WbFMeDL2eCjALoKs@6Ai81!~l3d5bNgZQ?f zTgufN#)|A&im|)K13cIGc?~(RCQ+E^pAR%xa6I`LxD$=mcOf z@v4=zb!i^TVJ(CsX?zlhk2fs((qe>+8Y#o60peO430M?7HT|g( zcVfD7@Ob>SyV%mu6}7g*=p&J}hJTo9hFn2o9Jy}QCXfAbC}WgpkeMXs7QNle)Z`PI zaU4~Uz`idIpQPmpq$?{N(5Wj_y%UX!5{=9|{BFV$P&Z}ciIVj<`zLyWb*T2wf|8o* zOk|-Qs_aJayia$?0k_jr6b#)1ONJ!Z;{~4NDyZJ6id*&SjT|kFCPH^!Q8MlaAE-*_ zNR!vqG}YZ6i}M3h>ENPmCHxC(#1( z7}2c0*RmVw1@+)M+n8t~gQT#+Yg3>|OA<9`Ynl5)ftY4g0EGA!t?E*;j*jRcB>mr~ z4f=etCrR1X;V_euWY<6p_AK%IoHB+bS8vl&LZ-5Q*QvzmfHq zZ>>MgWVvSa-wRV7cJ8O%vi&R+@2I&X=r`1P1;x8lhOpY4Z58^@Wm+--yBQ{&>GOL- zIJm(euOw?WYjBR|f~ue4(%k0i{lp`gI1~mF;g{;-0_gdf@ z*Q?M9wQ1ZdZwvrK|IY39={n^R^(zI|p=Px@ff|e_NEBug4N0vK!L9-J_DIiI7e5Pr z^Sce&Prjs*$mOY7Rf3V+?poBWP^ki{PIa+)OK%4)E`rV zxx7V^Qy14sZ;Dc2jD|ccyt5(5Zp~;Rg7N_IwB&EZ1jv&GoxT!1H7k>pY>Aa{$&oHg z`ykhr&GpvCL?|Xb;O}(ErzQAl=DZgICR);;Y=xkO<~chKzvaND<3}Wy~d>W0L>Q| z2-}wM73&w!hC@XZojB#$EnGzb4HAp3FWovUq|4f%x4KLKUg6YfVpokO|+JO^JSzIZEji>8`uBI~^1wYq9L`S;8*pu)y zTN!cO5)p_vO7vsEgglr#ee5WTiRh}7f0zLYNA)eB;_ z63%8_pGF-Dnkx@eu`dPn7Z1~vMk@*nIMW6HtpQX86HiyI1H>8W+4Y50C=@;!{F)Za-A9+#^G9aiAu<-#DuLR>+Vm6|21n$W?isfhl9KnurA)AcxJ* zIl$Iy_sl)Ewu1nV)Wiqc6M8RZ-OvG~x&%#S9h{L)QE&q|7$gk|*5h2|^bAvwHm@~P zRY4`*Kw4vB$#(Yqt2+Rd{vNGl*GA$FksiM6%fjfp!BEgA!3EEIq!j+(-cS%{(44@I z+KuDSMAy-fyJ3j}-3vV|_^?zVAkrrzw!3@QF<9e~z*m55Kjm<#D3z(4wCoyq=E3Z+5+o%*c82=9Dn;-mR<5ukCVG}$pfS0a zGXdRdAa-u4>?Cv7*|^+XrkWQGzzvT;h$l5u$vMI>9ouxPD^S{5-qvWAprQ>*&?#SpxdJ-SE&Kk2hn zy8lWI>IKrj;hSj%<-bXl8V%B!q_?jcj{k-hy&J%P3vb%^Qfyv08YOw$Qv~F2IOcFi z%I^ScI`VdU!El-&Werf%8X2asF7Tsk7{xt!qlOL$mCejuXC38O9pJ8y|M>$P50HUy zhcG}uKWP7NB@OTY;fq3kG@GPwLy>1x#YEu`vmQ=(0K)g*ckkeaAkM(C2nZ)rJS}8_IMTxIBXH|>190=4 zD%!`?a-E!T;jSVXMP%ETk{4ij&~`Q)&DZieRx)rLfXGfwvm9#PvZgMyX7+TpsoXa= z4Qq583C|0#1W{@tX6kUwtN40v^oyycsiqPP<(V!5f5bA~B0ZGZ{CU#4q>RznC|I_) z7I8BytRK$$wnfi79s*Phn%|0s_u9`zwWi2#=GE5F_sk({H`bq&(QCDy^X97O7~dVV zjm7hN0FhFY>Zr6d?l;%A(Z~&Ew$4)I4_&92>1%LB&Iz>(85AY z;VB`o-(qZZj2^wUL9TY=pDZ9{|L{Rg0eiHZxKR(>6I;B}xV?kpOG_~18o5kM9>bF; zvl22sk@FP)d1Mu!iPBd8n%hqPUH?B{lf+vBfKDaUjH};FB`hI|=TD}i4-Df(W|+FB zCt09JV@dNOy}=s3AS(U4&Ca^LI#IkDbY6-0Iby5ba=y`Wp2hYzhwTE5+|7W}HwTbp z9OzNwQYpe;mIt%rDX*W89h~mxYK3jmf-7Q*)B9kUP?Evo3sn(X81NyML>*eVx+RUlBPA+sDViBwk z7*Dl;#i5JP1+7=3^WriySJy*Ub#&|n!0jaOtW}%-grYW2t+eT{wz)iu1P?+?*78D4 z?m5`fN!6Uv7J4JU)^8tW`D-N9QO%RdtYTA8+bXhEgPf34?k{g{4Tq?|%C$Kz+U{9j z8RcUt*R}dKX*G74+BGaNebZUV{DCm;@U(5XnJYWyX(1gNvxR#br(Qa6)^hmsfX#aR zk+}yFE?Rp5@=+8!0rVoYMrk4eHt6+-pV!|CZFOXL81z;&nOQ!ct!B%hYyCe z$8CC^HadwLAC?`$JgYtvu%$b7`9Y=%pqA!R6Z96z- zLhL(4qE89OG&)oMjo05P>;5?Mp60` zPWdJ5-2@SE9T{-ytDRE{6sX)|Y1X;+C@K>yY^}14Y!088xh~SPfbJG?M1tBi?E>u?zdU>G{5+S>|$%tGJB zQ*X_vOy)g;@fbPm0a(Zh7zTzw2Ct$FB6Gz7!tmK*tZ2h588F#jY1p`jSJMli*7u-; z3tSU(fscAw1h}5i`&i`+?4UAF;AeV|b}3)i5zA^E*L0X|u;#%xYNx~?#g6jEh~;8t zQ8$5Sx)(-Y-j-9ugVW%b2(t*(k6(`>S>s9^t-podjkrgd0G}k7#${=(J0T7``%9)` zbz@# z89pMA4}>(ymEcPbh@I>#D9Az~sbv{(OXEh+fnx{b z6H8ULM@UCCdJbtvxLPl+w?prh49<(wWQ*(&g-1S%fFdrWy;&bp2wdG!zXt0n@O|(h^&64U7Am>%tK&1tn{(CN?9?pRJVbV0abQse6W* zjaunJ1r9_dkDSXE8y~{blX@E9+XdZr?+Cj9fSv4Dr%sM0X8+%}yVNrc%}Pks zfLfd-a~NL@9Ae&`->H9ihbrSTQK7`l0(9ei<9)-C-ZjdIKdOKOVrZbL^1x5+({hmz z^ka^IzOo7Z5kDX{UB^aJa=ZJ664{}im=U8r5}V}6e33gr#%&kPksN&;R!|y`-hx0+!ub!fTfgoWJ@3*jQ48CTp{?Y z$+bKR>!aBjD7x?Y0>>e`M#1*rfv0;edmByS@dJq0U>!j z12B#0J8%)E#AT3Tv<7hwsa2De$TgZ!6ya*gBbt8{dMpCoYg`{48qN!f$4KFI>9kSj zXqP7qQXV6DfRu{Jr(Mj>;=zUW>U{0sd8$z^(2$UE1b=z(K3T=YUsL(r3UwB%vS_@i zUw15;g`ql@wnozVkC>v|rqdrPO1t2>x^$SM@_>ucDEgntIq=60A2|p%szF-JmH5_! z>2S4sVX}c!H;5b!MnOy^fZYTP60VDhA{ikCTh{$>P4GK|N)1u_VGJ22k_IyXwj7Sj zcn5~M5{rQqE`|I<$3Bj`K#{b$K^z(UVwE$D46wB&kBgN&?rjSskPyQ3X&G^Acx^iv zW6lXF-}{o%ux^olbi{%ZmZM_C=6u(%CKQ={xs{jYqD zM26k$`Qj{UlW5Jt`l&1QP|d=7B{Dx;qd$8JdU$AE5&l(!MUkXC0mFRCM3JnDw?zVe z7`mm7)u~!VZs$|ahb9Y>#(9sjOV zcH~0w!lwVVM3oxLQd(|~MDZCpxbXh7qmbj2l;)N4J+?HVc6Jx7LG<@F&tGUvek#38UUOBInuVP22k}b4Ep?bEu^--cB#Ag|hqHNP79!T*v5&|g?2bQG86x5lB{ff(Rjr7|;rT&I0Ef(#dGARy zq-)N|z^0X-fAevH$bL+ip~x^dH#=T?vKN@HF~)7*3?~kd(`GwzGp*%S?H7db>`8F> zgx!tP`bl5-7lQ@AQ4i^?mNUb^ki+(Qvxg{R!^Ut%ya1_K$Ci-wGtO^W+(5We9^Z|i*}v@%bg{vBl7i??boO`xvQUh$k~C|d$i?y7U=W| z!<=;Y;tf9FpB=nOaU(_U#7Npj4id5?8H4? zsL^r@1_p9?VMR4cVe#mEOOH=f?>dB_m{#vzpM&E&KVbxd<&r?NMbz+F*duzV(?Y8LUgUpO4?&3)QPk z5&HoWONJr}EUHfHzJW4vCdqg&<>PN7f)paE#1!i^P<-8JfbLD7%T`A%By{h7P)CAW zJ1E&XBE96%#4a;dwNYQjcdiR0Nxh?uH~|2q&7C9LQ+QSv8X^PP0>Usz*HSS9C0>to ze1pO&s7BCS{x!VW_Pg@E-%TErJGYbnQ2hXL%RBzBNmFecgMmO#_uULhV~c2I)KHP{ zv{Eui!aMjaX?Mf>WoHp0KtGR^e4E^69*4@*{%8^>HwxUFNcSt7W0h7X$VzQ5JTGQg zLpd?yN%(bgiP_o-cst z@QA_VD0&n&*dj?j63J-vndy~X;lwmo=Q_8PV#w^VZOiYw;}mS|B;|u)e#GS8JRqxP zoWEuBMb#F=PknRG3P* z4GJA~MMpEbM%i4(YahXGEOSo2nB;oM z*5&1O`U}@hdRDps0PqD~2c@$6cz7sxmZ+b)O!Nllqto*I#I^<9nQ}0`3gtZjgFSc` zr<;IuXQCn=vP25FV3h8Z+}TdG6Sel7VCP+9#!U`9SHR~u*QtV&Ir;S6Z^sSGm|s;y z-f{CTn7y-&!B@eo#~6{h(77Nh6dHLyQG)b$p_3Gj)aRs!q6N>lUC*~^HSvWstrW}u z*CU=O3^xF*0&%aIQS)f~p!Vfgr70q9_)Pqs1=T}zL2n7bM8o8g#*F|Q%n>{#zGI3aoM5ptgqb|5#Q0-fuPveFm}*t#6J>nQI?04W zddadPl-27!^`1tRpwAVEqlr1diwI*)RCifevrPbt5Gp@fxs&zT5 zsb*ne&_BG~c(7H^P%7ADWn2!iMjp*h2XH3HT6VU72#$t`4=n-ZMCj(Lx2fTA@Q*v3DH1nr6oj-PQmZ9zCOcnn|~y1H8R1_aO#cRLv8n zA^SQ>qnD0V>X0{ZGw#)({*;uB(U$-bb3>y#gPQ0j{V0TAh2!q01pnET-gA>Z&%Zu& z{QmIumszVzi2m>gDlumvArvK|eWjErehNwr_*YQB+{U0n2iH{TJ z;qL1>Q|tNR;tK>w-Y~Xr!pxa~?@n`+EF(yvE$iV|s+c}C9kp5-ApELWNNyD z|D+=Q7PY%KH^%y&U#ewXB(vfZd=y2g6mLmY^!M=zO*K@jEGVFm+gRBYv6`7`j!j#_ z9w|2DzzCJJ^>~J#5j;E8*py74CK@&dIy0mkEqwTPE}}scXFHs_!v+39v(Q!~u%}FWO}FpFHX>#>99{bVQXu z&Mv05icalrL5O4IcpQ-%8V0q0)*4^oV6E1=wCFNkQG8D|Vcl#K3ekLmEmuno2}tcn+QcBWaoDND z?$>_WkP~3jJBVSpFIV5PxKA;nAt-PpDTxDvS|U0B~sCx$DrPuUWy1s-9;QX4FU@5U37&vhcuXyFpWC$dZ2bo2M?j zANK_Zrju>J;S;e;$Q-lXs>AJ;X+V(MnIVQV<}7RvF2tip0dAnk>SJRl?)-~WoU!77 zQ=Tzv)wwG*H6)RHIJxxBSAnc$34YukwX=MWwb+&MO&{6*3?R8{8xnSKM?Fx^SIqyB zbIrq9*-wfEPB-!(hD)U;417Yhr*_v$3yfCOLjgK9ct=m3wC4po@*K`;f?423NQ%Ha z=HQfTdxjl&#yC@aA?gUOwDc`m_JtKN%GtmX{+jhTzM{j)Zz!HLVWS zT3ud61ZuseM>#VB zB1v^H3>~f3ZuQ1y1W{>t-Z=ZAh`cL8Ph>}_y|h?Wg&}{_PP-`L`oK-Ig}U9hdlkA` zD(w7nYK?aP_vu?cAgjvw$DWY~|Nr`6dn+Ike-c>$`F=-2aTLj*LyZCcadEaCUHG~; z86DPAtoK5nu-&tR!-E*UKmtjQ&F-bed^U;yv{`=a-Q3MyR&EFcei`C7LwUEikDKv_ z{n2hUv{KSVf+2Ghr?p6~s8Uo}UNjM-Va{4f?=S0P)GQHiP&5mMDO6_~Oh#6NWhYTD zHVIY-Br?zR-A}*_d1E(u4)4jZiSX;qv}@p<)$5PHa8uof$- zN#h;PX!Sh`GyKY@#3`XavDTF!tlLp7pOnP|n7ydSTSeRN`9lT0{FsiXdyibTb1c%L zVA^GmC!c-pE7zzK?fNiiRLgGuZTzKsr@X+hJ&sngBnxa3+bfw(?G&G3Q%W|MUt{C{~s zF!W;nx?2MjfY!+%*n5u;$!Pee07wYZ@g^V02=j281Q-OI#l0q(9<@WCr<;o4(a|TM zH_t`S9?g&v-JRw*Z;u>5#?|UTBD=ggqWPrGOk$%Eut6-?OV>%E(R=5l*y|X#64&>rZ z#W3LPCfr7TgzQ0(qgidWUQd+uWMCx7o zEB>|%Jj&TVz$-D|qVAVU4!CF!@J}!yxFe4cX8SF|Y-XBWZzD>se-R!+{t?Wh6=}E7 zVI*Eoa1su_6K2`e8XfsS4OJM|U+&-7VS zIRJ0}JFs%}kcBm|$KkOHXW8Yj-C+KS#mq``V56%9am)P^?MzJPWU+*SyoQeWkRCz< zQ&Lq-Q>VTUJh=@7B#nHSC6HUHAey1!j}y>tP-yPh!o;992`-QHd7AI5t9 zPzm;}i0kMO6~Kl4TT`Y-BTU9Ku;r}*Q1TDl8m%S{+PFzk4&HGip;0#LkTx>X5q%>5 zvea2A%tl(PyC6CoWZ>)xHQQMu6n`UxQHJwS^%+zbld7C*CafaNLfh=(7&7eb)>jvC znLDJo2#ICn^BvWW7|$|a>!k)dOwPL;_Ao<@lzuJMoVs>;vkRhel4yyS2) zNMgz=@z?&pdF|R2kYSCb~_c?Vn#f0va))?V7TyrsA4t^o14=CVLW+YJt zornR!@R}SEh5X@8Mecwsv4(I7&TsC{FBAkUqM~hI4`ElK`EdgmwXTtz>9XPZVjTba zBi?BtsK{w&VnIK?b}XqbS5ujgFthngi(n$Qf0!GV*Ck3#A5=c-XwE4I2shGOBSw|T zij+DsI~26%8A9#jM#!kkG4k(|p=DlNOtp$^w;d!`3Z6v)Np-zYDWC&3J{ zwaUiwtA2L~pTeKQ%+q-puz^>p5WizwIVWT}a7;I6vmOl}V!9x!Q0+N)w0dK<>Zy?Q zIMqMK-zUY;#%$)=v;*}7l%0g)L@qrQ%(KKJ+7(26naCnPXDl!4!)l8vCvdPEi@Jw* z|6Y0vPmvHvkk-$$00p5yRzY+{Zx>_nKI_Xh)l_9kFz3dgjETw(U=}g;=}5EaiyMu4 z_K5!H6(p54QnUJxGgc8!K#+;aOOofhNq5c;z10R2IrtP1H4@T9A)rjBp`BPHrYhlL z+@cieQ3~0svr%Pi6*}fPW-L9x=CjjPl73d0y^9szowR56%tm}k>B)RtEMvOL*=5n6 z-O4NJdBneKC@(Ak6105naj(;SX_5pO7!J@7^!qDe`+jzeJ|J9eMX~dq_a4ty_&9?( zEDkVKBj$N0>Ka>58Y|PQq{Q2j-1e%45yo0bM~*k}vj%t;)h4!(={qG%V1_LSFm}aK zY-tE~MG&?}B;H1))pTEj@~LYqj3<1_=`$4^b24-b8Y}Do-qUr>x|NiG?ruc-9+TCz z;?EP^qy0SZdX`9sh!jt2^KgHyRrl?I`X8rO z8NK~qffuwrcv^i<^-sN;(~rF>En&Wk(?xUpXJ1i$BT!_#xy7-)Kt@ezB>Cmr;5qh^mji@urT}VzT*Om+_r%F`x$OqeakZ|EVfr%`L5IZXlLN1Lx$X$ z+~*?=bbBH!DkWE20Z&N_tCU_B5$>9N<-1b_)B4t9h0o5Fdg(TV#T=ZS;k;e9y5Pt( zcf%BKR`r}pq4b=}Y5!VT0!2?uu5S_u400^GsdDb9m9+E0!adTPK5T5=_*&)oy9xJV zF2%9jIC6B{IhfKk_L`{##PdAGvbj`=i^IWZR_QpWl7Pcg=0JJdXRWYv_wxuM9&rzRW2JGR-w|x_nY#<=SNhGv@xPUGak-)N>My zOneaxybJRv4`{BQkx7I>1a{^b!-nmXAIx>-%-v{b>i|3i&3>}pJSUmS2~`n_z^+yS z5F0W84=jO$-F%Y+=gUmi<5!s6KVLxR@N}V>dBECiGq5qIhN93#0IX18zN$3hPIm?d zV-!XFlLO}a%OLKmW?-;Ek-sboG(;JA1H1~@Hsm`!ZBY~!NrDxAkW>XLMBK-SZsJh| zutEn#h>3_B?HCwPO>9vHDV(GNHjo8$f7;~2gO;L~=q~SL-0fWZ~#j)X&6Bqf(AYY$jk0PJ03wGnXMds4rYbk)o%O?X5s6!3k zfXNPvon#Tm&!fx7m@-U0Xlej*iY)lxbYN7j0b(5#t3F$TR4GoDU7{+BI87QonpRme zOct=Q1)0SHI@Eabh9zRm!uB9RsmW9A4Z;2eABzjLU@_3Yb|{tzO}1YeB?~&EwGSvS z2b9-Gk@s+Bn7q;166{pOsgw*1jwq^ZTtTWtCL1hsmqk9p&jdx)T@RQl&dDjBieNJl zr|tj``9o2y>jP8GF7ag{X4W>)a%KhoKvyva1`M9A)97C%`B`O-U1bAu471WI(n_BRXdc33Qc~vQcM(m z%*7)yFC}Mk;$lTsaNBmW!75Q^;mHs)A-y`Vxw6QmkOqpmsncMpwYY?M85qRpg322J DDw4oP diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index cea7a793..ca025c83 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.14-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/gradlew b/gradlew index f5feea6d..23d15a93 100755 --- a/gradlew +++ b/gradlew @@ -86,8 +86,7 @@ done # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} # Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s -' "$PWD" ) || exit +APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -115,7 +114,7 @@ case "$( uname )" in #( NONSTOP* ) nonstop=true ;; esac -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar +CLASSPATH="\\\"\\\"" # Determine the Java command to use to start the JVM. @@ -206,7 +205,7 @@ fi DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' # Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, # and any embedded shellness will be escaped. # * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be # treated as '${Hostname}' itself on the command line. @@ -214,7 +213,7 @@ DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ + -jar "$APP_HOME/gradle/wrapper/gradle-wrapper.jar" \ "$@" # Stop when "xargs" is not available. diff --git a/gradlew.bat b/gradlew.bat index 9d21a218..db3a6ac2 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -70,11 +70,11 @@ goto fail :execute @rem Setup the command line -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar +set CLASSPATH= @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" -jar "%APP_HOME%\gradle\wrapper\gradle-wrapper.jar" %* :end @rem End local scope for the variables with windows NT shell From 503452a53912791693494eac42772e6aeca314d8 Mon Sep 17 00:00:00 2001 From: Space Walker Date: Sun, 2 Nov 2025 19:36:13 +0100 Subject: [PATCH 2/8] Loom/Ploceus 1.12 --- build.gradle | 8 ++++---- settings.gradle | 1 - 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/build.gradle b/build.gradle index 4b8ea6e6..5936a717 100644 --- a/build.gradle +++ b/build.gradle @@ -3,8 +3,8 @@ plugins { id 'eclipse' id 'idea' id 'maven-publish' - id 'fabric-loom' version '1.10-SNAPSHOT' apply false - id 'ploceus' version '1.10-SNAPSHOT' apply false + id 'fabric-loom' version '1.12-SNAPSHOT' apply false + id 'ploceus' version '1.12-SNAPSHOT' apply false } setUpJar(project) @@ -49,7 +49,7 @@ def setUpJar(project) { project.group = "${project.rootProject.root_maven_group}" project.ploceus { - setGeneration(2) + setIntermediaryGeneration(2) } project.repositories { @@ -194,7 +194,7 @@ def setUpModule(project, String... dependencies) { } } project.ploceus { - setGeneration(2) + setIntermediaryGeneration(2) } def libraries = getLibraryDependencies(project, dependencies) diff --git a/settings.gradle b/settings.gradle index cb6f2ac3..41a7d367 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,6 +1,5 @@ pluginManagement { repositories { - mavenLocal() maven { name = 'Fabric' url = 'https://maven.fabricmc.net/' From f07d6c727f2c749fb584c8e4eeb2fc12a0d08f9f Mon Sep 17 00:00:00 2001 From: Space Walker Date: Fri, 21 Nov 2025 17:59:10 +0100 Subject: [PATCH 3/8] update workflows --- .github/workflows/build.yml | 8 ++++++-- .github/workflows/publish.yml | 10 +++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index de36b9dd..d219fc9d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -16,11 +16,15 @@ jobs: - uses: actions/setup-java@v4 with: distribution: 'temurin' - java-version: '17' + java-version: '21' - - name: validate gradle wrapper + - name: wrapper validation uses: gradle/actions/wrapper-validation@v4 + - name: make gradle wrapper executable + if: ${{ runner.os != 'Windows' }} + run: chmod +x ./gradlew + - name: build run: ./gradlew build --stacktrace diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 6c1a18f1..f531fae0 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -2,7 +2,7 @@ name: Release on: [workflow_dispatch] # Manual trigger jobs: build: - runs-on: ${{ matrix.os }} + runs-on: ubuntu-24.04 steps: - name: checkout repository uses: actions/checkout@v4 @@ -10,11 +10,15 @@ jobs: - uses: actions/setup-java@v4 with: distribution: 'temurin' - java-version: '17' + java-version: '21' - - name: validate gradle wrapper + - name: wrapper validation uses: gradle/actions/wrapper-validation@v4 + - name: make gradle wrapper executable + if: ${{ runner.os != 'Windows' }} + run: chmod +x ./gradlew + - name: build run: ./gradlew build publish --stacktrace env: From bcb9fa0b325636d50bfaa63b8c06473ac706a579 Mon Sep 17 00:00:00 2001 From: Space Walker Date: Mon, 25 Aug 2025 16:56:45 +0200 Subject: [PATCH 4/8] rewrite networking api --- libraries/networking-impl/build.gradle | 1 + libraries/networking-impl/gradle.properties | 2 + .../build.gradle | 5 + .../gradle.properties | 7 + .../osl/networking/impl/Networking.java | 57 + .../client/ClientPlayNetworkHandlerMixin.java | 19 +- .../impl/mixin/client/MinecraftMixin.java | 18 + .../common/CustomPayloadC2SPacketMixin.java | 63 + .../common/CustomPayloadS2CPacketMixin.java | 31 + .../mixin/common/MinecraftServerMixin.java | 18 + .../impl/mixin/common/PlayerManagerMixin.java | 4 +- .../common/ServerPlayNetworkHandlerMixin.java | 17 +- .../main/resources/osl.networking.mixins.json | 4 +- .../build.gradle | 5 + .../gradle.properties | 7 + .../osl/networking/impl/Networking.java | 56 + .../client/ClientPlayNetworkHandlerMixin.java | 19 +- .../impl/mixin/client/MinecraftMixin.java | 18 + .../common/CustomPayloadC2SPacketMixin.java | 52 + .../common/CustomPayloadS2CPacketMixin.java | 31 + .../mixin/common/MinecraftServerMixin.java | 18 + .../impl/mixin/common/PlayerManagerMixin.java | 4 +- .../common/ServerPlayNetworkHandlerMixin.java | 17 +- .../main/resources/osl.networking.mixins.json | 5 +- .../build.gradle | 5 + .../gradle.properties | 0 .../osl/networking/impl/Networking.java | 59 + .../interfaces/mixin/INetworkHandler.java | 8 - .../client/ClientNetworkHandlerMixin.java | 28 +- .../impl/mixin/client/MinecraftMixin.java | 44 + .../impl/mixin/common/ConnectionMixin.java | 33 + .../common/CustomPayloadPacketMixin.java | 39 + .../impl/mixin/common/PacketHandlerMixin.java | 0 .../mixin/server/MinecraftServerMixin.java | 48 + .../ServerLoginNetworkHandlerMixin.java | 0 .../server/ServerPlayNetworkHandlerMixin.java | 26 +- .../main/resources/osl.networking.mixins.json | 5 +- .../build.gradle | 5 + .../gradle.properties | 0 .../osl/networking/impl/Networking.java | 57 + .../interfaces/mixin/INetworkHandler.java | 8 - .../client/ClientNetworkHandlerMixin.java | 28 +- .../impl/mixin/client/MinecraftMixin.java | 44 + .../impl/mixin/common/ConnectionMixin.java | 33 + .../common/CustomPayloadPacketMixin.java | 39 + .../impl/mixin/common/PacketHandlerMixin.java | 0 .../mixin/server/MinecraftServerMixin.java | 48 + .../ServerLoginNetworkHandlerMixin.java | 0 .../server/ServerPlayNetworkHandlerMixin.java | 26 +- .../main/resources/osl.networking.mixins.json | 5 +- .../build.gradle | 5 + .../gradle.properties | 0 .../osl/networking/impl/Networking.java | 57 + .../client/ClientNetworkHandlerMixin.java | 29 +- .../impl/mixin/client/MinecraftMixin.java | 44 + .../impl/mixin/common/ConnectionMixin.java | 33 + .../common/CustomPayloadPacketMixin.java | 39 + .../mixin/common/MinecraftServerMixin.java | 48 + .../ServerLoginNetworkHandlerMixin.java | 0 .../common/ServerPlayNetworkHandlerMixin.java | 27 +- .../main/resources/osl.networking.mixins.json | 5 +- .../build.gradle | 5 + .../gradle.properties | 4 +- .../osl/networking/impl/Networking.java | 57 + .../client/ClientNetworkHandlerMixin.java | 29 +- .../mixin/client/LocalConnectionMixin.java | 32 + .../impl/mixin/client/MinecraftMixin.java | 44 + .../common/CustomPayloadPacketMixin.java | 39 + .../mixin/common/MinecraftServerMixin.java | 44 + .../impl/mixin/common/PlayerManagerMixin.java | 2 +- .../mixin/common/RemoteConnectionMixin.java | 33 + .../common/ServerPlayNetworkHandlerMixin.java | 29 +- .../main/resources/osl.networking.mixins.json | 6 +- .../build.gradle | 5 + .../gradle.properties | 0 .../osl/networking/impl/Networking.java | 56 + .../client/ClientPlayNetworkHandlerMixin.java | 20 +- .../impl/mixin/client/MinecraftMixin.java | 44 + .../common/CustomPayloadC2SPacketMixin.java | 41 + .../common/CustomPayloadS2CPacketMixin.java | 41 + .../mixin/common/MinecraftServerMixin.java | 44 + .../impl/mixin/common/PacketMixin.java | 28 + .../impl/mixin/common/PlayerManagerMixin.java | 0 .../common/ServerPlayNetworkHandlerMixin.java | 17 +- .../main/resources/osl.networking.mixins.json | 23 + .../build.gradle | 5 + .../gradle.properties | 0 .../osl/networking/impl/Networking.java | 56 + .../client/ClientPlayNetworkHandlerMixin.java | 19 +- .../impl/mixin/client/MinecraftMixin.java | 18 + .../common/CustomPayloadC2SPacketMixin.java | 41 + .../common/CustomPayloadS2CPacketMixin.java | 41 + .../mixin/common/MinecraftServerMixin.java | 18 + .../impl/mixin/common/PlayerManagerMixin.java | 11 +- .../common/ServerPlayNetworkHandlerMixin.java | 18 +- .../main/resources/osl.networking.mixins.json | 5 +- .../build.gradle | 5 + .../gradle.properties | 0 .../osl/networking/impl/Networking.java | 56 + .../client/ClientPlayNetworkHandlerMixin.java | 85 ++ .../impl/mixin/client/MinecraftMixin.java | 18 + .../common/CustomPayloadC2SPacketMixin.java | 63 + .../common/CustomPayloadS2CPacketMixin.java | 42 + .../mixin/common/MinecraftServerMixin.java | 18 + .../impl/mixin/common/PlayerManagerMixin.java | 40 + .../common/ServerPlayNetworkHandlerMixin.java | 73 + .../main/resources/osl.networking.mixins.json | 22 + .../build.gradle | 5 + .../gradle.properties | 7 + .../osl/networking/impl/Networking.java | 56 + .../client/ClientPlayNetworkHandlerMixin.java | 85 ++ .../impl/mixin/client/MinecraftMixin.java | 22 + .../common/CustomPayloadC2SPacketMixin.java | 52 + .../common/CustomPayloadS2CPacketMixin.java | 31 + .../mixin/common/MinecraftServerMixin.java | 22 + .../impl/mixin/common/PlayerManagerMixin.java | 0 .../common/ServerPlayNetworkHandlerMixin.java | 73 + .../main/resources/osl.networking.mixins.json | 22 + .../build.gradle | 5 + .../gradle.properties | 10 + .../networking/impl/CustomPayloadPacket.java | 74 + .../osl/networking/impl/Networking.java | 38 + .../interfaces/mixin/INetworkHandler.java | 8 - .../client/ClientNetworkHandlerMixin.java | 30 +- .../mixin/client/HandshakePacketMixin.java | 0 .../client/LocalClientPlayerEntityMixin.java | 21 + .../impl/mixin/client/MinecraftMixin.java | 44 + .../impl/mixin/common/ConnectionMixin.java | 33 + .../impl/mixin/common/PacketAccessor.java | 0 .../main/resources/osl.networking.mixins.json | 4 +- .../build.gradle | 5 + .../gradle.properties | 0 .../networking/impl/CustomPayloadPacket.java | 74 + .../osl/networking/impl/Networking.java | 49 + .../interfaces/mixin/INetworkHandler.java | 8 - .../client/ClientNetworkHandlerMixin.java | 26 +- .../mixin/client/HandshakePacketMixin.java | 0 .../impl/mixin/client/MinecraftMixin.java | 44 + .../impl/mixin/common/ConnectionMixin.java | 33 + .../impl/mixin/common/PacketAccessor.java | 0 .../mixin/server/MinecraftServerMixin.java | 48 + .../ServerLoginNetworkHandlerMixin.java | 2 +- .../server/ServerPlayNetworkHandlerMixin.java | 26 +- .../main/resources/osl.networking.mixins.json | 5 +- .../build.gradle | 5 + .../gradle.properties | 0 .../networking/impl/CustomPayloadPacket.java | 39 +- .../osl/networking/impl/Networking.java | 49 + .../interfaces/mixin/INetworkHandler.java | 8 - .../client/ClientNetworkHandlerMixin.java | 26 +- .../mixin/client/HandshakePacketMixin.java | 0 .../impl/mixin/client/MinecraftMixin.java | 44 + .../impl/mixin/common/ConnectionMixin.java | 33 + .../impl/mixin/common/PacketAccessor.java | 0 .../mixin/server/MinecraftServerMixin.java | 48 + .../ServerLoginNetworkHandlerMixin.java | 2 +- .../server/ServerPlayNetworkHandlerMixin.java | 26 +- .../main/resources/osl.networking.mixins.json | 23 + .../build.gradle | 5 + .../gradle.properties | 10 + .../networking/impl/CustomPayloadPacket.java | 74 + .../osl/networking/impl/Networking.java | 35 + .../interfaces/mixin/INetworkHandler.java | 8 - .../impl/mixin/common/ConnectionMixin.java | 33 + .../impl/mixin/common/PacketAccessor.java | 0 .../mixin/server/MinecraftServerMixin.java | 48 + .../ServerLoginNetworkHandlerMixin.java | 2 +- .../server/ServerPlayNetworkHandlerMixin.java | 26 +- .../main/resources/osl.networking.mixins.json | 2 + .../networking-impl/icon.png | Bin 0 -> 365675 bytes .../src/main/resources/fabric.mod.json | 41 + .../build.gradle | 4 - .../gradle.properties | 7 - .../osl/networking/api/CustomPayload.java | 13 - .../osl/networking/api/PacketByteBufs.java | 31 - .../api/client/ClientPlayNetworking.java | 154 --- .../api/server/ServerPlayNetworking.java | 317 ----- .../osl/networking/impl/HandshakePayload.java | 55 - .../osl/networking/impl/NetworkListener.java | 20 - .../osl/networking/impl/Networking.java | 57 - .../impl/client/ClientPlayNetworkingImpl.java | 183 --- .../mixin/ICustomPayloadPacket.java | 12 - .../interfaces/mixin/INetworkHandler.java | 15 - .../common/CustomPayloadC2SPacketMixin.java | 27 - .../impl/server/ServerPlayNetworkingImpl.java | 286 ---- .../networking-mc11w49a-mc12w16a/build.gradle | 4 - .../osl/networking/api/CustomPayload.java | 13 - .../osl/networking/api/DataStreams.java | 23 - .../api/client/ClientConnectionEvents.java | 70 - .../api/client/ClientPlayNetworking.java | 158 --- .../api/server/ServerConnectionEvents.java | 71 - .../api/server/ServerPlayNetworking.java | 321 ----- .../osl/networking/impl/HandshakePayload.java | 57 - .../osl/networking/impl/Networking.java | 57 - .../impl/client/ClientPlayNetworkingImpl.java | 179 --- .../common/CustomPayloadPacketMixin.java | 23 - .../impl/server/ServerPlayNetworkingImpl.java | 280 ---- .../networking-mc12w17a-mc12w17a/build.gradle | 4 - .../osl/networking/api/CustomPayload.java | 13 - .../osl/networking/api/DataStreams.java | 23 - .../api/client/ClientConnectionEvents.java | 70 - .../api/client/ClientPlayNetworking.java | 158 --- .../api/server/ServerConnectionEvents.java | 71 - .../api/server/ServerPlayNetworking.java | 321 ----- .../osl/networking/impl/HandshakePayload.java | 57 - .../osl/networking/impl/Networking.java | 57 - .../impl/client/ClientPlayNetworkingImpl.java | 179 --- .../common/CustomPayloadPacketMixin.java | 23 - .../impl/server/ServerPlayNetworkingImpl.java | 280 ---- .../networking-mc12w18a-mc12w19a/build.gradle | 4 - .../osl/networking/api/CustomPayload.java | 13 - .../osl/networking/api/DataStreams.java | 23 - .../api/client/ClientPlayNetworking.java | 158 --- .../api/server/ServerPlayNetworking.java | 321 ----- .../osl/networking/impl/HandshakePayload.java | 57 - .../osl/networking/impl/Networking.java | 57 - .../impl/client/ClientPlayNetworkingImpl.java | 168 --- .../interfaces/mixin/INetworkHandler.java | 13 - .../common/CustomPayloadPacketMixin.java | 23 - .../impl/server/ServerPlayNetworkingImpl.java | 269 ---- .../osl/networking/api/CustomPayload.java | 13 - .../osl/networking/api/DataStreams.java | 23 - .../api/client/ClientConnectionEvents.java | 82 -- .../api/client/ClientPlayNetworking.java | 158 --- .../api/server/ServerConnectionEvents.java | 83 -- .../api/server/ServerPlayNetworking.java | 321 ----- .../osl/networking/impl/HandshakePayload.java | 57 - .../osl/networking/impl/Networking.java | 57 - .../impl/client/ClientPlayNetworkingImpl.java | 168 --- .../interfaces/mixin/INetworkHandler.java | 13 - .../common/CustomPayloadPacketMixin.java | 23 - .../impl/server/ServerPlayNetworkingImpl.java | 269 ---- .../osl/networking/api/CustomPayload.java | 13 - .../osl/networking/api/PacketByteBufs.java | 31 - .../api/client/ClientConnectionEvents.java | 82 -- .../api/client/ClientPlayNetworking.java | 174 --- .../osl/networking/impl/HandshakePayload.java | 55 - .../osl/networking/impl/Networking.java | 57 - .../impl/client/ClientPlayNetworkingImpl.java | 184 --- .../mixin/ICustomPayloadPacket.java | 12 - .../interfaces/mixin/INetworkHandler.java | 13 - .../client/CustomPayloadS2CPacketMixin.java | 24 - .../common/CustomPayloadC2SPacketMixin.java | 24 - .../impl/server/ServerPlayNetworkingImpl.java | 309 ----- .../build.gradle | 0 .../gradle.properties | 7 + .../IdentifierChannelIdentifierParser.java | 49 + .../osl/networking/api/PacketBuffer.java | 1227 +++++++++++++++++ .../osl/networking/api/PacketBuffers.java | 41 + .../osl/networking/api/PacketPayload.java | 11 + .../api/client/ClientConnectionEvents.java | 0 .../api/client/ClientPacketListener.java | 31 + .../api/client/ClientPlayNetworking.java | 153 ++ .../api/server/ServerConnectionEvents.java | 0 .../api/server/ServerPacketListener.java | 32 + .../api/server/ServerPlayNetworking.java | 189 +-- .../osl/networking/impl/HandshakePayload.java | 61 + .../osl/networking/impl/PacketFactory.java | 15 + .../access/CustomPayloadPacketAccess.java | 12 + .../impl/access/NetworkHandlerAccess.java | 15 + .../impl/access/PlayerManagerAccess.java | 11 + .../impl/access/TaskRunnerAccess.java | 7 + .../impl/client/ClientPlayNetworkingImpl.java | 267 ++++ .../impl/server/ServerPlayNetworkingImpl.java | 420 ++++++ .../networking-mc14w21a-mc14w30c/build.gradle | 4 - .../osl/networking/api/CustomPayload.java | 13 - .../osl/networking/api/PacketByteBufs.java | 31 - .../api/client/ClientConnectionEvents.java | 82 -- .../api/client/ClientPlayNetworking.java | 201 --- .../api/server/ServerConnectionEvents.java | 83 -- .../osl/networking/impl/HandshakePayload.java | 55 - .../osl/networking/impl/NetworkListener.java | 20 - .../osl/networking/impl/Networking.java | 57 - .../impl/client/ClientPlayNetworkingImpl.java | 214 --- .../interfaces/mixin/INetworkHandler.java | 13 - .../impl/interfaces/mixin/IPlayerManager.java | 13 - .../impl/server/ServerPlayNetworkingImpl.java | 339 ----- .../main/resources/osl.networking.mixins.json | 18 - .../build.gradle | 4 - .../osl/networking/api/CustomPayload.java | 13 - .../osl/networking/api/PacketByteBufs.java | 31 - .../api/client/ClientConnectionEvents.java | 82 -- .../api/client/ClientPlayNetworking.java | 153 -- .../api/server/ServerConnectionEvents.java | 83 -- .../api/server/ServerPlayNetworking.java | 316 ----- .../osl/networking/impl/HandshakePayload.java | 55 - .../osl/networking/impl/NetworkListener.java | 20 - .../osl/networking/impl/Networking.java | 57 - .../impl/client/ClientPlayNetworkingImpl.java | 185 --- .../interfaces/mixin/INetworkHandler.java | 13 - .../impl/interfaces/mixin/IPlayerManager.java | 13 - .../impl/server/ServerPlayNetworkingImpl.java | 286 ---- .../main/resources/osl.networking.mixins.json | 18 - .../gradle.properties | 2 +- .../osl/networking/api/CustomPayload.java | 13 - .../IdentifierChannelIdentifierParser.java | 49 + .../osl/networking/api/PacketBuffer.java | 1113 +++++++++++++++ .../osl/networking/api/PacketBuffers.java | 41 + .../osl/networking/api/PacketByteBufs.java | 31 - .../osl/networking/api/PacketPayload.java | 11 + .../api/client/ClientPacketListener.java | 31 + .../api/client/ClientPlayNetworking.java | 103 +- .../api/server/ServerPacketListener.java | 32 + .../api/server/ServerPlayNetworking.java | 216 +-- .../osl/networking/impl/HandshakePayload.java | 44 +- .../osl/networking/impl/NetworkListener.java | 20 - .../osl/networking/impl/Networking.java | 57 - .../osl/networking/impl/PacketFactory.java | 13 + .../access/CustomPayloadPacketAccess.java | 12 + .../impl/access/NetworkHandlerAccess.java | 15 + .../impl/access/PlayerManagerAccess.java | 11 + .../impl/access/TaskRunnerAccess.java | 7 + .../impl/client/ClientPlayNetworkingImpl.java | 232 +++- .../mixin/ICustomPayloadPacket.java | 12 - .../interfaces/mixin/INetworkHandler.java | 15 - .../client/ClientPlayNetworkHandlerMixin.java | 85 -- .../common/CustomPayloadC2SPacketMixin.java | 27 - .../common/ServerPlayNetworkHandlerMixin.java | 73 - .../impl/server/ServerPlayNetworkingImpl.java | 389 ++++-- .../build.gradle | 2 +- .../osl/networking/api/CustomPayload.java | 13 - .../osl/networking/api/DataStreams.java | 23 - .../osl/networking/api/PacketBuffer.java | 1217 ++++++++++++++++ .../osl/networking/api/PacketBuffers.java | 35 + .../osl/networking/api/PacketPayload.java | 11 + .../api/client/ClientConnectionEvents.java | 12 + .../api/client/ClientPacketListener.java | 31 + .../api/client/ClientPlayNetworking.java | 123 +- .../osl/networking/impl/Connections.java | 22 + .../networking/impl/CustomPayloadPacket.java | 75 - .../osl/networking/impl/HandshakePayload.java | 49 +- .../osl/networking/impl/Networking.java | 37 - .../osl/networking/impl/PacketFactory.java | 11 + .../access/CustomPayloadPacketAccess.java | 11 + .../impl/access/LocalClientPlayerAccess.java | 9 + .../impl/access/NetworkHandlerAccess.java | 17 + .../impl/access/TaskRunnerAccess.java | 7 + .../impl/client/ClientPlayNetworkingImpl.java | 240 +++- .../LocalClientPlayerEntityAccessor.java | 16 - .../build.gradle | 0 .../gradle.properties | 8 + .../osl/networking/api/PacketBuffer.java | 1217 ++++++++++++++++ .../osl/networking/api/PacketBuffers.java | 35 + .../osl/networking/api/PacketPayload.java | 11 + .../api/client/ClientConnectionEvents.java | 0 .../api/client/ClientPacketListener.java | 31 + .../api/client/ClientPlayNetworking.java | 153 ++ .../api/server/ServerConnectionEvents.java | 0 .../api/server/ServerPacketListener.java | 32 + .../api/server/ServerPlayNetworking.java | 204 ++- .../osl/networking/impl/Connections.java | 22 + .../osl/networking/impl/HandshakePayload.java | 61 + .../osl/networking/impl/PacketFactory.java | 11 + .../access/CustomPayloadPacketAccess.java | 11 + .../impl/access/NetworkHandlerAccess.java | 17 + .../impl/access/TaskRunnerAccess.java | 7 + .../impl/client/ClientPlayNetworkingImpl.java | 265 ++++ .../impl/server/ServerPlayNetworkingImpl.java | 417 ++++++ .../networking-mcb1.0-mcb1.4_01/build.gradle | 4 - .../osl/networking/api/CustomPayload.java | 13 - .../osl/networking/api/DataStreams.java | 23 - .../api/client/ClientConnectionEvents.java | 70 - .../api/client/ClientPlayNetworking.java | 158 --- .../api/server/ServerConnectionEvents.java | 71 - .../api/server/ServerPlayNetworking.java | 321 ----- .../networking/impl/CustomPayloadPacket.java | 75 - .../osl/networking/impl/HandshakePayload.java | 54 - .../osl/networking/impl/Networking.java | 58 - .../impl/client/ClientPlayNetworkingImpl.java | 168 --- .../ServerLoginNetworkHandlerMixin.java | 61 - .../server/ServerPlayNetworkHandlerMixin.java | 64 - .../impl/server/ServerPlayNetworkingImpl.java | 269 ---- .../networking-mcb1.5-mc11w48a/build.gradle | 4 - .../osl/networking/api/CustomPayload.java | 13 - .../osl/networking/api/DataStreams.java | 23 - .../api/client/ClientConnectionEvents.java | 70 - .../api/client/ClientPlayNetworking.java | 158 --- .../api/server/ServerConnectionEvents.java | 71 - .../api/server/ServerPlayNetworking.java | 321 ----- .../osl/networking/impl/HandshakePayload.java | 57 - .../osl/networking/impl/Networking.java | 58 - .../impl/client/ClientPlayNetworkingImpl.java | 168 --- .../impl/server/ServerPlayNetworkingImpl.java | 269 ---- .../build.gradle | 0 .../gradle.properties | 4 +- .../osl/networking/api/PacketBuffer.java | 1217 ++++++++++++++++ .../osl/networking/api/PacketBuffers.java | 35 + .../osl/networking/api/PacketPayload.java | 11 + .../api/server/ServerConnectionEvents.java | 2 +- .../api/server/ServerPacketListener.java | 32 + .../api/server/ServerPlayNetworking.java | 295 ++++ .../osl/networking/impl/Connections.java | 22 + .../osl/networking/impl/HandshakePayload.java | 56 + .../osl/networking/impl/PacketFactory.java | 11 + .../access/CustomPayloadPacketAccess.java | 11 + .../impl/access/NetworkHandlerAccess.java | 17 + .../impl/access/TaskRunnerAccess.java | 7 + .../impl/server/ServerPlayNetworkingImpl.java | 385 ++++++ .../main/resources/osl.networking.mixins.json | 6 +- .../osl/networking/api/CustomPayload.java | 13 - .../osl/networking/api/DataStreams.java | 23 - .../api/server/ServerConnectionEvents.java | 71 - .../api/server/ServerPlayNetworking.java | 265 ---- .../networking/impl/CustomPayloadPacket.java | 75 - .../osl/networking/impl/HandshakePayload.java | 53 - .../osl/networking/impl/Networking.java | 34 - .../impl/server/ServerPlayNetworkingImpl.java | 245 ---- .../osl/networking/api/CustomPayload.java | 13 - .../osl/networking/api/DataStreams.java | 23 - .../osl/networking/api/PacketBuffer.java | 1217 ++++++++++++++++ .../osl/networking/api/PacketBuffers.java | 35 + .../osl/networking/api/PacketPayload.java | 11 + .../api/server/ServerConnectionEvents.java | 12 + .../api/server/ServerPacketListener.java | 32 + .../api/server/ServerPlayNetworking.java | 236 ++-- .../osl/networking/impl/Connections.java | 22 + .../networking/impl/CustomPayloadPacket.java | 75 - .../osl/networking/impl/HandshakePayload.java | 49 +- .../osl/networking/impl/Networking.java | 34 - .../osl/networking/impl/PacketFactory.java | 11 + .../access/CustomPayloadPacketAccess.java | 11 + .../impl/access/NetworkHandlerAccess.java | 17 + .../impl/access/TaskRunnerAccess.java | 7 + .../interfaces/mixin/INetworkHandler.java | 17 - .../impl/mixin/common/PacketAccessor.java | 15 - .../impl/server/ServerPlayNetworkingImpl.java | 380 +++-- .../main/resources/osl.networking.mixins.json | 4 +- .../networking/api/ChannelIdentifiers.java | 108 ++ .../osl/networking/api/Channels.java | 20 - .../api/StringChannelIdentifierParser.java | 71 + .../impl/ChannelIdentifierException.java | 31 + .../impl/ChannelIdentifierParseException.java | 21 + .../osl/networking/impl/Constants.java | 14 +- .../src/main/resources/fabric.mod.json | 10 - settings.gradle | 30 +- 435 files changed, 16503 insertions(+), 14914 deletions(-) create mode 100644 libraries/networking-impl/build.gradle create mode 100644 libraries/networking-impl/gradle.properties create mode 100644 libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/build.gradle create mode 100644 libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/gradle.properties create mode 100644 libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/java/net/ornithemc/osl/networking/impl/Networking.java rename libraries/{networking/networking-mc14w21a-mc14w30c => networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3}/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java (75%) create mode 100644 libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java create mode 100644 libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java create mode 100644 libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadS2CPacketMixin.java create mode 100644 libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/MinecraftServerMixin.java rename libraries/{networking/networking-mc14w21a-mc14w30c => networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3}/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java (89%) rename libraries/{networking/networking-mc13w41a-mc14w20b => networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3}/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java (76%) rename libraries/{networking/networking-mc13w41a-mc14w20b => networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3}/src/main/resources/osl.networking.mixins.json (79%) create mode 100644 libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/build.gradle create mode 100644 libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/gradle.properties create mode 100644 libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/java/net/ornithemc/osl/networking/impl/Networking.java rename libraries/{networking/networking-mc13w41a-mc14w20b => networking-impl/networking-impl-mc1.13-pre4-mc1.13.2}/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java (75%) create mode 100644 libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java create mode 100644 libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java create mode 100644 libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadS2CPacketMixin.java create mode 100644 libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/MinecraftServerMixin.java rename libraries/{networking/networking-mc14w31a-mc1.13-pre2 => networking-impl/networking-impl-mc1.13-pre4-mc1.13.2}/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java (89%) rename libraries/{networking/networking-mc14w31a-mc1.13-pre2 => networking-impl/networking-impl-mc1.13-pre4-mc1.13.2}/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java (76%) rename libraries/{networking/networking-mc18w31a-mc1.14.4 => networking-impl/networking-impl-mc1.13-pre4-mc1.13.2}/src/main/resources/osl.networking.mixins.json (70%) create mode 100644 libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/build.gradle rename libraries/{networking/networking-mc11w49a-mc12w16a => networking-impl/networking-impl-mc11w49a-mc12w16a}/gradle.properties (100%) create mode 100644 libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java rename libraries/{networking/networking-mc11w49a-mc12w16a => networking-impl/networking-impl-mc11w49a-mc12w16a}/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java (55%) rename libraries/{networking/networking-mc12w17a-mc12w17a => networking-impl/networking-impl-mc11w49a-mc12w16a}/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java (65%) create mode 100644 libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java create mode 100644 libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ConnectionMixin.java create mode 100644 libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadPacketMixin.java rename libraries/{networking/networking-mc11w49a-mc12w16a => networking-impl/networking-impl-mc11w49a-mc12w16a}/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketHandlerMixin.java (100%) create mode 100644 libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/MinecraftServerMixin.java rename libraries/{networking/networking-mc11w49a-mc12w16a => networking-impl/networking-impl-mc11w49a-mc12w16a}/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerLoginNetworkHandlerMixin.java (100%) rename libraries/{networking/networking-mc11w49a-mc12w16a => networking-impl/networking-impl-mc11w49a-mc12w16a}/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java (68%) rename libraries/{networking/networking-mc11w49a-mc12w16a => networking-impl/networking-impl-mc11w49a-mc12w16a}/src/main/resources/osl.networking.mixins.json (75%) create mode 100644 libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/build.gradle rename libraries/{networking/networking-mc12w17a-mc12w17a => networking-impl/networking-impl-mc12w17a-mc12w17a}/gradle.properties (100%) create mode 100644 libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java rename libraries/{networking/networking-mc12w17a-mc12w17a => networking-impl/networking-impl-mc12w17a-mc12w17a}/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java (55%) rename libraries/{networking/networking-mc11w49a-mc12w16a => networking-impl/networking-impl-mc12w17a-mc12w17a}/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java (65%) create mode 100644 libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java create mode 100644 libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ConnectionMixin.java create mode 100644 libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadPacketMixin.java rename libraries/{networking/networking-mc12w17a-mc12w17a => networking-impl/networking-impl-mc12w17a-mc12w17a}/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketHandlerMixin.java (100%) create mode 100644 libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/MinecraftServerMixin.java rename libraries/{networking/networking-mc12w17a-mc12w17a => networking-impl/networking-impl-mc12w17a-mc12w17a}/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerLoginNetworkHandlerMixin.java (100%) rename libraries/{networking/networking-mc12w17a-mc12w17a => networking-impl/networking-impl-mc12w17a-mc12w17a}/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java (71%) rename libraries/{networking/networking-mc12w17a-mc12w17a => networking-impl/networking-impl-mc12w17a-mc12w17a}/src/main/resources/osl.networking.mixins.json (75%) create mode 100644 libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/build.gradle rename libraries/{networking/networking-mc12w18a-mc12w19a => networking-impl/networking-impl-mc12w18a-mc12w19a}/gradle.properties (100%) create mode 100644 libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java rename libraries/{networking/networking-mc12w18a-mc12w19a => networking-impl/networking-impl-mc12w18a-mc12w19a}/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java (66%) create mode 100644 libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java create mode 100644 libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ConnectionMixin.java create mode 100644 libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadPacketMixin.java create mode 100644 libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/MinecraftServerMixin.java rename libraries/{networking/networking-mc12w18a-mc12w19a => networking-impl/networking-impl-mc12w18a-mc12w19a}/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerLoginNetworkHandlerMixin.java (100%) rename libraries/{networking/networking-mc12w18a-mc12w19a => networking-impl/networking-impl-mc12w18a-mc12w19a}/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java (69%) rename libraries/{networking/networking-mc12w18a-mc12w19a => networking-impl/networking-impl-mc12w18a-mc12w19a}/src/main/resources/osl.networking.mixins.json (73%) create mode 100644 libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/build.gradle rename libraries/{networking/networking-mc12w21a-mc13w39b => networking-impl/networking-impl-mc12w21a-mc13w39b}/gradle.properties (77%) create mode 100644 libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/Networking.java rename libraries/{networking/networking-mc12w21a-mc13w39b => networking-impl/networking-impl-mc12w21a-mc13w39b}/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java (66%) create mode 100644 libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/LocalConnectionMixin.java create mode 100644 libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java create mode 100644 libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadPacketMixin.java create mode 100644 libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/MinecraftServerMixin.java rename libraries/{networking/networking-mc18w31a-mc1.14.4 => networking-impl/networking-impl-mc12w21a-mc13w39b}/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java (93%) create mode 100644 libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/RemoteConnectionMixin.java rename libraries/{networking/networking-mc12w21a-mc13w39b => networking-impl/networking-impl-mc12w21a-mc13w39b}/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java (66%) rename libraries/{networking/networking-mc12w21a-mc13w39b => networking-impl/networking-impl-mc12w21a-mc13w39b}/src/main/resources/osl.networking.mixins.json (67%) create mode 100644 libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/build.gradle rename libraries/{networking/networking-mc13w41a-mc14w20b => networking-impl/networking-impl-mc13w41a-mc14w20b}/gradle.properties (100%) create mode 100644 libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/Networking.java rename libraries/{networking/networking-mc1.13-pre4-mc18w30b => networking-impl/networking-impl-mc13w41a-mc14w20b}/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java (75%) create mode 100644 libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java create mode 100644 libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java create mode 100644 libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadS2CPacketMixin.java create mode 100644 libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/MinecraftServerMixin.java create mode 100644 libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketMixin.java rename libraries/{networking/networking-mc1.13-pre4-mc18w30b => networking-impl/networking-impl-mc13w41a-mc14w20b}/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java (100%) rename libraries/{networking/networking-mc14w21a-mc14w30c => networking-impl/networking-impl-mc13w41a-mc14w20b}/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java (76%) create mode 100644 libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/resources/osl.networking.mixins.json create mode 100644 libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/build.gradle rename libraries/{networking/networking-mc14w21a-mc14w30c => networking-impl/networking-impl-mc14w21a-mc14w30c}/gradle.properties (100%) create mode 100644 libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/Networking.java rename libraries/{networking/networking-mc14w31a-mc1.13-pre2 => networking-impl/networking-impl-mc14w21a-mc14w30c}/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java (75%) create mode 100644 libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java create mode 100644 libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java create mode 100644 libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadS2CPacketMixin.java create mode 100644 libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/MinecraftServerMixin.java rename libraries/{networking/networking-mc13w41a-mc14w20b => networking-impl/networking-impl-mc14w21a-mc14w30c}/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java (75%) rename libraries/{networking/networking-mc1.13-pre4-mc18w30b => networking-impl/networking-impl-mc14w21a-mc14w30c}/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java (76%) rename libraries/{networking/networking-mc1.13-pre4-mc18w30b => networking-impl/networking-impl-mc14w21a-mc14w30c}/src/main/resources/osl.networking.mixins.json (70%) create mode 100644 libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/build.gradle rename libraries/{networking/networking-mc14w31a-mc1.13-pre2 => networking-impl/networking-impl-mc14w31a-mc1.13-pre2}/gradle.properties (100%) create mode 100644 libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/Networking.java create mode 100644 libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java create mode 100644 libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java create mode 100644 libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java create mode 100644 libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadS2CPacketMixin.java create mode 100644 libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/MinecraftServerMixin.java create mode 100644 libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java create mode 100644 libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java create mode 100644 libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/resources/osl.networking.mixins.json create mode 100644 libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/build.gradle create mode 100644 libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/gradle.properties create mode 100644 libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/Networking.java create mode 100644 libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java create mode 100644 libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java create mode 100644 libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java create mode 100644 libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadS2CPacketMixin.java create mode 100644 libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/MinecraftServerMixin.java rename libraries/{networking/networking-mc12w21a-mc13w39b => networking-impl/networking-impl-mc18w43a-mc1.14.4}/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java (100%) create mode 100644 libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java create mode 100644 libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/resources/osl.networking.mixins.json create mode 100644 libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/build.gradle create mode 100644 libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/gradle.properties create mode 100644 libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java create mode 100644 libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/Networking.java rename libraries/{networking/networking-mcb1.5-mc11w48a => networking-impl/networking-impl-mca1.0.16-mca1.2.6}/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java (55%) rename libraries/{networking/networking-mcb1.0-mcb1.4_01 => networking-impl/networking-impl-mca1.0.16-mca1.2.6}/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java (61%) rename libraries/{networking/networking-mca1.0.16-mca1.2.6 => networking-impl/networking-impl-mca1.0.16-mca1.2.6}/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/HandshakePacketMixin.java (100%) create mode 100644 libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/LocalClientPlayerEntityMixin.java create mode 100644 libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java create mode 100644 libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ConnectionMixin.java rename libraries/{networking/networking-mca1.0.16-mca1.2.6 => networking-impl/networking-impl-mca1.0.16-mca1.2.6}/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java (100%) rename libraries/{networking/networking-mca1.0.16-mca1.2.6 => networking-impl/networking-impl-mca1.0.16-mca1.2.6}/src/main/resources/osl.networking.mixins.json (77%) create mode 100644 libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/build.gradle rename libraries/{networking/networking-mcb1.0-mcb1.4_01 => networking-impl/networking-impl-mcb1.0-mcb1.4_01}/gradle.properties (100%) create mode 100644 libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java create mode 100644 libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/Networking.java rename libraries/{networking/networking-mca1.0.16-mca1.2.6 => networking-impl/networking-impl-mcb1.0-mcb1.4_01}/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java (55%) rename libraries/{networking/networking-mcb1.5-mc11w48a => networking-impl/networking-impl-mcb1.0-mcb1.4_01}/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java (66%) rename libraries/{networking/networking-mcb1.0-mcb1.4_01 => networking-impl/networking-impl-mcb1.0-mcb1.4_01}/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/HandshakePacketMixin.java (100%) create mode 100644 libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java create mode 100644 libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ConnectionMixin.java rename libraries/{networking/networking-mcb1.0-mcb1.4_01 => networking-impl/networking-impl-mcb1.0-mcb1.4_01}/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java (100%) create mode 100644 libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/MinecraftServerMixin.java rename libraries/{networking/networking-mcb1.5-mc11w48a => networking-impl/networking-impl-mcb1.0-mcb1.4_01}/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerLoginNetworkHandlerMixin.java (94%) rename libraries/{networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1 => networking-impl/networking-impl-mcb1.0-mcb1.4_01}/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java (68%) rename libraries/{networking/networking-mcb1.5-mc11w48a => networking-impl/networking-impl-mcb1.0-mcb1.4_01}/src/main/resources/osl.networking.mixins.json (75%) create mode 100644 libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/build.gradle rename libraries/{networking/networking-mcb1.5-mc11w48a => networking-impl/networking-impl-mcb1.5-mc11w48a}/gradle.properties (100%) rename libraries/{networking/networking-mcb1.5-mc11w48a => networking-impl/networking-impl-mcb1.5-mc11w48a}/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java (57%) create mode 100644 libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java rename libraries/{networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1 => networking-impl/networking-impl-mcb1.5-mc11w48a}/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java (55%) rename libraries/{networking/networking-mca1.0.16-mca1.2.6 => networking-impl/networking-impl-mcb1.5-mc11w48a}/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java (66%) rename libraries/{networking/networking-mcb1.5-mc11w48a => networking-impl/networking-impl-mcb1.5-mc11w48a}/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/HandshakePacketMixin.java (100%) create mode 100644 libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java create mode 100644 libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ConnectionMixin.java rename libraries/{networking/networking-mcb1.5-mc11w48a => networking-impl/networking-impl-mcb1.5-mc11w48a}/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java (100%) create mode 100644 libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/MinecraftServerMixin.java rename libraries/{networking/networking-mcserver-a0.2.2-mcserver-a0.2.8 => networking-impl/networking-impl-mcb1.5-mc11w48a}/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerLoginNetworkHandlerMixin.java (94%) rename libraries/{networking/networking-mcserver-a0.2.2-mcserver-a0.2.8 => networking-impl/networking-impl-mcb1.5-mc11w48a}/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java (68%) create mode 100644 libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/resources/osl.networking.mixins.json create mode 100644 libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/build.gradle create mode 100644 libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/gradle.properties create mode 100644 libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java create mode 100644 libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/Networking.java rename libraries/{networking/networking-mcb1.0-mcb1.4_01 => networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8}/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java (55%) create mode 100644 libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ConnectionMixin.java rename libraries/{networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1 => networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8}/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java (100%) create mode 100644 libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/MinecraftServerMixin.java rename libraries/{networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1 => networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8}/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerLoginNetworkHandlerMixin.java (94%) rename libraries/{networking/networking-mcb1.5-mc11w48a => networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8}/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java (68%) rename libraries/{networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1 => networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8}/src/main/resources/osl.networking.mixins.json (84%) create mode 100644 libraries/networking-impl/src/main/resources/assets/ornithe-standard-libraries/networking-impl/icon.png create mode 100644 libraries/networking-impl/src/main/resources/fabric.mod.json delete mode 100644 libraries/networking/networking-mc1.13-pre4-mc18w30b/build.gradle delete mode 100644 libraries/networking/networking-mc1.13-pre4-mc18w30b/gradle.properties delete mode 100644 libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java delete mode 100644 libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/PacketByteBufs.java delete mode 100644 libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java delete mode 100644 libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java delete mode 100644 libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java delete mode 100644 libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/NetworkListener.java delete mode 100644 libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/Networking.java delete mode 100644 libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java delete mode 100644 libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/ICustomPayloadPacket.java delete mode 100644 libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java delete mode 100644 libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java delete mode 100644 libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java delete mode 100644 libraries/networking/networking-mc11w49a-mc12w16a/build.gradle delete mode 100644 libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java delete mode 100644 libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java delete mode 100644 libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java delete mode 100644 libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java delete mode 100644 libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java delete mode 100644 libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java delete mode 100644 libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java delete mode 100644 libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java delete mode 100644 libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java delete mode 100644 libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadPacketMixin.java delete mode 100644 libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java delete mode 100644 libraries/networking/networking-mc12w17a-mc12w17a/build.gradle delete mode 100644 libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java delete mode 100644 libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java delete mode 100644 libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java delete mode 100644 libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java delete mode 100644 libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java delete mode 100644 libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java delete mode 100644 libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java delete mode 100644 libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java delete mode 100644 libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java delete mode 100644 libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadPacketMixin.java delete mode 100644 libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java delete mode 100644 libraries/networking/networking-mc12w18a-mc12w19a/build.gradle delete mode 100644 libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java delete mode 100644 libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java delete mode 100644 libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java delete mode 100644 libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java delete mode 100644 libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java delete mode 100644 libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java delete mode 100644 libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java delete mode 100644 libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java delete mode 100644 libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadPacketMixin.java delete mode 100644 libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java delete mode 100644 libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java delete mode 100644 libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java delete mode 100644 libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java delete mode 100644 libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java delete mode 100644 libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java delete mode 100644 libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java delete mode 100644 libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java delete mode 100644 libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/Networking.java delete mode 100644 libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java delete mode 100644 libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java delete mode 100644 libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadPacketMixin.java delete mode 100644 libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java delete mode 100644 libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java delete mode 100644 libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/api/PacketByteBufs.java delete mode 100644 libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java delete mode 100644 libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java delete mode 100644 libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java delete mode 100644 libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/Networking.java delete mode 100644 libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java delete mode 100644 libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/ICustomPayloadPacket.java delete mode 100644 libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java delete mode 100644 libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/CustomPayloadS2CPacketMixin.java delete mode 100644 libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java delete mode 100644 libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java rename libraries/networking/{networking-mc13w41a-mc14w20b => networking-mc13w41a-mc18w30b}/build.gradle (100%) create mode 100644 libraries/networking/networking-mc13w41a-mc18w30b/gradle.properties create mode 100644 libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/IdentifierChannelIdentifierParser.java create mode 100644 libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/PacketBuffer.java create mode 100644 libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/PacketBuffers.java create mode 100644 libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/PacketPayload.java rename libraries/networking/{networking-mc1.13-pre4-mc18w30b => networking-mc13w41a-mc18w30b}/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java (100%) create mode 100644 libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPacketListener.java create mode 100644 libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java rename libraries/networking/{networking-mc1.13-pre4-mc18w30b => networking-mc13w41a-mc18w30b}/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java (100%) create mode 100644 libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java rename libraries/networking/{networking-mc14w21a-mc14w30c => networking-mc13w41a-mc18w30b}/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java (52%) create mode 100644 libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java create mode 100644 libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/PacketFactory.java create mode 100644 libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/access/CustomPayloadPacketAccess.java create mode 100644 libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/access/NetworkHandlerAccess.java create mode 100644 libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/access/PlayerManagerAccess.java create mode 100644 libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/access/TaskRunnerAccess.java create mode 100644 libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java create mode 100644 libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java delete mode 100644 libraries/networking/networking-mc14w21a-mc14w30c/build.gradle delete mode 100644 libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java delete mode 100644 libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/api/PacketByteBufs.java delete mode 100644 libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java delete mode 100644 libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java delete mode 100644 libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java delete mode 100644 libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java delete mode 100644 libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/NetworkListener.java delete mode 100644 libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/Networking.java delete mode 100644 libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java delete mode 100644 libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java delete mode 100644 libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/IPlayerManager.java delete mode 100644 libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java delete mode 100644 libraries/networking/networking-mc14w21a-mc14w30c/src/main/resources/osl.networking.mixins.json delete mode 100644 libraries/networking/networking-mc14w31a-mc1.13-pre2/build.gradle delete mode 100644 libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java delete mode 100644 libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/api/PacketByteBufs.java delete mode 100644 libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java delete mode 100644 libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java delete mode 100644 libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java delete mode 100644 libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java delete mode 100644 libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java delete mode 100644 libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/NetworkListener.java delete mode 100644 libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/Networking.java delete mode 100644 libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java delete mode 100644 libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java delete mode 100644 libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/IPlayerManager.java delete mode 100644 libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java delete mode 100644 libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/resources/osl.networking.mixins.json delete mode 100644 libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java create mode 100644 libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/IdentifierChannelIdentifierParser.java create mode 100644 libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/PacketBuffer.java create mode 100644 libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/PacketBuffers.java delete mode 100644 libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/PacketByteBufs.java create mode 100644 libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/PacketPayload.java create mode 100644 libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/client/ClientPacketListener.java create mode 100644 libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java delete mode 100644 libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/NetworkListener.java delete mode 100644 libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/Networking.java create mode 100644 libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/PacketFactory.java create mode 100644 libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/access/CustomPayloadPacketAccess.java create mode 100644 libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/access/NetworkHandlerAccess.java create mode 100644 libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/access/PlayerManagerAccess.java create mode 100644 libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/access/TaskRunnerAccess.java delete mode 100644 libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/ICustomPayloadPacket.java delete mode 100644 libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java delete mode 100644 libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java delete mode 100644 libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java delete mode 100644 libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java delete mode 100644 libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java delete mode 100644 libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java create mode 100644 libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/PacketBuffer.java create mode 100644 libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/PacketBuffers.java create mode 100644 libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/PacketPayload.java create mode 100644 libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/client/ClientPacketListener.java create mode 100644 libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/Connections.java delete mode 100644 libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java delete mode 100644 libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/Networking.java create mode 100644 libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/PacketFactory.java create mode 100644 libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/access/CustomPayloadPacketAccess.java create mode 100644 libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/access/LocalClientPlayerAccess.java create mode 100644 libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/access/NetworkHandlerAccess.java create mode 100644 libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/access/TaskRunnerAccess.java delete mode 100644 libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/LocalClientPlayerEntityAccessor.java rename libraries/networking/{networking-mc12w21a-mc13w39b => networking-mcb1.0-mc13w39b}/build.gradle (100%) create mode 100644 libraries/networking/networking-mcb1.0-mc13w39b/gradle.properties create mode 100644 libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/PacketBuffer.java create mode 100644 libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/PacketBuffers.java create mode 100644 libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/PacketPayload.java rename libraries/networking/{networking-mc12w18a-mc12w19a => networking-mcb1.0-mc13w39b}/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java (100%) create mode 100644 libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPacketListener.java create mode 100644 libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java rename libraries/networking/{networking-mc12w18a-mc12w19a => networking-mcb1.0-mc13w39b}/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java (100%) create mode 100644 libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java rename libraries/networking/{networking-mc13w41a-mc14w20b => networking-mcb1.0-mc13w39b}/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java (52%) create mode 100644 libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/Connections.java create mode 100644 libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java create mode 100644 libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/PacketFactory.java create mode 100644 libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/access/CustomPayloadPacketAccess.java create mode 100644 libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/access/NetworkHandlerAccess.java create mode 100644 libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/access/TaskRunnerAccess.java create mode 100644 libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java create mode 100644 libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java delete mode 100644 libraries/networking/networking-mcb1.0-mcb1.4_01/build.gradle delete mode 100644 libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java delete mode 100644 libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java delete mode 100644 libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java delete mode 100644 libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java delete mode 100644 libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java delete mode 100644 libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java delete mode 100644 libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java delete mode 100644 libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java delete mode 100644 libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/Networking.java delete mode 100644 libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java delete mode 100644 libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerLoginNetworkHandlerMixin.java delete mode 100644 libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java delete mode 100644 libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java delete mode 100644 libraries/networking/networking-mcb1.5-mc11w48a/build.gradle delete mode 100644 libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java delete mode 100644 libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java delete mode 100644 libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java delete mode 100644 libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java delete mode 100644 libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java delete mode 100644 libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java delete mode 100644 libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java delete mode 100644 libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java delete mode 100644 libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java delete mode 100644 libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java rename libraries/networking/{networking-mcserver-a0.1.2_01-mcserver-a0.2.1 => networking-mcserver-a0.1.0-mcserver-a0.2.1}/build.gradle (100%) rename libraries/networking/{networking-mcserver-a0.1.2_01-mcserver-a0.2.1 => networking-mcserver-a0.1.0-mcserver-a0.2.1}/gradle.properties (63%) create mode 100644 libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/PacketBuffer.java create mode 100644 libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/PacketBuffers.java create mode 100644 libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/PacketPayload.java rename libraries/networking/{networking-mc13w41a-mc14w20b => networking-mcserver-a0.1.0-mcserver-a0.2.1}/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java (96%) create mode 100644 libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java create mode 100644 libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java create mode 100644 libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/Connections.java create mode 100644 libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java create mode 100644 libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/PacketFactory.java create mode 100644 libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/access/CustomPayloadPacketAccess.java create mode 100644 libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/access/NetworkHandlerAccess.java create mode 100644 libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/access/TaskRunnerAccess.java create mode 100644 libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java rename libraries/networking/{networking-mcb1.0-mcb1.4_01 => networking-mcserver-a0.1.0-mcserver-a0.2.1}/src/main/resources/osl.networking.mixins.json (76%) delete mode 100644 libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java delete mode 100644 libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java delete mode 100644 libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java delete mode 100644 libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java delete mode 100644 libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java delete mode 100644 libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java delete mode 100644 libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/Networking.java delete mode 100644 libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java delete mode 100644 libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java delete mode 100644 libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java create mode 100644 libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/PacketBuffer.java create mode 100644 libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/PacketBuffers.java create mode 100644 libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/PacketPayload.java create mode 100644 libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java create mode 100644 libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/Connections.java delete mode 100644 libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java delete mode 100644 libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/Networking.java create mode 100644 libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/PacketFactory.java create mode 100644 libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/access/CustomPayloadPacketAccess.java create mode 100644 libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/access/NetworkHandlerAccess.java create mode 100644 libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/access/TaskRunnerAccess.java delete mode 100644 libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java delete mode 100644 libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java create mode 100644 libraries/networking/src/main/java/net/ornithemc/osl/networking/api/ChannelIdentifiers.java delete mode 100644 libraries/networking/src/main/java/net/ornithemc/osl/networking/api/Channels.java create mode 100644 libraries/networking/src/main/java/net/ornithemc/osl/networking/api/StringChannelIdentifierParser.java create mode 100644 libraries/networking/src/main/java/net/ornithemc/osl/networking/impl/ChannelIdentifierException.java create mode 100644 libraries/networking/src/main/java/net/ornithemc/osl/networking/impl/ChannelIdentifierParseException.java diff --git a/libraries/networking-impl/build.gradle b/libraries/networking-impl/build.gradle new file mode 100644 index 00000000..e98ba2c6 --- /dev/null +++ b/libraries/networking-impl/build.gradle @@ -0,0 +1 @@ +setUpLibrary(project) diff --git a/libraries/networking-impl/gradle.properties b/libraries/networking-impl/gradle.properties new file mode 100644 index 00000000..fdc41376 --- /dev/null +++ b/libraries/networking-impl/gradle.properties @@ -0,0 +1,2 @@ +version = 0.1.0 +archives_base_name = networking-impl diff --git a/libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/build.gradle b/libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/build.gradle new file mode 100644 index 00000000..8f761724 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/build.gradle @@ -0,0 +1,5 @@ +setUpModule(project, + 'entrypoints-mc13w16a-04192037-mc1.14.4', + 'lifecycle-events-mc13w36a-09051446-mc1.13', + 'networking-mc13w41a-mc18w30b' +) diff --git a/libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/gradle.properties b/libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/gradle.properties new file mode 100644 index 00000000..435c0b41 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/gradle.properties @@ -0,0 +1,7 @@ +environment = * +min_mc_version = 1.13-pre3 +max_mc_version = 1.13-pre3 +mc_version_range = >=1.13-rc.3 <=1.13-rc.3 + +minecraft_version = 1.13-pre3 +feather_build = 1 diff --git a/libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/java/net/ornithemc/osl/networking/impl/Networking.java new file mode 100644 index 00000000..be65ff90 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/java/net/ornithemc/osl/networking/impl/Networking.java @@ -0,0 +1,57 @@ +package net.ornithemc.osl.networking.impl; + +import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; +import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; + +import net.ornithemc.osl.entrypoints.api.ModInitializer; +import net.ornithemc.osl.entrypoints.api.client.ClientModInitializer; +import net.ornithemc.osl.entrypoints.api.server.ServerModInitializer; +import net.ornithemc.osl.lifecycle.api.client.MinecraftClientEvents; +import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; +import net.ornithemc.osl.networking.api.IdentifierChannelIdentifierParser; +import net.ornithemc.osl.networking.api.PacketBuffers; +import net.ornithemc.osl.networking.api.StringChannelIdentifierParser; +import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; +import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; +import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; +import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; + +public class Networking implements ModInitializer, ClientModInitializer, ServerModInitializer { + + @Override + public void init() { + MinecraftServerEvents.START.register(ServerPlayNetworkingImpl::setUp); + MinecraftServerEvents.STOP.register(ServerPlayNetworkingImpl::destroy); + ServerPlayNetworkingImpl.setUpPacketFactory((channel, data) -> + new CustomPayloadS2CPacket(IdentifierChannelIdentifierParser.toIdentifier(channel), PacketBuffers.unwrapped(data))); + ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { + // send channel registration data as a response to receiving client channel registration data + ServerPlayNetworkingImpl.sendNoCheck(player, HandshakePayload.CHANNEL, HandshakePayload.server()); + + ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); + ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); + + return true; + }); + } + + @Override + public void initClient() { + MinecraftClientEvents.START.register(ClientPlayNetworkingImpl::setUp); + MinecraftClientEvents.STOP.register(ClientPlayNetworkingImpl::destroy); + ClientPlayNetworkingImpl.setUpPacketFactory((channel, data) -> + new CustomPayloadC2SPacket(StringChannelIdentifierParser.toString(channel), PacketBuffers.unwrapped(data))); + ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { + ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); + ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); + + return true; + }); + } + + @Override + public void initServer() { + // no-op + } +} diff --git a/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java b/libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java similarity index 75% rename from libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java rename to libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java index a755af19..ef5dbdfb 100644 --- a/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java +++ b/libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java @@ -15,20 +15,21 @@ import net.minecraft.client.network.handler.ClientPlayNetworkHandler; import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; import net.ornithemc.osl.networking.impl.HandshakePayload; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; @Mixin(ClientPlayNetworkHandler.class) -public class ClientPlayNetworkHandlerMixin implements INetworkHandler { +public class ClientPlayNetworkHandlerMixin implements NetworkHandlerAccess { @Shadow @Final private Minecraft minecraft; /** * Channels that the server is listening to. */ - @Unique private Set serverChannels; + @Unique private Set serverChannels; @Inject( method = "handleLogin", @@ -38,7 +39,7 @@ public class ClientPlayNetworkHandlerMixin implements INetworkHandler { ) private void osl$networking$handleLogin(CallbackInfo ci) { // send channel registration data as soon as login occurs - ClientPlayNetworkingImpl.doSend(HandshakePayload.CHANNEL, HandshakePayload.client()); + ClientPlayNetworkingImpl.sendNoCheck(HandshakePayload.CHANNEL, HandshakePayload.client()); ClientConnectionEvents.LOGIN.invoker().accept(minecraft); } @@ -62,7 +63,7 @@ public class ClientPlayNetworkHandlerMixin implements INetworkHandler { ) ) private void osl$networking$handleCustomPayload(CustomPayloadS2CPacket packet, CallbackInfo ci) { - if (ClientPlayNetworkingImpl.handle(minecraft, (ClientPlayNetworkHandler)(Object)this, packet)) { + if (ClientPlayNetworkingImpl.handlePacket(minecraft, (ClientPlayNetworkHandler)(Object)this, packet)) { ci.cancel(); } } @@ -73,12 +74,12 @@ public class ClientPlayNetworkHandlerMixin implements INetworkHandler { } @Override - public void osl$networking$registerChannels(Set channels) { - serverChannels = new LinkedHashSet<>(channels); + public boolean osl$networking$isPlayReady(NamespacedIdentifier channel) { + return serverChannels != null && serverChannels.contains(channel); } @Override - public boolean osl$networking$isRegisteredChannel(String channel) { - return serverChannels != null && serverChannels.contains(channel); + public void osl$networking$registerChannels(Set channels) { + serverChannels = new LinkedHashSet<>(channels); } } diff --git a/libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java b/libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java new file mode 100644 index 00000000..06467881 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java @@ -0,0 +1,18 @@ +package net.ornithemc.osl.networking.impl.mixin.client; + +import org.spongepowered.asm.mixin.Mixin; + +import net.minecraft.client.Minecraft; +import net.minecraft.util.BlockableEventLoop; + +import net.ornithemc.osl.networking.impl.access.TaskRunnerAccess; + +@Mixin(Minecraft.class) +public abstract class MinecraftMixin implements BlockableEventLoop, TaskRunnerAccess { + + @Override + public boolean osl$networking$submit(Runnable task) { + this.submit(task); + return true; + } +} diff --git a/libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java b/libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java new file mode 100644 index 00000000..64f448dd --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java @@ -0,0 +1,63 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.At.Shift; +import org.spongepowered.asm.mixin.injection.Constant; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyConstant; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketBuffers; +import net.ornithemc.osl.networking.api.StringChannelIdentifierParser; +import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; + +@Mixin(CustomPayloadC2SPacket.class) +public class CustomPayloadC2SPacketMixin implements CustomPayloadPacketAccess { + + @Shadow private String channel; + @Shadow private PacketByteBuf data; + + @ModifyConstant( + method = "read", + constant = @Constant( + intValue = 20 + ) + ) + private int osl$networking$modifyMaxChannelLength(int maxLength) { + return StringChannelIdentifierParser.MAX_LENGTH; + } + + @Inject( + method = "m_9429910", + cancellable = true, + at = @At( + value = "INVOKE", + shift = Shift.AFTER, + target = "Lnet/minecraft/server/network/handler/ServerPlayPacketHandler;handleCustomPayload(Lnet/minecraft/network/packet/c2s/play/CustomPayloadC2SPacket;)V" + ) + ) + private void osl$networking$skipBufferRelease(CallbackInfo ci) { + // there's a call to ByteBuf.release() that we want to skip + // so that we can queue packet handling to the main thread + // Vanilla does this by throwing an exception but for the sake + // of version compat we cannot use the same approach + ci.cancel(); + } + + @Override + public NamespacedIdentifier osl$networking$getChannel() { + return StringChannelIdentifierParser.fromString(channel); + } + + @Override + public PacketBuffer osl$networking$getData() { + return PacketBuffers.wrapped(data.copy()); + } +} diff --git a/libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadS2CPacketMixin.java b/libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadS2CPacketMixin.java new file mode 100644 index 00000000..97912aa8 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadS2CPacketMixin.java @@ -0,0 +1,31 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; +import net.minecraft.resource.Identifier; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.api.IdentifierChannelIdentifierParser; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketBuffers; +import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; + +@Mixin(CustomPayloadS2CPacket.class) +public class CustomPayloadS2CPacketMixin implements CustomPayloadPacketAccess { + + @Shadow private Identifier channel; + @Shadow private PacketByteBuf data; + + @Override + public NamespacedIdentifier osl$networking$getChannel() { + return IdentifierChannelIdentifierParser.fromIdentifier(channel); + } + + @Override + public PacketBuffer osl$networking$getData() { + return PacketBuffers.wrapped(data.copy()); + } +} diff --git a/libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/MinecraftServerMixin.java b/libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/MinecraftServerMixin.java new file mode 100644 index 00000000..032c1691 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/MinecraftServerMixin.java @@ -0,0 +1,18 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.BlockableEventLoop; + +import net.ornithemc.osl.networking.impl.access.TaskRunnerAccess; + +@Mixin(MinecraftServer.class) +public abstract class MinecraftServerMixin implements BlockableEventLoop, TaskRunnerAccess { + + @Override + public boolean osl$networking$submit(Runnable task) { + this.submit(task); + return true; + } +} diff --git a/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java b/libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java similarity index 89% rename from libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java rename to libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java index 180abcf1..e88d1f5a 100644 --- a/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java +++ b/libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java @@ -15,10 +15,10 @@ import net.minecraft.server.entity.living.player.ServerPlayerEntity; import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; -import net.ornithemc.osl.networking.impl.interfaces.mixin.IPlayerManager; +import net.ornithemc.osl.networking.impl.access.PlayerManagerAccess; @Mixin(PlayerManager.class) -public class PlayerManagerMixin implements IPlayerManager { +public class PlayerManagerMixin implements PlayerManagerAccess { @Shadow @Final private MinecraftServer server; @Shadow @Final private List players; diff --git a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java b/libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java similarity index 76% rename from libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java rename to libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java index 60288278..ac66d440 100644 --- a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java +++ b/libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java @@ -16,12 +16,13 @@ import net.minecraft.server.entity.living.player.ServerPlayerEntity; import net.minecraft.server.network.handler.ServerPlayNetworkHandler; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; @Mixin(ServerPlayNetworkHandler.class) -public class ServerPlayNetworkHandlerMixin implements INetworkHandler { +public class ServerPlayNetworkHandlerMixin implements NetworkHandlerAccess { @Shadow @Final private MinecraftServer server; @Shadow @Final private ServerPlayerEntity player; @@ -29,7 +30,7 @@ public class ServerPlayNetworkHandlerMixin implements INetworkHandler { /** * Channels that the client is listening to. */ - @Unique private Set clientChannels; + @Unique private Set clientChannels; @Inject( method = "onDisconnect", @@ -50,7 +51,7 @@ public class ServerPlayNetworkHandlerMixin implements INetworkHandler { ) ) private void osl$networking$handleCustomPayload(CustomPayloadC2SPacket packet, CallbackInfo ci) { - if (ServerPlayNetworkingImpl.handle(server, (ServerPlayNetworkHandler)(Object)this, player, packet)) { + if (ServerPlayNetworkingImpl.handlePacket(server, (ServerPlayNetworkHandler)(Object)this, player, packet)) { ci.cancel(); } } @@ -61,12 +62,12 @@ public class ServerPlayNetworkHandlerMixin implements INetworkHandler { } @Override - public void osl$networking$registerChannels(Set channels) { - clientChannels = new LinkedHashSet<>(channels); + public boolean osl$networking$isPlayReady(NamespacedIdentifier channel) { + return clientChannels != null && clientChannels.contains(channel); } @Override - public boolean osl$networking$isRegisteredChannel(String channel) { - return clientChannels != null && clientChannels.contains(channel); + public void osl$networking$registerChannels(Set channels) { + clientChannels = new LinkedHashSet<>(channels); } } diff --git a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/resources/osl.networking.mixins.json b/libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/resources/osl.networking.mixins.json similarity index 79% rename from libraries/networking/networking-mc13w41a-mc14w20b/src/main/resources/osl.networking.mixins.json rename to libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/resources/osl.networking.mixins.json index 202183f7..f64bbc23 100644 --- a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/resources/osl.networking.mixins.json +++ b/libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/resources/osl.networking.mixins.json @@ -5,12 +5,14 @@ "compatibilityLevel": "JAVA_8", "mixins": [ "common.CustomPayloadC2SPacketMixin", + "common.CustomPayloadS2CPacketMixin", + "common.MinecraftServerMixin", "common.PlayerManagerMixin", "common.ServerPlayNetworkHandlerMixin" ], "client": [ "client.ClientPlayNetworkHandlerMixin", - "client.CustomPayloadS2CPacketMixin" + "client.MinecraftMixin" ], "server": [ ], diff --git a/libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/build.gradle b/libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/build.gradle new file mode 100644 index 00000000..3664b731 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/build.gradle @@ -0,0 +1,5 @@ +setUpModule(project, + 'entrypoints-mc13w16a-04192037-mc1.14.4', + 'lifecycle-events-mc18w30a-mc18w50a', + 'networking-mc18w31a-mc1.14.4' +) diff --git a/libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/gradle.properties b/libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/gradle.properties new file mode 100644 index 00000000..be43d59e --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/gradle.properties @@ -0,0 +1,7 @@ +environment = * +min_mc_version = 1.13-pre4 +max_mc_version = 1.13.2 +mc_version_range = >=1.13-rc.4 <=1.13.2 + +minecraft_version = 1.13.2 +feather_build = 2 diff --git a/libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/java/net/ornithemc/osl/networking/impl/Networking.java new file mode 100644 index 00000000..431eefe5 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/java/net/ornithemc/osl/networking/impl/Networking.java @@ -0,0 +1,56 @@ +package net.ornithemc.osl.networking.impl; + +import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; +import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; + +import net.ornithemc.osl.entrypoints.api.ModInitializer; +import net.ornithemc.osl.entrypoints.api.client.ClientModInitializer; +import net.ornithemc.osl.entrypoints.api.server.ServerModInitializer; +import net.ornithemc.osl.lifecycle.api.client.MinecraftClientEvents; +import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; +import net.ornithemc.osl.networking.api.IdentifierChannelIdentifierParser; +import net.ornithemc.osl.networking.api.PacketBuffers; +import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; +import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; +import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; +import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; + +public class Networking implements ModInitializer, ClientModInitializer, ServerModInitializer { + + @Override + public void init() { + MinecraftServerEvents.START.register(ServerPlayNetworkingImpl::setUp); + MinecraftServerEvents.STOP.register(ServerPlayNetworkingImpl::destroy); + ServerPlayNetworkingImpl.setUpPacketFactory((channel, data) -> + new CustomPayloadS2CPacket(IdentifierChannelIdentifierParser.toIdentifier(channel), PacketBuffers.unwrapped(data))); + ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { + // send channel registration data as a response to receiving client channel registration data + ServerPlayNetworkingImpl.sendNoCheck(player, HandshakePayload.CHANNEL, HandshakePayload.server()); + + ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); + ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); + + return true; + }); + } + + @Override + public void initClient() { + MinecraftClientEvents.START.register(ClientPlayNetworkingImpl::setUp); + MinecraftClientEvents.STOP.register(ClientPlayNetworkingImpl::destroy); + ClientPlayNetworkingImpl.setUpPacketFactory((channel, data) -> + new CustomPayloadC2SPacket(IdentifierChannelIdentifierParser.toIdentifier(channel), PacketBuffers.unwrapped(data))); + ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { + ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); + ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); + + return true; + }); + } + + @Override + public void initServer() { + // no-op + } +} diff --git a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java b/libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java similarity index 75% rename from libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java rename to libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java index a755af19..ef5dbdfb 100644 --- a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java +++ b/libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java @@ -15,20 +15,21 @@ import net.minecraft.client.network.handler.ClientPlayNetworkHandler; import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; import net.ornithemc.osl.networking.impl.HandshakePayload; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; @Mixin(ClientPlayNetworkHandler.class) -public class ClientPlayNetworkHandlerMixin implements INetworkHandler { +public class ClientPlayNetworkHandlerMixin implements NetworkHandlerAccess { @Shadow @Final private Minecraft minecraft; /** * Channels that the server is listening to. */ - @Unique private Set serverChannels; + @Unique private Set serverChannels; @Inject( method = "handleLogin", @@ -38,7 +39,7 @@ public class ClientPlayNetworkHandlerMixin implements INetworkHandler { ) private void osl$networking$handleLogin(CallbackInfo ci) { // send channel registration data as soon as login occurs - ClientPlayNetworkingImpl.doSend(HandshakePayload.CHANNEL, HandshakePayload.client()); + ClientPlayNetworkingImpl.sendNoCheck(HandshakePayload.CHANNEL, HandshakePayload.client()); ClientConnectionEvents.LOGIN.invoker().accept(minecraft); } @@ -62,7 +63,7 @@ public class ClientPlayNetworkHandlerMixin implements INetworkHandler { ) ) private void osl$networking$handleCustomPayload(CustomPayloadS2CPacket packet, CallbackInfo ci) { - if (ClientPlayNetworkingImpl.handle(minecraft, (ClientPlayNetworkHandler)(Object)this, packet)) { + if (ClientPlayNetworkingImpl.handlePacket(minecraft, (ClientPlayNetworkHandler)(Object)this, packet)) { ci.cancel(); } } @@ -73,12 +74,12 @@ public class ClientPlayNetworkHandlerMixin implements INetworkHandler { } @Override - public void osl$networking$registerChannels(Set channels) { - serverChannels = new LinkedHashSet<>(channels); + public boolean osl$networking$isPlayReady(NamespacedIdentifier channel) { + return serverChannels != null && serverChannels.contains(channel); } @Override - public boolean osl$networking$isRegisteredChannel(String channel) { - return serverChannels != null && serverChannels.contains(channel); + public void osl$networking$registerChannels(Set channels) { + serverChannels = new LinkedHashSet<>(channels); } } diff --git a/libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java b/libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java new file mode 100644 index 00000000..06467881 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java @@ -0,0 +1,18 @@ +package net.ornithemc.osl.networking.impl.mixin.client; + +import org.spongepowered.asm.mixin.Mixin; + +import net.minecraft.client.Minecraft; +import net.minecraft.util.BlockableEventLoop; + +import net.ornithemc.osl.networking.impl.access.TaskRunnerAccess; + +@Mixin(Minecraft.class) +public abstract class MinecraftMixin implements BlockableEventLoop, TaskRunnerAccess { + + @Override + public boolean osl$networking$submit(Runnable task) { + this.submit(task); + return true; + } +} diff --git a/libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java b/libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java new file mode 100644 index 00000000..7853cd80 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java @@ -0,0 +1,52 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.At.Shift; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; +import net.minecraft.resource.Identifier; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.api.IdentifierChannelIdentifierParser; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketBuffers; +import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; + +@Mixin(CustomPayloadC2SPacket.class) +public class CustomPayloadC2SPacketMixin implements CustomPayloadPacketAccess { + + @Shadow private Identifier channel; + @Shadow private PacketByteBuf data; + + @Inject( + method = "m_9429910", + cancellable = true, + at = @At( + value = "INVOKE", + shift = Shift.AFTER, + target = "Lnet/minecraft/server/network/handler/ServerPlayPacketHandler;handleCustomPayload(Lnet/minecraft/network/packet/c2s/play/CustomPayloadC2SPacket;)V" + ) + ) + private void osl$networking$skipBufferRelease(CallbackInfo ci) { + // there's a call to ByteBuf.release() that we want to skip + // so that we can queue packet handling to the main thread + // Vanilla does this by throwing an exception but for the sake + // of version compat we cannot use the same approach + ci.cancel(); + } + + @Override + public NamespacedIdentifier osl$networking$getChannel() { + return IdentifierChannelIdentifierParser.fromIdentifier(channel); + } + + @Override + public PacketBuffer osl$networking$getData() { + return PacketBuffers.wrapped(data.copy()); + } +} diff --git a/libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadS2CPacketMixin.java b/libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadS2CPacketMixin.java new file mode 100644 index 00000000..97912aa8 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadS2CPacketMixin.java @@ -0,0 +1,31 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; +import net.minecraft.resource.Identifier; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.api.IdentifierChannelIdentifierParser; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketBuffers; +import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; + +@Mixin(CustomPayloadS2CPacket.class) +public class CustomPayloadS2CPacketMixin implements CustomPayloadPacketAccess { + + @Shadow private Identifier channel; + @Shadow private PacketByteBuf data; + + @Override + public NamespacedIdentifier osl$networking$getChannel() { + return IdentifierChannelIdentifierParser.fromIdentifier(channel); + } + + @Override + public PacketBuffer osl$networking$getData() { + return PacketBuffers.wrapped(data.copy()); + } +} diff --git a/libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/MinecraftServerMixin.java b/libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/MinecraftServerMixin.java new file mode 100644 index 00000000..032c1691 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/MinecraftServerMixin.java @@ -0,0 +1,18 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.BlockableEventLoop; + +import net.ornithemc.osl.networking.impl.access.TaskRunnerAccess; + +@Mixin(MinecraftServer.class) +public abstract class MinecraftServerMixin implements BlockableEventLoop, TaskRunnerAccess { + + @Override + public boolean osl$networking$submit(Runnable task) { + this.submit(task); + return true; + } +} diff --git a/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java b/libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java similarity index 89% rename from libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java rename to libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java index 180abcf1..e88d1f5a 100644 --- a/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java +++ b/libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java @@ -15,10 +15,10 @@ import net.minecraft.server.entity.living.player.ServerPlayerEntity; import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; -import net.ornithemc.osl.networking.impl.interfaces.mixin.IPlayerManager; +import net.ornithemc.osl.networking.impl.access.PlayerManagerAccess; @Mixin(PlayerManager.class) -public class PlayerManagerMixin implements IPlayerManager { +public class PlayerManagerMixin implements PlayerManagerAccess { @Shadow @Final private MinecraftServer server; @Shadow @Final private List players; diff --git a/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java b/libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java similarity index 76% rename from libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java rename to libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java index 60288278..ac66d440 100644 --- a/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java +++ b/libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java @@ -16,12 +16,13 @@ import net.minecraft.server.entity.living.player.ServerPlayerEntity; import net.minecraft.server.network.handler.ServerPlayNetworkHandler; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; @Mixin(ServerPlayNetworkHandler.class) -public class ServerPlayNetworkHandlerMixin implements INetworkHandler { +public class ServerPlayNetworkHandlerMixin implements NetworkHandlerAccess { @Shadow @Final private MinecraftServer server; @Shadow @Final private ServerPlayerEntity player; @@ -29,7 +30,7 @@ public class ServerPlayNetworkHandlerMixin implements INetworkHandler { /** * Channels that the client is listening to. */ - @Unique private Set clientChannels; + @Unique private Set clientChannels; @Inject( method = "onDisconnect", @@ -50,7 +51,7 @@ public class ServerPlayNetworkHandlerMixin implements INetworkHandler { ) ) private void osl$networking$handleCustomPayload(CustomPayloadC2SPacket packet, CallbackInfo ci) { - if (ServerPlayNetworkingImpl.handle(server, (ServerPlayNetworkHandler)(Object)this, player, packet)) { + if (ServerPlayNetworkingImpl.handlePacket(server, (ServerPlayNetworkHandler)(Object)this, player, packet)) { ci.cancel(); } } @@ -61,12 +62,12 @@ public class ServerPlayNetworkHandlerMixin implements INetworkHandler { } @Override - public void osl$networking$registerChannels(Set channels) { - clientChannels = new LinkedHashSet<>(channels); + public boolean osl$networking$isPlayReady(NamespacedIdentifier channel) { + return clientChannels != null && clientChannels.contains(channel); } @Override - public boolean osl$networking$isRegisteredChannel(String channel) { - return clientChannels != null && clientChannels.contains(channel); + public void osl$networking$registerChannels(Set channels) { + clientChannels = new LinkedHashSet<>(channels); } } diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/resources/osl.networking.mixins.json b/libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/resources/osl.networking.mixins.json similarity index 70% rename from libraries/networking/networking-mc18w31a-mc1.14.4/src/main/resources/osl.networking.mixins.json rename to libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/resources/osl.networking.mixins.json index 36ceef9e..f64bbc23 100644 --- a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/resources/osl.networking.mixins.json +++ b/libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/resources/osl.networking.mixins.json @@ -5,11 +5,14 @@ "compatibilityLevel": "JAVA_8", "mixins": [ "common.CustomPayloadC2SPacketMixin", + "common.CustomPayloadS2CPacketMixin", + "common.MinecraftServerMixin", "common.PlayerManagerMixin", "common.ServerPlayNetworkHandlerMixin" ], "client": [ - "client.ClientPlayNetworkHandlerMixin" + "client.ClientPlayNetworkHandlerMixin", + "client.MinecraftMixin" ], "server": [ ], diff --git a/libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/build.gradle b/libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/build.gradle new file mode 100644 index 00000000..435282a3 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/build.gradle @@ -0,0 +1,5 @@ +setUpModule(project, + 'entrypoints-mcin-20091223-1459-mc1.5.2', + 'lifecycle-events-mc12w01a-mc12w17a', + 'networking-mcb1.0-mc13w39b' +) diff --git a/libraries/networking/networking-mc11w49a-mc12w16a/gradle.properties b/libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/gradle.properties similarity index 100% rename from libraries/networking/networking-mc11w49a-mc12w16a/gradle.properties rename to libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/gradle.properties diff --git a/libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java new file mode 100644 index 00000000..265638db --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java @@ -0,0 +1,59 @@ +package net.ornithemc.osl.networking.impl; + +import net.minecraft.network.packet.CustomPayloadPacket; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.entrypoints.api.ModInitializer; +import net.ornithemc.osl.entrypoints.api.client.ClientModInitializer; +import net.ornithemc.osl.entrypoints.api.server.ServerModInitializer; +import net.ornithemc.osl.lifecycle.api.client.MinecraftClientEvents; +import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; +import net.ornithemc.osl.networking.api.StringChannelIdentifierParser; +import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; +import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; +import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; +import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; + +public class Networking implements ModInitializer, ClientModInitializer, ServerModInitializer { + + @Override + public void init() { + // no-op + } + + @Override + public void initClient() { + MinecraftClientEvents.START.register(ClientPlayNetworkingImpl::setUp); + MinecraftClientEvents.STOP.register(ClientPlayNetworkingImpl::destroy); + ClientPlayNetworkingImpl.setUpPacketFactory(Networking::newCustomPayloadPacket); + ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { + ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); + ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); + + return true; + }); + } + + @Override + public void initServer() { + MinecraftServerEvents.START.register(ServerPlayNetworkingImpl::setUp); + MinecraftServerEvents.STOP.register(ServerPlayNetworkingImpl::destroy); + ServerPlayNetworkingImpl.setUpPacketFactory(Networking::newCustomPayloadPacket); + ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { + // send channel registration data as a response to receiving client channel registration data + ServerPlayNetworkingImpl.sendNoCheck(player, HandshakePayload.CHANNEL, HandshakePayload.server()); + + ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); + ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); + + return true; + }); + } + + private static CustomPayloadPacket newCustomPayloadPacket(NamespacedIdentifier channel, byte[] data) { + CustomPayloadPacket p = new CustomPayloadPacket(); + p.channel = StringChannelIdentifierParser.toString(channel); + p.data = data; + return p; + } +} diff --git a/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java b/libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java similarity index 55% rename from libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java rename to libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java index a583e081..47f751c1 100644 --- a/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java +++ b/libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java @@ -1,17 +1,9 @@ package net.ornithemc.osl.networking.impl.interfaces.mixin; -import java.util.Set; - import net.minecraft.network.packet.CustomPayloadPacket; public interface INetworkHandler { boolean osl$networking$handleCustomPayload(CustomPayloadPacket packet); - boolean osl$networking$isPlayReady(); - - void osl$networking$registerChannels(Set channels); - - boolean osl$networking$isRegisteredChannel(String channel); - } diff --git a/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java b/libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java similarity index 65% rename from libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java rename to libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java index 1de7fa9b..6faff580 100644 --- a/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java +++ b/libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java @@ -3,7 +3,6 @@ import java.util.LinkedHashSet; import java.util.Set; -import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -13,22 +12,26 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.network.handler.ClientNetworkHandler; +import net.minecraft.client.world.MultiplayerWorld; import net.minecraft.network.packet.CustomPayloadPacket; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; import net.ornithemc.osl.networking.impl.HandshakePayload; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; @Mixin(ClientNetworkHandler.class) -public class ClientNetworkHandlerMixin implements INetworkHandler { +public class ClientNetworkHandlerMixin implements NetworkHandlerAccess, INetworkHandler { - @Shadow @Final private Minecraft minecraft; + @Shadow private Minecraft minecraft; + @Shadow private MultiplayerWorld world; /** * Channels that the server is listening to. */ - @Unique private Set serverChannels; + @Unique private Set serverChannels; @Inject( method = "handleLogin", @@ -38,7 +41,7 @@ public class ClientNetworkHandlerMixin implements INetworkHandler { ) private void osl$networking$handleLogin(CallbackInfo ci) { // send channel registration data as soon as login occurs - ClientPlayNetworkingImpl.doSend(HandshakePayload.CHANNEL, HandshakePayload.client()); + ClientPlayNetworkingImpl.sendNoCheck(HandshakePayload.CHANNEL, HandshakePayload.client()); ClientConnectionEvents.LOGIN.invoker().accept(minecraft); } @@ -55,8 +58,8 @@ public class ClientNetworkHandlerMixin implements INetworkHandler { } @Override - public boolean osl$networking$handleCustomPayload(CustomPayloadPacket packet) { - return ClientPlayNetworkingImpl.handle(minecraft, (ClientNetworkHandler)(Object)this, packet); + public boolean osl$networking$canRunOffMainThread() { + return minecraft != null && minecraft.world != null && minecraft.player != null && world != null; } @Override @@ -65,12 +68,17 @@ public class ClientNetworkHandlerMixin implements INetworkHandler { } @Override - public void osl$networking$registerChannels(Set channels) { + public boolean osl$networking$isPlayReady(NamespacedIdentifier channel) { + return serverChannels != null && serverChannels.contains(channel); + } + + @Override + public void osl$networking$registerChannels(Set channels) { serverChannels = new LinkedHashSet<>(channels); } @Override - public boolean osl$networking$isRegisteredChannel(String channel) { - return serverChannels != null && serverChannels.contains(channel); + public boolean osl$networking$handleCustomPayload(CustomPayloadPacket packet) { + return ClientPlayNetworkingImpl.handlePacket(minecraft, (ClientNetworkHandler)(Object)this, packet); } } diff --git a/libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java b/libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java new file mode 100644 index 00000000..85baea9b --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java @@ -0,0 +1,44 @@ +package net.ornithemc.osl.networking.impl.mixin.client; + +import java.util.ArrayDeque; +import java.util.Queue; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.client.Minecraft; + +import net.ornithemc.osl.networking.impl.access.TaskRunnerAccess; + +@Mixin(Minecraft.class) +public class MinecraftMixin implements TaskRunnerAccess { + + @Unique + private Queue tasks = new ArrayDeque<>(); + + @Inject( + method = "tick", + at = @At( + value = "HEAD" + ) + ) + private void osl$networking$runTasks(CallbackInfo ci) { + synchronized (this.tasks) { + while (!this.tasks.isEmpty()) { + this.tasks.poll().run(); + } + } + } + + @Override + public boolean osl$networking$submit(Runnable task) { + synchronized (this.tasks) { + this.tasks.add(task); + } + + return true; + } +} diff --git a/libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ConnectionMixin.java b/libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ConnectionMixin.java new file mode 100644 index 00000000..8cbf1eeb --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ConnectionMixin.java @@ -0,0 +1,33 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import net.minecraft.network.Connection; +import net.minecraft.network.PacketHandler; +import net.minecraft.network.packet.Packet; + +import net.ornithemc.osl.networking.impl.Connections; + +@Mixin(Connection.class) +public class ConnectionMixin { + + @Shadow private PacketHandler listener; + + @Inject( + method = "read", + cancellable = true, + at = @At( + value = "INVOKE", + target = "Ljava/util/List;add(Ljava/lang/Object;)Z" + ) + ) + private void osl$networking$handlePacketsAsync(Packet packet, CallbackInfoReturnable cir) { + if (Connections.checkAsyncHandling(packet, listener)) { + cir.setReturnValue(true); + } + } +} diff --git a/libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadPacketMixin.java b/libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadPacketMixin.java new file mode 100644 index 00000000..8183ea1b --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadPacketMixin.java @@ -0,0 +1,39 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.Constant; +import org.spongepowered.asm.mixin.injection.ModifyConstant; + +import net.minecraft.network.packet.CustomPayloadPacket; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.api.StringChannelIdentifierParser; +import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; + +@Mixin(CustomPayloadPacket.class) +public class CustomPayloadPacketMixin implements CustomPayloadPacketAccess { + + @Shadow private String channel; + @Shadow private byte[] data; + + @ModifyConstant( + method = "read", + constant = @Constant( + intValue = 16 + ) + ) + private int osl$networking$modifyMaxChannelLength(int maxLength) { + return StringChannelIdentifierParser.MAX_LENGTH; + } + + @Override + public NamespacedIdentifier osl$networking$getChannel() { + return StringChannelIdentifierParser.fromString(channel); + } + + @Override + public byte[] osl$networking$getData() { + return data; + } +} diff --git a/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketHandlerMixin.java b/libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketHandlerMixin.java similarity index 100% rename from libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketHandlerMixin.java rename to libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketHandlerMixin.java diff --git a/libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/MinecraftServerMixin.java b/libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/MinecraftServerMixin.java new file mode 100644 index 00000000..5cdbf6c6 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/MinecraftServerMixin.java @@ -0,0 +1,48 @@ +package net.ornithemc.osl.networking.impl.mixin.server; + +import java.util.ArrayDeque; +import java.util.Queue; + +import org.objectweb.asm.Opcodes; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.server.MinecraftServer; + +import net.ornithemc.osl.networking.impl.access.TaskRunnerAccess; + +@Mixin(MinecraftServer.class) +public class MinecraftServerMixin implements TaskRunnerAccess { + + @Unique + private Queue tasks = new ArrayDeque<>(); + + @Inject( + method = "tick", + at = @At( + value = "FIELD", + opcode = Opcodes.PUTFIELD, + target = "Lnet/minecraft/server/MinecraftServer;ticks:I" + ) + ) + private void osl$networking$runTasks(CallbackInfo ci) { + synchronized (this.tasks) { + while (!this.tasks.isEmpty()) { + this.tasks.poll().run(); + } + } + } + + @Override + public boolean osl$networking$submit(Runnable task) { + synchronized (this.tasks) { + this.tasks.add(task); + } + + return true; + } +} diff --git a/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerLoginNetworkHandlerMixin.java b/libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerLoginNetworkHandlerMixin.java similarity index 100% rename from libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerLoginNetworkHandlerMixin.java rename to libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerLoginNetworkHandlerMixin.java diff --git a/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java b/libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java similarity index 68% rename from libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java rename to libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java index 7e50711b..fd9e42b4 100644 --- a/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java +++ b/libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java @@ -3,7 +3,6 @@ import java.util.LinkedHashSet; import java.util.Set; -import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -16,20 +15,22 @@ import net.minecraft.server.entity.mob.player.ServerPlayerEntity; import net.minecraft.server.network.handler.ServerPlayNetworkHandler; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; @Mixin(ServerPlayNetworkHandler.class) -public class ServerPlayNetworkHandlerMixin implements INetworkHandler { +public class ServerPlayNetworkHandlerMixin implements NetworkHandlerAccess, INetworkHandler { - @Shadow @Final private MinecraftServer server; - @Shadow @Final private ServerPlayerEntity player; + @Shadow private MinecraftServer server; + @Shadow private ServerPlayerEntity player; /** * Channels that the client is listening to. */ - @Unique private Set clientChannels; + @Unique private Set clientChannels; @Inject( method = "onDisconnect", @@ -43,8 +44,8 @@ public class ServerPlayNetworkHandlerMixin implements INetworkHandler { } @Override - public boolean osl$networking$handleCustomPayload(CustomPayloadPacket packet) { - return ServerPlayNetworkingImpl.handle(server, (ServerPlayNetworkHandler)(Object)this, player, packet); + public boolean osl$networking$canRunOffMainThread() { + return true; } @Override @@ -53,12 +54,17 @@ public class ServerPlayNetworkHandlerMixin implements INetworkHandler { } @Override - public void osl$networking$registerChannels(Set channels) { + public boolean osl$networking$isPlayReady(NamespacedIdentifier channel) { + return clientChannels != null && clientChannels.contains(channel); + } + + @Override + public void osl$networking$registerChannels(Set channels) { clientChannels = new LinkedHashSet<>(channels); } @Override - public boolean osl$networking$isRegisteredChannel(String channel) { - return clientChannels != null && clientChannels.contains(channel); + public boolean osl$networking$handleCustomPayload(CustomPayloadPacket packet) { + return ServerPlayNetworkingImpl.handlePacket(server, (ServerPlayNetworkHandler)(Object)this, player, packet); } } diff --git a/libraries/networking/networking-mc11w49a-mc12w16a/src/main/resources/osl.networking.mixins.json b/libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/resources/osl.networking.mixins.json similarity index 75% rename from libraries/networking/networking-mc11w49a-mc12w16a/src/main/resources/osl.networking.mixins.json rename to libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/resources/osl.networking.mixins.json index 67872f8d..8ef551df 100644 --- a/libraries/networking/networking-mc11w49a-mc12w16a/src/main/resources/osl.networking.mixins.json +++ b/libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/resources/osl.networking.mixins.json @@ -4,13 +4,16 @@ "package": "net.ornithemc.osl.networking.impl.mixin", "compatibilityLevel": "JAVA_8", "mixins": [ + "common.ConnectionMixin", "common.CustomPayloadPacketMixin", "common.PacketHandlerMixin" ], "client": [ - "client.ClientNetworkHandlerMixin" + "client.ClientNetworkHandlerMixin", + "client.MinecraftMixin" ], "server": [ + "server.MinecraftServerMixin", "server.ServerLoginNetworkHandlerMixin", "server.ServerPlayNetworkHandlerMixin" ], diff --git a/libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/build.gradle b/libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/build.gradle new file mode 100644 index 00000000..435282a3 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/build.gradle @@ -0,0 +1,5 @@ +setUpModule(project, + 'entrypoints-mcin-20091223-1459-mc1.5.2', + 'lifecycle-events-mc12w01a-mc12w17a', + 'networking-mcb1.0-mc13w39b' +) diff --git a/libraries/networking/networking-mc12w17a-mc12w17a/gradle.properties b/libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/gradle.properties similarity index 100% rename from libraries/networking/networking-mc12w17a-mc12w17a/gradle.properties rename to libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/gradle.properties diff --git a/libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java new file mode 100644 index 00000000..74d7452d --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java @@ -0,0 +1,57 @@ +package net.ornithemc.osl.networking.impl; + +import net.minecraft.network.packet.CustomPayloadPacket; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.entrypoints.api.ModInitializer; +import net.ornithemc.osl.entrypoints.api.client.ClientModInitializer; +import net.ornithemc.osl.entrypoints.api.server.ServerModInitializer; +import net.ornithemc.osl.lifecycle.api.client.MinecraftClientEvents; +import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; +import net.ornithemc.osl.networking.api.StringChannelIdentifierParser; +import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; +import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; +import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; +import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; + +public class Networking implements ModInitializer, ClientModInitializer, ServerModInitializer { + + @Override + public void init() { + // no-op + } + + @Override + public void initClient() { + MinecraftClientEvents.START.register(ClientPlayNetworkingImpl::setUp); + MinecraftClientEvents.STOP.register(ClientPlayNetworkingImpl::destroy); + ClientPlayNetworkingImpl.setUpPacketFactory(Networking::newCustomPayloadPacket); + ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { + ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); + ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); + + return true; + }); + } + + @Override + public void initServer() { + MinecraftServerEvents.START.register(ServerPlayNetworkingImpl::setUp); + MinecraftServerEvents.STOP.register(ServerPlayNetworkingImpl::destroy); + ServerPlayNetworkingImpl.setUpPacketFactory(Networking::newCustomPayloadPacket); + ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { + // send channel registration data as a response to receiving client channel registration data + ServerPlayNetworkingImpl.sendNoCheck(player, HandshakePayload.CHANNEL, HandshakePayload.server()); + + ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); + ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); + + return true; + }); + } + + private static CustomPayloadPacket newCustomPayloadPacket(NamespacedIdentifier channel, byte[] data) { + return new CustomPayloadPacket(StringChannelIdentifierParser.toString(channel), data); + } +} diff --git a/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java b/libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java similarity index 55% rename from libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java rename to libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java index a583e081..47f751c1 100644 --- a/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java +++ b/libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java @@ -1,17 +1,9 @@ package net.ornithemc.osl.networking.impl.interfaces.mixin; -import java.util.Set; - import net.minecraft.network.packet.CustomPayloadPacket; public interface INetworkHandler { boolean osl$networking$handleCustomPayload(CustomPayloadPacket packet); - boolean osl$networking$isPlayReady(); - - void osl$networking$registerChannels(Set channels); - - boolean osl$networking$isRegisteredChannel(String channel); - } diff --git a/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java b/libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java similarity index 65% rename from libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java rename to libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java index 1de7fa9b..6faff580 100644 --- a/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java +++ b/libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java @@ -3,7 +3,6 @@ import java.util.LinkedHashSet; import java.util.Set; -import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -13,22 +12,26 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.network.handler.ClientNetworkHandler; +import net.minecraft.client.world.MultiplayerWorld; import net.minecraft.network.packet.CustomPayloadPacket; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; import net.ornithemc.osl.networking.impl.HandshakePayload; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; @Mixin(ClientNetworkHandler.class) -public class ClientNetworkHandlerMixin implements INetworkHandler { +public class ClientNetworkHandlerMixin implements NetworkHandlerAccess, INetworkHandler { - @Shadow @Final private Minecraft minecraft; + @Shadow private Minecraft minecraft; + @Shadow private MultiplayerWorld world; /** * Channels that the server is listening to. */ - @Unique private Set serverChannels; + @Unique private Set serverChannels; @Inject( method = "handleLogin", @@ -38,7 +41,7 @@ public class ClientNetworkHandlerMixin implements INetworkHandler { ) private void osl$networking$handleLogin(CallbackInfo ci) { // send channel registration data as soon as login occurs - ClientPlayNetworkingImpl.doSend(HandshakePayload.CHANNEL, HandshakePayload.client()); + ClientPlayNetworkingImpl.sendNoCheck(HandshakePayload.CHANNEL, HandshakePayload.client()); ClientConnectionEvents.LOGIN.invoker().accept(minecraft); } @@ -55,8 +58,8 @@ public class ClientNetworkHandlerMixin implements INetworkHandler { } @Override - public boolean osl$networking$handleCustomPayload(CustomPayloadPacket packet) { - return ClientPlayNetworkingImpl.handle(minecraft, (ClientNetworkHandler)(Object)this, packet); + public boolean osl$networking$canRunOffMainThread() { + return minecraft != null && minecraft.world != null && minecraft.player != null && world != null; } @Override @@ -65,12 +68,17 @@ public class ClientNetworkHandlerMixin implements INetworkHandler { } @Override - public void osl$networking$registerChannels(Set channels) { + public boolean osl$networking$isPlayReady(NamespacedIdentifier channel) { + return serverChannels != null && serverChannels.contains(channel); + } + + @Override + public void osl$networking$registerChannels(Set channels) { serverChannels = new LinkedHashSet<>(channels); } @Override - public boolean osl$networking$isRegisteredChannel(String channel) { - return serverChannels != null && serverChannels.contains(channel); + public boolean osl$networking$handleCustomPayload(CustomPayloadPacket packet) { + return ClientPlayNetworkingImpl.handlePacket(minecraft, (ClientNetworkHandler)(Object)this, packet); } } diff --git a/libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java b/libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java new file mode 100644 index 00000000..85baea9b --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java @@ -0,0 +1,44 @@ +package net.ornithemc.osl.networking.impl.mixin.client; + +import java.util.ArrayDeque; +import java.util.Queue; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.client.Minecraft; + +import net.ornithemc.osl.networking.impl.access.TaskRunnerAccess; + +@Mixin(Minecraft.class) +public class MinecraftMixin implements TaskRunnerAccess { + + @Unique + private Queue tasks = new ArrayDeque<>(); + + @Inject( + method = "tick", + at = @At( + value = "HEAD" + ) + ) + private void osl$networking$runTasks(CallbackInfo ci) { + synchronized (this.tasks) { + while (!this.tasks.isEmpty()) { + this.tasks.poll().run(); + } + } + } + + @Override + public boolean osl$networking$submit(Runnable task) { + synchronized (this.tasks) { + this.tasks.add(task); + } + + return true; + } +} diff --git a/libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ConnectionMixin.java b/libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ConnectionMixin.java new file mode 100644 index 00000000..8cbf1eeb --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ConnectionMixin.java @@ -0,0 +1,33 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import net.minecraft.network.Connection; +import net.minecraft.network.PacketHandler; +import net.minecraft.network.packet.Packet; + +import net.ornithemc.osl.networking.impl.Connections; + +@Mixin(Connection.class) +public class ConnectionMixin { + + @Shadow private PacketHandler listener; + + @Inject( + method = "read", + cancellable = true, + at = @At( + value = "INVOKE", + target = "Ljava/util/List;add(Ljava/lang/Object;)Z" + ) + ) + private void osl$networking$handlePacketsAsync(Packet packet, CallbackInfoReturnable cir) { + if (Connections.checkAsyncHandling(packet, listener)) { + cir.setReturnValue(true); + } + } +} diff --git a/libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadPacketMixin.java b/libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadPacketMixin.java new file mode 100644 index 00000000..f5e2b624 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadPacketMixin.java @@ -0,0 +1,39 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.Constant; +import org.spongepowered.asm.mixin.injection.ModifyConstant; + +import net.minecraft.network.packet.CustomPayloadPacket; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.api.StringChannelIdentifierParser; +import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; + +@Mixin(CustomPayloadPacket.class) +public class CustomPayloadPacketMixin implements CustomPayloadPacketAccess { + + @Shadow private String channel; + @Shadow private byte[] data; + + @ModifyConstant( + method = "read", + constant = @Constant( + intValue = 20 + ) + ) + private int osl$networking$modifyMaxChannelLength(int maxLength) { + return StringChannelIdentifierParser.MAX_LENGTH; + } + + @Override + public NamespacedIdentifier osl$networking$getChannel() { + return StringChannelIdentifierParser.fromString(channel); + } + + @Override + public byte[] osl$networking$getData() { + return data; + } +} diff --git a/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketHandlerMixin.java b/libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketHandlerMixin.java similarity index 100% rename from libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketHandlerMixin.java rename to libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketHandlerMixin.java diff --git a/libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/MinecraftServerMixin.java b/libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/MinecraftServerMixin.java new file mode 100644 index 00000000..5cdbf6c6 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/MinecraftServerMixin.java @@ -0,0 +1,48 @@ +package net.ornithemc.osl.networking.impl.mixin.server; + +import java.util.ArrayDeque; +import java.util.Queue; + +import org.objectweb.asm.Opcodes; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.server.MinecraftServer; + +import net.ornithemc.osl.networking.impl.access.TaskRunnerAccess; + +@Mixin(MinecraftServer.class) +public class MinecraftServerMixin implements TaskRunnerAccess { + + @Unique + private Queue tasks = new ArrayDeque<>(); + + @Inject( + method = "tick", + at = @At( + value = "FIELD", + opcode = Opcodes.PUTFIELD, + target = "Lnet/minecraft/server/MinecraftServer;ticks:I" + ) + ) + private void osl$networking$runTasks(CallbackInfo ci) { + synchronized (this.tasks) { + while (!this.tasks.isEmpty()) { + this.tasks.poll().run(); + } + } + } + + @Override + public boolean osl$networking$submit(Runnable task) { + synchronized (this.tasks) { + this.tasks.add(task); + } + + return true; + } +} diff --git a/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerLoginNetworkHandlerMixin.java b/libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerLoginNetworkHandlerMixin.java similarity index 100% rename from libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerLoginNetworkHandlerMixin.java rename to libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerLoginNetworkHandlerMixin.java diff --git a/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java b/libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java similarity index 71% rename from libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java rename to libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java index 35197aaa..a07c8490 100644 --- a/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java +++ b/libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java @@ -3,7 +3,6 @@ import java.util.LinkedHashSet; import java.util.Set; -import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -16,20 +15,22 @@ import net.minecraft.server.entity.mob.player.ServerPlayerEntity; import net.minecraft.server.network.handler.ServerPlayNetworkHandler; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; @Mixin(ServerPlayNetworkHandler.class) -public class ServerPlayNetworkHandlerMixin implements INetworkHandler { +public class ServerPlayNetworkHandlerMixin implements NetworkHandlerAccess, INetworkHandler { - @Shadow @Final private MinecraftServer server; - @Shadow @Final private ServerPlayerEntity player; + @Shadow private MinecraftServer server; + @Shadow private ServerPlayerEntity player; /** * Channels that the client is listening to. */ - @Unique private Set clientChannels; + @Unique private Set clientChannels; @Inject( method = "onDisconnect", @@ -56,8 +57,8 @@ public class ServerPlayNetworkHandlerMixin implements INetworkHandler { } @Override - public boolean osl$networking$handleCustomPayload(CustomPayloadPacket packet) { - return ServerPlayNetworkingImpl.handle(server, (ServerPlayNetworkHandler)(Object)this, player, packet); + public boolean osl$networking$canRunOffMainThread() { + return true; } @Override @@ -66,12 +67,17 @@ public class ServerPlayNetworkHandlerMixin implements INetworkHandler { } @Override - public void osl$networking$registerChannels(Set channels) { + public boolean osl$networking$isPlayReady(NamespacedIdentifier channel) { + return clientChannels != null && clientChannels.contains(channel); + } + + @Override + public void osl$networking$registerChannels(Set channels) { clientChannels = new LinkedHashSet<>(channels); } @Override - public boolean osl$networking$isRegisteredChannel(String channel) { - return clientChannels != null && clientChannels.contains(channel); + public boolean osl$networking$handleCustomPayload(CustomPayloadPacket packet) { + return ServerPlayNetworkingImpl.handlePacket(server, (ServerPlayNetworkHandler)(Object)this, player, packet); } } diff --git a/libraries/networking/networking-mc12w17a-mc12w17a/src/main/resources/osl.networking.mixins.json b/libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/resources/osl.networking.mixins.json similarity index 75% rename from libraries/networking/networking-mc12w17a-mc12w17a/src/main/resources/osl.networking.mixins.json rename to libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/resources/osl.networking.mixins.json index 67872f8d..8ef551df 100644 --- a/libraries/networking/networking-mc12w17a-mc12w17a/src/main/resources/osl.networking.mixins.json +++ b/libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/resources/osl.networking.mixins.json @@ -4,13 +4,16 @@ "package": "net.ornithemc.osl.networking.impl.mixin", "compatibilityLevel": "JAVA_8", "mixins": [ + "common.ConnectionMixin", "common.CustomPayloadPacketMixin", "common.PacketHandlerMixin" ], "client": [ - "client.ClientNetworkHandlerMixin" + "client.ClientNetworkHandlerMixin", + "client.MinecraftMixin" ], "server": [ + "server.MinecraftServerMixin", "server.ServerLoginNetworkHandlerMixin", "server.ServerPlayNetworkHandlerMixin" ], diff --git a/libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/build.gradle b/libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/build.gradle new file mode 100644 index 00000000..d7d42d27 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/build.gradle @@ -0,0 +1,5 @@ +setUpModule(project, + 'entrypoints-mcin-20091223-1459-mc1.5.2', + 'lifecycle-events-mc12w18a-mc12w19a', + 'networking-mcb1.0-mc13w39b' +) diff --git a/libraries/networking/networking-mc12w18a-mc12w19a/gradle.properties b/libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/gradle.properties similarity index 100% rename from libraries/networking/networking-mc12w18a-mc12w19a/gradle.properties rename to libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/gradle.properties diff --git a/libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java new file mode 100644 index 00000000..e2f5e0b5 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java @@ -0,0 +1,57 @@ +package net.ornithemc.osl.networking.impl; + +import net.minecraft.network.packet.CustomPayloadPacket; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.entrypoints.api.ModInitializer; +import net.ornithemc.osl.entrypoints.api.client.ClientModInitializer; +import net.ornithemc.osl.entrypoints.api.server.ServerModInitializer; +import net.ornithemc.osl.lifecycle.api.client.MinecraftClientEvents; +import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; +import net.ornithemc.osl.networking.api.StringChannelIdentifierParser; +import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; +import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; +import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; +import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; + +public class Networking implements ModInitializer, ClientModInitializer, ServerModInitializer { + + @Override + public void init() { + MinecraftServerEvents.START.register(ServerPlayNetworkingImpl::setUp); + MinecraftServerEvents.STOP.register(ServerPlayNetworkingImpl::destroy); + ServerPlayNetworkingImpl.setUpPacketFactory(Networking::newCustomPayloadPacket); + ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { + // send channel registration data as a response to receiving client channel registration data + ServerPlayNetworkingImpl.sendNoCheck(player, HandshakePayload.CHANNEL, HandshakePayload.server()); + + ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); + ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); + + return true; + }); + } + + @Override + public void initClient() { + MinecraftClientEvents.START.register(ClientPlayNetworkingImpl::setUp); + MinecraftClientEvents.STOP.register(ClientPlayNetworkingImpl::destroy); + ClientPlayNetworkingImpl.setUpPacketFactory(Networking::newCustomPayloadPacket); + ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { + ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); + ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); + + return true; + }); + } + + @Override + public void initServer() { + // no-op + } + + private static CustomPayloadPacket newCustomPayloadPacket(NamespacedIdentifier channel, byte[] data) { + return new CustomPayloadPacket(StringChannelIdentifierParser.toString(channel), data); + } +} diff --git a/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java b/libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java similarity index 66% rename from libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java rename to libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java index 4c469af8..a5a8a07b 100644 --- a/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java +++ b/libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java @@ -3,7 +3,6 @@ import java.util.LinkedHashSet; import java.util.Set; -import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -13,22 +12,25 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.network.handler.ClientNetworkHandler; +import net.minecraft.client.world.ClientWorld; import net.minecraft.network.packet.CustomPayloadPacket; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; import net.ornithemc.osl.networking.impl.HandshakePayload; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; @Mixin(ClientNetworkHandler.class) -public class ClientNetworkHandlerMixin implements INetworkHandler { +public class ClientNetworkHandlerMixin implements NetworkHandlerAccess { - @Shadow @Final private Minecraft minecraft; + @Shadow private Minecraft minecraft; + @Shadow private ClientWorld world; /** * Channels that the server is listening to. */ - @Unique private Set serverChannels; + @Unique private Set serverChannels; @Inject( method = "handleLogin", @@ -38,7 +40,7 @@ public class ClientNetworkHandlerMixin implements INetworkHandler { ) private void osl$networking$handleLogin(CallbackInfo ci) { // send channel registration data as soon as login occurs - ClientPlayNetworkingImpl.doSend(HandshakePayload.CHANNEL, HandshakePayload.client()); + ClientPlayNetworkingImpl.sendNoCheck(HandshakePayload.CHANNEL, HandshakePayload.client()); ClientConnectionEvents.LOGIN.invoker().accept(minecraft); } @@ -62,23 +64,28 @@ public class ClientNetworkHandlerMixin implements INetworkHandler { ) ) private void osl$networking$handleCustomPayload(CustomPayloadPacket packet, CallbackInfo ci) { - if (ClientPlayNetworkingImpl.handle(minecraft, (ClientNetworkHandler)(Object)this, packet)) { + if (ClientPlayNetworkingImpl.handlePacket(minecraft, (ClientNetworkHandler)(Object)this, packet)) { ci.cancel(); } } + @Override + public boolean osl$networking$canRunOffMainThread() { + return minecraft != null && minecraft.world != null && minecraft.player != null && world != null; + } + @Override public boolean osl$networking$isPlayReady() { return serverChannels != null; } @Override - public void osl$networking$registerChannels(Set channels) { - serverChannels = new LinkedHashSet<>(channels); + public boolean osl$networking$isPlayReady(NamespacedIdentifier channel) { + return serverChannels != null && serverChannels.contains(channel); } @Override - public boolean osl$networking$isRegisteredChannel(String channel) { - return serverChannels != null && serverChannels.contains(channel); + public void osl$networking$registerChannels(Set channels) { + serverChannels = new LinkedHashSet<>(channels); } } diff --git a/libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java b/libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java new file mode 100644 index 00000000..85baea9b --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java @@ -0,0 +1,44 @@ +package net.ornithemc.osl.networking.impl.mixin.client; + +import java.util.ArrayDeque; +import java.util.Queue; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.client.Minecraft; + +import net.ornithemc.osl.networking.impl.access.TaskRunnerAccess; + +@Mixin(Minecraft.class) +public class MinecraftMixin implements TaskRunnerAccess { + + @Unique + private Queue tasks = new ArrayDeque<>(); + + @Inject( + method = "tick", + at = @At( + value = "HEAD" + ) + ) + private void osl$networking$runTasks(CallbackInfo ci) { + synchronized (this.tasks) { + while (!this.tasks.isEmpty()) { + this.tasks.poll().run(); + } + } + } + + @Override + public boolean osl$networking$submit(Runnable task) { + synchronized (this.tasks) { + this.tasks.add(task); + } + + return true; + } +} diff --git a/libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ConnectionMixin.java b/libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ConnectionMixin.java new file mode 100644 index 00000000..8cbf1eeb --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ConnectionMixin.java @@ -0,0 +1,33 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import net.minecraft.network.Connection; +import net.minecraft.network.PacketHandler; +import net.minecraft.network.packet.Packet; + +import net.ornithemc.osl.networking.impl.Connections; + +@Mixin(Connection.class) +public class ConnectionMixin { + + @Shadow private PacketHandler listener; + + @Inject( + method = "read", + cancellable = true, + at = @At( + value = "INVOKE", + target = "Ljava/util/List;add(Ljava/lang/Object;)Z" + ) + ) + private void osl$networking$handlePacketsAsync(Packet packet, CallbackInfoReturnable cir) { + if (Connections.checkAsyncHandling(packet, listener)) { + cir.setReturnValue(true); + } + } +} diff --git a/libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadPacketMixin.java b/libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadPacketMixin.java new file mode 100644 index 00000000..f5e2b624 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadPacketMixin.java @@ -0,0 +1,39 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.Constant; +import org.spongepowered.asm.mixin.injection.ModifyConstant; + +import net.minecraft.network.packet.CustomPayloadPacket; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.api.StringChannelIdentifierParser; +import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; + +@Mixin(CustomPayloadPacket.class) +public class CustomPayloadPacketMixin implements CustomPayloadPacketAccess { + + @Shadow private String channel; + @Shadow private byte[] data; + + @ModifyConstant( + method = "read", + constant = @Constant( + intValue = 20 + ) + ) + private int osl$networking$modifyMaxChannelLength(int maxLength) { + return StringChannelIdentifierParser.MAX_LENGTH; + } + + @Override + public NamespacedIdentifier osl$networking$getChannel() { + return StringChannelIdentifierParser.fromString(channel); + } + + @Override + public byte[] osl$networking$getData() { + return data; + } +} diff --git a/libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/MinecraftServerMixin.java b/libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/MinecraftServerMixin.java new file mode 100644 index 00000000..0842d547 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/MinecraftServerMixin.java @@ -0,0 +1,48 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import java.util.ArrayDeque; +import java.util.Queue; + +import org.objectweb.asm.Opcodes; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.server.MinecraftServer; + +import net.ornithemc.osl.networking.impl.access.TaskRunnerAccess; + +@Mixin(MinecraftServer.class) +public class MinecraftServerMixin implements TaskRunnerAccess { + + @Unique + private Queue tasks = new ArrayDeque<>(); + + @Inject( + method = "tick", + at = @At( + value = "FIELD", + opcode = Opcodes.PUTFIELD, + target = "Lnet/minecraft/server/MinecraftServer;ticks:I" + ) + ) + private void osl$networking$runTasks(CallbackInfo ci) { + synchronized (this.tasks) { + while (!this.tasks.isEmpty()) { + this.tasks.poll().run(); + } + } + } + + @Override + public boolean osl$networking$submit(Runnable task) { + synchronized (this.tasks) { + this.tasks.add(task); + } + + return true; + } +} diff --git a/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerLoginNetworkHandlerMixin.java b/libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerLoginNetworkHandlerMixin.java similarity index 100% rename from libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerLoginNetworkHandlerMixin.java rename to libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerLoginNetworkHandlerMixin.java diff --git a/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java b/libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java similarity index 69% rename from libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java rename to libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java index cc8e6a20..c05277df 100644 --- a/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java +++ b/libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java @@ -3,7 +3,6 @@ import java.util.LinkedHashSet; import java.util.Set; -import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -16,20 +15,21 @@ import net.minecraft.server.entity.mob.player.ServerPlayerEntity; import net.minecraft.server.network.handler.ServerPlayNetworkHandler; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; @Mixin(ServerPlayNetworkHandler.class) -public class ServerPlayNetworkHandlerMixin implements INetworkHandler { +public class ServerPlayNetworkHandlerMixin implements NetworkHandlerAccess { - @Shadow @Final private MinecraftServer server; - @Shadow @Final private ServerPlayerEntity player; + @Shadow private MinecraftServer server; + @Shadow private ServerPlayerEntity player; /** * Channels that the client is listening to. */ - @Unique private Set clientChannels; + @Unique private Set clientChannels; @Inject( method = "onDisconnect", @@ -50,23 +50,28 @@ public class ServerPlayNetworkHandlerMixin implements INetworkHandler { ) ) private void osl$networking$handleCustomPayload(CustomPayloadPacket packet, CallbackInfo ci) { - if (ServerPlayNetworkingImpl.handle(server, (ServerPlayNetworkHandler)(Object)this, player, packet)) { + if (ServerPlayNetworkingImpl.handlePacket(server, (ServerPlayNetworkHandler)(Object)this, player, packet)) { ci.cancel(); } } + @Override + public boolean osl$networking$canRunOffMainThread() { + return true; + } + @Override public boolean osl$networking$isPlayReady() { return clientChannels != null; } @Override - public void osl$networking$registerChannels(Set channels) { - clientChannels = new LinkedHashSet<>(channels); + public boolean osl$networking$isPlayReady(NamespacedIdentifier channel) { + return clientChannels != null && clientChannels.contains(channel); } @Override - public boolean osl$networking$isRegisteredChannel(String channel) { - return clientChannels != null && clientChannels.contains(channel); + public void osl$networking$registerChannels(Set channels) { + clientChannels = new LinkedHashSet<>(channels); } } diff --git a/libraries/networking/networking-mc12w18a-mc12w19a/src/main/resources/osl.networking.mixins.json b/libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/src/main/resources/osl.networking.mixins.json similarity index 73% rename from libraries/networking/networking-mc12w18a-mc12w19a/src/main/resources/osl.networking.mixins.json rename to libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/src/main/resources/osl.networking.mixins.json index e90f6883..62d8d97e 100644 --- a/libraries/networking/networking-mc12w18a-mc12w19a/src/main/resources/osl.networking.mixins.json +++ b/libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/src/main/resources/osl.networking.mixins.json @@ -4,12 +4,15 @@ "package": "net.ornithemc.osl.networking.impl.mixin", "compatibilityLevel": "JAVA_8", "mixins": [ + "common.ConnectionMixin", "common.CustomPayloadPacketMixin", + "common.MinecraftServerMixin", "common.ServerLoginNetworkHandlerMixin", "common.ServerPlayNetworkHandlerMixin" ], "client": [ - "client.ClientNetworkHandlerMixin" + "client.ClientNetworkHandlerMixin", + "client.MinecraftMixin" ], "server": [ ], diff --git a/libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/build.gradle b/libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/build.gradle new file mode 100644 index 00000000..2ba2de65 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/build.gradle @@ -0,0 +1,5 @@ +setUpModule(project, + 'entrypoints-mcin-20091223-1459-mc1.5.2', + 'lifecycle-events-mc12w21a-mc1.6.4', + 'networking-mcb1.0-mc13w39b' +) diff --git a/libraries/networking/networking-mc12w21a-mc13w39b/gradle.properties b/libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/gradle.properties similarity index 77% rename from libraries/networking/networking-mc12w21a-mc13w39b/gradle.properties rename to libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/gradle.properties index f77fabb6..19360a2c 100644 --- a/libraries/networking/networking-mc12w21a-mc13w39b/gradle.properties +++ b/libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/gradle.properties @@ -3,6 +3,6 @@ min_mc_version = 12w21a max_mc_version = 13w39b mc_version_range = >=1.3.1-alpha.12.21.a <=1.7-alpha.13.39.b -minecraft_version = 13w39b +minecraft_version = 1.5.2 feather_build = 1 -nests_build = 2 +nests_build = 5 diff --git a/libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/Networking.java new file mode 100644 index 00000000..e2f5e0b5 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/Networking.java @@ -0,0 +1,57 @@ +package net.ornithemc.osl.networking.impl; + +import net.minecraft.network.packet.CustomPayloadPacket; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.entrypoints.api.ModInitializer; +import net.ornithemc.osl.entrypoints.api.client.ClientModInitializer; +import net.ornithemc.osl.entrypoints.api.server.ServerModInitializer; +import net.ornithemc.osl.lifecycle.api.client.MinecraftClientEvents; +import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; +import net.ornithemc.osl.networking.api.StringChannelIdentifierParser; +import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; +import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; +import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; +import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; + +public class Networking implements ModInitializer, ClientModInitializer, ServerModInitializer { + + @Override + public void init() { + MinecraftServerEvents.START.register(ServerPlayNetworkingImpl::setUp); + MinecraftServerEvents.STOP.register(ServerPlayNetworkingImpl::destroy); + ServerPlayNetworkingImpl.setUpPacketFactory(Networking::newCustomPayloadPacket); + ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { + // send channel registration data as a response to receiving client channel registration data + ServerPlayNetworkingImpl.sendNoCheck(player, HandshakePayload.CHANNEL, HandshakePayload.server()); + + ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); + ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); + + return true; + }); + } + + @Override + public void initClient() { + MinecraftClientEvents.START.register(ClientPlayNetworkingImpl::setUp); + MinecraftClientEvents.STOP.register(ClientPlayNetworkingImpl::destroy); + ClientPlayNetworkingImpl.setUpPacketFactory(Networking::newCustomPayloadPacket); + ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { + ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); + ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); + + return true; + }); + } + + @Override + public void initServer() { + // no-op + } + + private static CustomPayloadPacket newCustomPayloadPacket(NamespacedIdentifier channel, byte[] data) { + return new CustomPayloadPacket(StringChannelIdentifierParser.toString(channel), data); + } +} diff --git a/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java b/libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java similarity index 66% rename from libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java rename to libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java index 4c469af8..a5a8a07b 100644 --- a/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java +++ b/libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java @@ -3,7 +3,6 @@ import java.util.LinkedHashSet; import java.util.Set; -import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -13,22 +12,25 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.network.handler.ClientNetworkHandler; +import net.minecraft.client.world.ClientWorld; import net.minecraft.network.packet.CustomPayloadPacket; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; import net.ornithemc.osl.networking.impl.HandshakePayload; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; @Mixin(ClientNetworkHandler.class) -public class ClientNetworkHandlerMixin implements INetworkHandler { +public class ClientNetworkHandlerMixin implements NetworkHandlerAccess { - @Shadow @Final private Minecraft minecraft; + @Shadow private Minecraft minecraft; + @Shadow private ClientWorld world; /** * Channels that the server is listening to. */ - @Unique private Set serverChannels; + @Unique private Set serverChannels; @Inject( method = "handleLogin", @@ -38,7 +40,7 @@ public class ClientNetworkHandlerMixin implements INetworkHandler { ) private void osl$networking$handleLogin(CallbackInfo ci) { // send channel registration data as soon as login occurs - ClientPlayNetworkingImpl.doSend(HandshakePayload.CHANNEL, HandshakePayload.client()); + ClientPlayNetworkingImpl.sendNoCheck(HandshakePayload.CHANNEL, HandshakePayload.client()); ClientConnectionEvents.LOGIN.invoker().accept(minecraft); } @@ -62,23 +64,28 @@ public class ClientNetworkHandlerMixin implements INetworkHandler { ) ) private void osl$networking$handleCustomPayload(CustomPayloadPacket packet, CallbackInfo ci) { - if (ClientPlayNetworkingImpl.handle(minecraft, (ClientNetworkHandler)(Object)this, packet)) { + if (ClientPlayNetworkingImpl.handlePacket(minecraft, (ClientNetworkHandler)(Object)this, packet)) { ci.cancel(); } } + @Override + public boolean osl$networking$canRunOffMainThread() { + return minecraft != null && minecraft.world != null && minecraft.player != null && world != null; + } + @Override public boolean osl$networking$isPlayReady() { return serverChannels != null; } @Override - public void osl$networking$registerChannels(Set channels) { - serverChannels = new LinkedHashSet<>(channels); + public boolean osl$networking$isPlayReady(NamespacedIdentifier channel) { + return serverChannels != null && serverChannels.contains(channel); } @Override - public boolean osl$networking$isRegisteredChannel(String channel) { - return serverChannels != null && serverChannels.contains(channel); + public void osl$networking$registerChannels(Set channels) { + serverChannels = new LinkedHashSet<>(channels); } } diff --git a/libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/LocalConnectionMixin.java b/libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/LocalConnectionMixin.java new file mode 100644 index 00000000..61f65ca8 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/LocalConnectionMixin.java @@ -0,0 +1,32 @@ +package net.ornithemc.osl.networking.impl.mixin.client; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.network.LocalConnection; +import net.minecraft.network.PacketHandler; +import net.minecraft.network.packet.Packet; + +import net.ornithemc.osl.networking.impl.Connections; + +@Mixin(LocalConnection.class) +public class LocalConnectionMixin { + + @Shadow private PacketHandler listener; + + @Inject( + method = "accept", + cancellable = true, + at = @At( + value = "HEAD" + ) + ) + private void osl$networking$handlePacketsAsync(Packet packet, CallbackInfo ci) { + if (Connections.checkAsyncHandling(packet, listener)) { + ci.cancel(); + } + } +} diff --git a/libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java b/libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java new file mode 100644 index 00000000..85baea9b --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java @@ -0,0 +1,44 @@ +package net.ornithemc.osl.networking.impl.mixin.client; + +import java.util.ArrayDeque; +import java.util.Queue; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.client.Minecraft; + +import net.ornithemc.osl.networking.impl.access.TaskRunnerAccess; + +@Mixin(Minecraft.class) +public class MinecraftMixin implements TaskRunnerAccess { + + @Unique + private Queue tasks = new ArrayDeque<>(); + + @Inject( + method = "tick", + at = @At( + value = "HEAD" + ) + ) + private void osl$networking$runTasks(CallbackInfo ci) { + synchronized (this.tasks) { + while (!this.tasks.isEmpty()) { + this.tasks.poll().run(); + } + } + } + + @Override + public boolean osl$networking$submit(Runnable task) { + synchronized (this.tasks) { + this.tasks.add(task); + } + + return true; + } +} diff --git a/libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadPacketMixin.java b/libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadPacketMixin.java new file mode 100644 index 00000000..f5e2b624 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadPacketMixin.java @@ -0,0 +1,39 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.Constant; +import org.spongepowered.asm.mixin.injection.ModifyConstant; + +import net.minecraft.network.packet.CustomPayloadPacket; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.api.StringChannelIdentifierParser; +import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; + +@Mixin(CustomPayloadPacket.class) +public class CustomPayloadPacketMixin implements CustomPayloadPacketAccess { + + @Shadow private String channel; + @Shadow private byte[] data; + + @ModifyConstant( + method = "read", + constant = @Constant( + intValue = 20 + ) + ) + private int osl$networking$modifyMaxChannelLength(int maxLength) { + return StringChannelIdentifierParser.MAX_LENGTH; + } + + @Override + public NamespacedIdentifier osl$networking$getChannel() { + return StringChannelIdentifierParser.fromString(channel); + } + + @Override + public byte[] osl$networking$getData() { + return data; + } +} diff --git a/libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/MinecraftServerMixin.java b/libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/MinecraftServerMixin.java new file mode 100644 index 00000000..355179c1 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/MinecraftServerMixin.java @@ -0,0 +1,44 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import java.util.ArrayDeque; +import java.util.Queue; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.server.MinecraftServer; + +import net.ornithemc.osl.networking.impl.access.TaskRunnerAccess; + +@Mixin(MinecraftServer.class) +public class MinecraftServerMixin implements TaskRunnerAccess { + + @Unique + private Queue tasks = new ArrayDeque<>(); + + @Inject( + method = "tickWorlds", + at = @At( + value = "HEAD" + ) + ) + private void osl$networking$runTasks(CallbackInfo ci) { + synchronized (this.tasks) { + while (!this.tasks.isEmpty()) { + this.tasks.poll().run(); + } + } + } + + @Override + public boolean osl$networking$submit(Runnable task) { + synchronized (this.tasks) { + this.tasks.add(task); + } + + return true; + } +} diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java b/libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java similarity index 93% rename from libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java rename to libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java index eaca81eb..524a0e78 100644 --- a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java +++ b/libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java @@ -10,7 +10,7 @@ import net.minecraft.network.Connection; import net.minecraft.server.MinecraftServer; import net.minecraft.server.PlayerManager; -import net.minecraft.server.entity.living.player.ServerPlayerEntity; +import net.minecraft.server.entity.mob.player.ServerPlayerEntity; import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; diff --git a/libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/RemoteConnectionMixin.java b/libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/RemoteConnectionMixin.java new file mode 100644 index 00000000..485ba3d4 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/RemoteConnectionMixin.java @@ -0,0 +1,33 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import net.minecraft.network.PacketHandler; +import net.minecraft.network.RemoteConnection; +import net.minecraft.network.packet.Packet; + +import net.ornithemc.osl.networking.impl.Connections; + +@Mixin(RemoteConnection.class) +public class RemoteConnectionMixin { + + @Shadow private PacketHandler listener; + + @Inject( + method = "read", + cancellable = true, + at = @At( + value = "INVOKE", + target = "Ljava/util/List;add(Ljava/lang/Object;)Z" + ) + ) + private void osl$networking$handlePacketsAsync(Packet packet, CallbackInfoReturnable cir) { + if (Connections.checkAsyncHandling(packet, listener)) { + cir.setReturnValue(true); + } + } +} diff --git a/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java b/libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java similarity index 66% rename from libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java rename to libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java index b1f392b1..c05277df 100644 --- a/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java +++ b/libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java @@ -3,7 +3,6 @@ import java.util.LinkedHashSet; import java.util.Set; -import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -13,23 +12,24 @@ import net.minecraft.network.packet.CustomPayloadPacket; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.entity.living.player.ServerPlayerEntity; +import net.minecraft.server.entity.mob.player.ServerPlayerEntity; import net.minecraft.server.network.handler.ServerPlayNetworkHandler; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; @Mixin(ServerPlayNetworkHandler.class) -public class ServerPlayNetworkHandlerMixin implements INetworkHandler { +public class ServerPlayNetworkHandlerMixin implements NetworkHandlerAccess { - @Shadow @Final private MinecraftServer server; - @Shadow @Final private ServerPlayerEntity player; + @Shadow private MinecraftServer server; + @Shadow private ServerPlayerEntity player; /** * Channels that the client is listening to. */ - @Unique private Set clientChannels; + @Unique private Set clientChannels; @Inject( method = "onDisconnect", @@ -50,23 +50,28 @@ public class ServerPlayNetworkHandlerMixin implements INetworkHandler { ) ) private void osl$networking$handleCustomPayload(CustomPayloadPacket packet, CallbackInfo ci) { - if (ServerPlayNetworkingImpl.handle(server, (ServerPlayNetworkHandler)(Object)this, player, packet)) { + if (ServerPlayNetworkingImpl.handlePacket(server, (ServerPlayNetworkHandler)(Object)this, player, packet)) { ci.cancel(); } } + @Override + public boolean osl$networking$canRunOffMainThread() { + return true; + } + @Override public boolean osl$networking$isPlayReady() { return clientChannels != null; } @Override - public void osl$networking$registerChannels(Set channels) { - clientChannels = new LinkedHashSet<>(channels); + public boolean osl$networking$isPlayReady(NamespacedIdentifier channel) { + return clientChannels != null && clientChannels.contains(channel); } @Override - public boolean osl$networking$isRegisteredChannel(String channel) { - return clientChannels != null && clientChannels.contains(channel); + public void osl$networking$registerChannels(Set channels) { + clientChannels = new LinkedHashSet<>(channels); } } diff --git a/libraries/networking/networking-mc12w21a-mc13w39b/src/main/resources/osl.networking.mixins.json b/libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/resources/osl.networking.mixins.json similarity index 67% rename from libraries/networking/networking-mc12w21a-mc13w39b/src/main/resources/osl.networking.mixins.json rename to libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/resources/osl.networking.mixins.json index 2ec9d276..5b686811 100644 --- a/libraries/networking/networking-mc12w21a-mc13w39b/src/main/resources/osl.networking.mixins.json +++ b/libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/resources/osl.networking.mixins.json @@ -5,11 +5,15 @@ "compatibilityLevel": "JAVA_8", "mixins": [ "common.CustomPayloadPacketMixin", + "common.MinecraftServerMixin", "common.PlayerManagerMixin", + "common.RemoteConnectionMixin", "common.ServerPlayNetworkHandlerMixin" ], "client": [ - "client.ClientNetworkHandlerMixin" + "client.ClientNetworkHandlerMixin", + "common.LocalConnectionMixin", + "client.MinecraftMixin" ], "server": [ ], diff --git a/libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/build.gradle b/libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/build.gradle new file mode 100644 index 00000000..8f761724 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/build.gradle @@ -0,0 +1,5 @@ +setUpModule(project, + 'entrypoints-mc13w16a-04192037-mc1.14.4', + 'lifecycle-events-mc13w36a-09051446-mc1.13', + 'networking-mc13w41a-mc18w30b' +) diff --git a/libraries/networking/networking-mc13w41a-mc14w20b/gradle.properties b/libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/gradle.properties similarity index 100% rename from libraries/networking/networking-mc13w41a-mc14w20b/gradle.properties rename to libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/gradle.properties diff --git a/libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/Networking.java new file mode 100644 index 00000000..4d06185a --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/Networking.java @@ -0,0 +1,56 @@ +package net.ornithemc.osl.networking.impl; + +import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; +import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; + +import net.ornithemc.osl.entrypoints.api.ModInitializer; +import net.ornithemc.osl.entrypoints.api.client.ClientModInitializer; +import net.ornithemc.osl.entrypoints.api.server.ServerModInitializer; +import net.ornithemc.osl.lifecycle.api.client.MinecraftClientEvents; +import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; +import net.ornithemc.osl.networking.api.PacketBuffers; +import net.ornithemc.osl.networking.api.StringChannelIdentifierParser; +import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; +import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; +import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; +import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; + +public class Networking implements ModInitializer, ClientModInitializer, ServerModInitializer { + + @Override + public void init() { + MinecraftServerEvents.START.register(ServerPlayNetworkingImpl::setUp); + MinecraftServerEvents.STOP.register(ServerPlayNetworkingImpl::destroy); + ServerPlayNetworkingImpl.setUpPacketFactory((channel, data) -> + new CustomPayloadS2CPacket(StringChannelIdentifierParser.toString(channel), PacketBuffers.unwrapped(data))); + ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { + // send channel registration data as a response to receiving client channel registration data + ServerPlayNetworkingImpl.sendNoCheck(player, HandshakePayload.CHANNEL, HandshakePayload.server()); + + ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); + ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); + + return true; + }); + } + + @Override + public void initClient() { + MinecraftClientEvents.START.register(ClientPlayNetworkingImpl::setUp); + MinecraftClientEvents.STOP.register(ClientPlayNetworkingImpl::destroy); + ClientPlayNetworkingImpl.setUpPacketFactory((channel, data) -> + new CustomPayloadC2SPacket(StringChannelIdentifierParser.toString(channel), PacketBuffers.unwrapped(data))); + ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { + ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); + ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); + + return true; + }); + } + + @Override + public void initServer() { + // no-op + } +} diff --git a/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java b/libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java similarity index 75% rename from libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java rename to libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java index 54cf473b..ef5dbdfb 100644 --- a/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java +++ b/libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java @@ -14,22 +14,22 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.network.handler.ClientPlayNetworkHandler; import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; -import net.minecraft.resource.Identifier; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; import net.ornithemc.osl.networking.impl.HandshakePayload; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; @Mixin(ClientPlayNetworkHandler.class) -public class ClientPlayNetworkHandlerMixin implements INetworkHandler { +public class ClientPlayNetworkHandlerMixin implements NetworkHandlerAccess { @Shadow @Final private Minecraft minecraft; /** * Channels that the server is listening to. */ - @Unique private Set serverChannels; + @Unique private Set serverChannels; @Inject( method = "handleLogin", @@ -39,7 +39,7 @@ public class ClientPlayNetworkHandlerMixin implements INetworkHandler { ) private void osl$networking$handleLogin(CallbackInfo ci) { // send channel registration data as soon as login occurs - ClientPlayNetworkingImpl.doSend(HandshakePayload.CHANNEL, HandshakePayload.client()); + ClientPlayNetworkingImpl.sendNoCheck(HandshakePayload.CHANNEL, HandshakePayload.client()); ClientConnectionEvents.LOGIN.invoker().accept(minecraft); } @@ -63,7 +63,7 @@ public class ClientPlayNetworkHandlerMixin implements INetworkHandler { ) ) private void osl$networking$handleCustomPayload(CustomPayloadS2CPacket packet, CallbackInfo ci) { - if (ClientPlayNetworkingImpl.handle(minecraft, (ClientPlayNetworkHandler)(Object)this, packet)) { + if (ClientPlayNetworkingImpl.handlePacket(minecraft, (ClientPlayNetworkHandler)(Object)this, packet)) { ci.cancel(); } } @@ -74,12 +74,12 @@ public class ClientPlayNetworkHandlerMixin implements INetworkHandler { } @Override - public void osl$networking$registerChannels(Set channels) { - serverChannels = new LinkedHashSet<>(channels); + public boolean osl$networking$isPlayReady(NamespacedIdentifier channel) { + return serverChannels != null && serverChannels.contains(channel); } @Override - public boolean osl$networking$isRegisteredChannel(Identifier channel) { - return serverChannels != null && serverChannels.contains(channel); + public void osl$networking$registerChannels(Set channels) { + serverChannels = new LinkedHashSet<>(channels); } } diff --git a/libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java b/libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java new file mode 100644 index 00000000..85baea9b --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java @@ -0,0 +1,44 @@ +package net.ornithemc.osl.networking.impl.mixin.client; + +import java.util.ArrayDeque; +import java.util.Queue; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.client.Minecraft; + +import net.ornithemc.osl.networking.impl.access.TaskRunnerAccess; + +@Mixin(Minecraft.class) +public class MinecraftMixin implements TaskRunnerAccess { + + @Unique + private Queue tasks = new ArrayDeque<>(); + + @Inject( + method = "tick", + at = @At( + value = "HEAD" + ) + ) + private void osl$networking$runTasks(CallbackInfo ci) { + synchronized (this.tasks) { + while (!this.tasks.isEmpty()) { + this.tasks.poll().run(); + } + } + } + + @Override + public boolean osl$networking$submit(Runnable task) { + synchronized (this.tasks) { + this.tasks.add(task); + } + + return true; + } +} diff --git a/libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java b/libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java new file mode 100644 index 00000000..84dc5bdc --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java @@ -0,0 +1,41 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.Constant; +import org.spongepowered.asm.mixin.injection.ModifyConstant; + +import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketBuffers; +import net.ornithemc.osl.networking.api.StringChannelIdentifierParser; +import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; + +@Mixin(CustomPayloadC2SPacket.class) +public class CustomPayloadC2SPacketMixin implements CustomPayloadPacketAccess { + + @Shadow private String channel; + @Shadow private byte[] data; + + @ModifyConstant( + method = "read", + constant = @Constant( + intValue = 20 + ) + ) + private int osl$networking$modifyMaxChannelLength(int maxLength) { + return StringChannelIdentifierParser.MAX_LENGTH; + } + + @Override + public NamespacedIdentifier osl$networking$getChannel() { + return StringChannelIdentifierParser.fromString(channel); + } + + @Override + public PacketBuffer osl$networking$getData() { + return PacketBuffers.wrap(data); + } +} diff --git a/libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadS2CPacketMixin.java b/libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadS2CPacketMixin.java new file mode 100644 index 00000000..f1730adf --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadS2CPacketMixin.java @@ -0,0 +1,41 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.Constant; +import org.spongepowered.asm.mixin.injection.ModifyConstant; + +import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketBuffers; +import net.ornithemc.osl.networking.api.StringChannelIdentifierParser; +import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; + +@Mixin(CustomPayloadS2CPacket.class) +public class CustomPayloadS2CPacketMixin implements CustomPayloadPacketAccess { + + @Shadow private String channel; + @Shadow private byte[] data; + + @ModifyConstant( + method = "read", + constant = @Constant( + intValue = 20 + ) + ) + private int osl$networking$modifyMaxChannelLength(int maxLength) { + return StringChannelIdentifierParser.MAX_LENGTH; + } + + @Override + public NamespacedIdentifier osl$networking$getChannel() { + return StringChannelIdentifierParser.fromString(channel); + } + + @Override + public PacketBuffer osl$networking$getData() { + return PacketBuffers.wrap(data); + } +} diff --git a/libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/MinecraftServerMixin.java b/libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/MinecraftServerMixin.java new file mode 100644 index 00000000..355179c1 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/MinecraftServerMixin.java @@ -0,0 +1,44 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import java.util.ArrayDeque; +import java.util.Queue; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.server.MinecraftServer; + +import net.ornithemc.osl.networking.impl.access.TaskRunnerAccess; + +@Mixin(MinecraftServer.class) +public class MinecraftServerMixin implements TaskRunnerAccess { + + @Unique + private Queue tasks = new ArrayDeque<>(); + + @Inject( + method = "tickWorlds", + at = @At( + value = "HEAD" + ) + ) + private void osl$networking$runTasks(CallbackInfo ci) { + synchronized (this.tasks) { + while (!this.tasks.isEmpty()) { + this.tasks.poll().run(); + } + } + } + + @Override + public boolean osl$networking$submit(Runnable task) { + synchronized (this.tasks) { + this.tasks.add(task); + } + + return true; + } +} diff --git a/libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketMixin.java b/libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketMixin.java new file mode 100644 index 00000000..658a8e05 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketMixin.java @@ -0,0 +1,28 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import net.minecraft.network.packet.Packet; + +import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; + +@Mixin(Packet.class) +public class PacketMixin { + + @Inject( + method = "canBeHandledOffMainThread", + cancellable = true, + at = @At( + value = "HEAD" + ) + ) + private void osl$networking$asyncCustomPayloads(CallbackInfoReturnable cir) { + // TODO: somehow only do this for channels OSL has listeners for + if (this instanceof CustomPayloadPacketAccess) { + cir.setReturnValue(true); + } + } +} diff --git a/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java b/libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java similarity index 100% rename from libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java rename to libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java diff --git a/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java b/libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java similarity index 76% rename from libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java rename to libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java index 60288278..ac66d440 100644 --- a/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java +++ b/libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java @@ -16,12 +16,13 @@ import net.minecraft.server.entity.living.player.ServerPlayerEntity; import net.minecraft.server.network.handler.ServerPlayNetworkHandler; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; @Mixin(ServerPlayNetworkHandler.class) -public class ServerPlayNetworkHandlerMixin implements INetworkHandler { +public class ServerPlayNetworkHandlerMixin implements NetworkHandlerAccess { @Shadow @Final private MinecraftServer server; @Shadow @Final private ServerPlayerEntity player; @@ -29,7 +30,7 @@ public class ServerPlayNetworkHandlerMixin implements INetworkHandler { /** * Channels that the client is listening to. */ - @Unique private Set clientChannels; + @Unique private Set clientChannels; @Inject( method = "onDisconnect", @@ -50,7 +51,7 @@ public class ServerPlayNetworkHandlerMixin implements INetworkHandler { ) ) private void osl$networking$handleCustomPayload(CustomPayloadC2SPacket packet, CallbackInfo ci) { - if (ServerPlayNetworkingImpl.handle(server, (ServerPlayNetworkHandler)(Object)this, player, packet)) { + if (ServerPlayNetworkingImpl.handlePacket(server, (ServerPlayNetworkHandler)(Object)this, player, packet)) { ci.cancel(); } } @@ -61,12 +62,12 @@ public class ServerPlayNetworkHandlerMixin implements INetworkHandler { } @Override - public void osl$networking$registerChannels(Set channels) { - clientChannels = new LinkedHashSet<>(channels); + public boolean osl$networking$isPlayReady(NamespacedIdentifier channel) { + return clientChannels != null && clientChannels.contains(channel); } @Override - public boolean osl$networking$isRegisteredChannel(String channel) { - return clientChannels != null && clientChannels.contains(channel); + public void osl$networking$registerChannels(Set channels) { + clientChannels = new LinkedHashSet<>(channels); } } diff --git a/libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/resources/osl.networking.mixins.json b/libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/resources/osl.networking.mixins.json new file mode 100644 index 00000000..e08148f7 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/resources/osl.networking.mixins.json @@ -0,0 +1,23 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "net.ornithemc.osl.networking.impl.mixin", + "compatibilityLevel": "JAVA_8", + "mixins": [ + "common.CustomPayloadC2SPacketMixin", + "common.CustomPayloadS2CPacketMixin", + "common.MinecraftServerMixin", + "common.PacketMixin", + "common.PlayerManagerMixin", + "common.ServerPlayNetworkHandlerMixin" + ], + "client": [ + "client.ClientPlayNetworkHandlerMixin", + "client.MinecraftMixin" + ], + "server": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/build.gradle b/libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/build.gradle new file mode 100644 index 00000000..8f761724 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/build.gradle @@ -0,0 +1,5 @@ +setUpModule(project, + 'entrypoints-mc13w16a-04192037-mc1.14.4', + 'lifecycle-events-mc13w36a-09051446-mc1.13', + 'networking-mc13w41a-mc18w30b' +) diff --git a/libraries/networking/networking-mc14w21a-mc14w30c/gradle.properties b/libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/gradle.properties similarity index 100% rename from libraries/networking/networking-mc14w21a-mc14w30c/gradle.properties rename to libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/gradle.properties diff --git a/libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/Networking.java new file mode 100644 index 00000000..4d06185a --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/Networking.java @@ -0,0 +1,56 @@ +package net.ornithemc.osl.networking.impl; + +import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; +import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; + +import net.ornithemc.osl.entrypoints.api.ModInitializer; +import net.ornithemc.osl.entrypoints.api.client.ClientModInitializer; +import net.ornithemc.osl.entrypoints.api.server.ServerModInitializer; +import net.ornithemc.osl.lifecycle.api.client.MinecraftClientEvents; +import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; +import net.ornithemc.osl.networking.api.PacketBuffers; +import net.ornithemc.osl.networking.api.StringChannelIdentifierParser; +import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; +import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; +import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; +import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; + +public class Networking implements ModInitializer, ClientModInitializer, ServerModInitializer { + + @Override + public void init() { + MinecraftServerEvents.START.register(ServerPlayNetworkingImpl::setUp); + MinecraftServerEvents.STOP.register(ServerPlayNetworkingImpl::destroy); + ServerPlayNetworkingImpl.setUpPacketFactory((channel, data) -> + new CustomPayloadS2CPacket(StringChannelIdentifierParser.toString(channel), PacketBuffers.unwrapped(data))); + ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { + // send channel registration data as a response to receiving client channel registration data + ServerPlayNetworkingImpl.sendNoCheck(player, HandshakePayload.CHANNEL, HandshakePayload.server()); + + ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); + ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); + + return true; + }); + } + + @Override + public void initClient() { + MinecraftClientEvents.START.register(ClientPlayNetworkingImpl::setUp); + MinecraftClientEvents.STOP.register(ClientPlayNetworkingImpl::destroy); + ClientPlayNetworkingImpl.setUpPacketFactory((channel, data) -> + new CustomPayloadC2SPacket(StringChannelIdentifierParser.toString(channel), PacketBuffers.unwrapped(data))); + ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { + ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); + ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); + + return true; + }); + } + + @Override + public void initServer() { + // no-op + } +} diff --git a/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java b/libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java similarity index 75% rename from libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java rename to libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java index a755af19..ef5dbdfb 100644 --- a/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java +++ b/libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java @@ -15,20 +15,21 @@ import net.minecraft.client.network.handler.ClientPlayNetworkHandler; import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; import net.ornithemc.osl.networking.impl.HandshakePayload; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; @Mixin(ClientPlayNetworkHandler.class) -public class ClientPlayNetworkHandlerMixin implements INetworkHandler { +public class ClientPlayNetworkHandlerMixin implements NetworkHandlerAccess { @Shadow @Final private Minecraft minecraft; /** * Channels that the server is listening to. */ - @Unique private Set serverChannels; + @Unique private Set serverChannels; @Inject( method = "handleLogin", @@ -38,7 +39,7 @@ public class ClientPlayNetworkHandlerMixin implements INetworkHandler { ) private void osl$networking$handleLogin(CallbackInfo ci) { // send channel registration data as soon as login occurs - ClientPlayNetworkingImpl.doSend(HandshakePayload.CHANNEL, HandshakePayload.client()); + ClientPlayNetworkingImpl.sendNoCheck(HandshakePayload.CHANNEL, HandshakePayload.client()); ClientConnectionEvents.LOGIN.invoker().accept(minecraft); } @@ -62,7 +63,7 @@ public class ClientPlayNetworkHandlerMixin implements INetworkHandler { ) ) private void osl$networking$handleCustomPayload(CustomPayloadS2CPacket packet, CallbackInfo ci) { - if (ClientPlayNetworkingImpl.handle(minecraft, (ClientPlayNetworkHandler)(Object)this, packet)) { + if (ClientPlayNetworkingImpl.handlePacket(minecraft, (ClientPlayNetworkHandler)(Object)this, packet)) { ci.cancel(); } } @@ -73,12 +74,12 @@ public class ClientPlayNetworkHandlerMixin implements INetworkHandler { } @Override - public void osl$networking$registerChannels(Set channels) { - serverChannels = new LinkedHashSet<>(channels); + public boolean osl$networking$isPlayReady(NamespacedIdentifier channel) { + return serverChannels != null && serverChannels.contains(channel); } @Override - public boolean osl$networking$isRegisteredChannel(String channel) { - return serverChannels != null && serverChannels.contains(channel); + public void osl$networking$registerChannels(Set channels) { + serverChannels = new LinkedHashSet<>(channels); } } diff --git a/libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java b/libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java new file mode 100644 index 00000000..06467881 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java @@ -0,0 +1,18 @@ +package net.ornithemc.osl.networking.impl.mixin.client; + +import org.spongepowered.asm.mixin.Mixin; + +import net.minecraft.client.Minecraft; +import net.minecraft.util.BlockableEventLoop; + +import net.ornithemc.osl.networking.impl.access.TaskRunnerAccess; + +@Mixin(Minecraft.class) +public abstract class MinecraftMixin implements BlockableEventLoop, TaskRunnerAccess { + + @Override + public boolean osl$networking$submit(Runnable task) { + this.submit(task); + return true; + } +} diff --git a/libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java b/libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java new file mode 100644 index 00000000..84dc5bdc --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java @@ -0,0 +1,41 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.Constant; +import org.spongepowered.asm.mixin.injection.ModifyConstant; + +import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketBuffers; +import net.ornithemc.osl.networking.api.StringChannelIdentifierParser; +import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; + +@Mixin(CustomPayloadC2SPacket.class) +public class CustomPayloadC2SPacketMixin implements CustomPayloadPacketAccess { + + @Shadow private String channel; + @Shadow private byte[] data; + + @ModifyConstant( + method = "read", + constant = @Constant( + intValue = 20 + ) + ) + private int osl$networking$modifyMaxChannelLength(int maxLength) { + return StringChannelIdentifierParser.MAX_LENGTH; + } + + @Override + public NamespacedIdentifier osl$networking$getChannel() { + return StringChannelIdentifierParser.fromString(channel); + } + + @Override + public PacketBuffer osl$networking$getData() { + return PacketBuffers.wrap(data); + } +} diff --git a/libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadS2CPacketMixin.java b/libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadS2CPacketMixin.java new file mode 100644 index 00000000..f1730adf --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadS2CPacketMixin.java @@ -0,0 +1,41 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.Constant; +import org.spongepowered.asm.mixin.injection.ModifyConstant; + +import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketBuffers; +import net.ornithemc.osl.networking.api.StringChannelIdentifierParser; +import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; + +@Mixin(CustomPayloadS2CPacket.class) +public class CustomPayloadS2CPacketMixin implements CustomPayloadPacketAccess { + + @Shadow private String channel; + @Shadow private byte[] data; + + @ModifyConstant( + method = "read", + constant = @Constant( + intValue = 20 + ) + ) + private int osl$networking$modifyMaxChannelLength(int maxLength) { + return StringChannelIdentifierParser.MAX_LENGTH; + } + + @Override + public NamespacedIdentifier osl$networking$getChannel() { + return StringChannelIdentifierParser.fromString(channel); + } + + @Override + public PacketBuffer osl$networking$getData() { + return PacketBuffers.wrap(data); + } +} diff --git a/libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/MinecraftServerMixin.java b/libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/MinecraftServerMixin.java new file mode 100644 index 00000000..032c1691 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/MinecraftServerMixin.java @@ -0,0 +1,18 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.BlockableEventLoop; + +import net.ornithemc.osl.networking.impl.access.TaskRunnerAccess; + +@Mixin(MinecraftServer.class) +public abstract class MinecraftServerMixin implements BlockableEventLoop, TaskRunnerAccess { + + @Override + public boolean osl$networking$submit(Runnable task) { + this.submit(task); + return true; + } +} diff --git a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java b/libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java similarity index 75% rename from libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java rename to libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java index eaca81eb..e88d1f5a 100644 --- a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java +++ b/libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java @@ -1,5 +1,7 @@ package net.ornithemc.osl.networking.impl.mixin.common; +import java.util.List; + import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; @@ -13,11 +15,13 @@ import net.minecraft.server.entity.living.player.ServerPlayerEntity; import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; +import net.ornithemc.osl.networking.impl.access.PlayerManagerAccess; @Mixin(PlayerManager.class) -public class PlayerManagerMixin { +public class PlayerManagerMixin implements PlayerManagerAccess { @Shadow @Final private MinecraftServer server; + @Shadow @Final private List players; @Inject( method = "onLogin", @@ -28,4 +32,9 @@ public class PlayerManagerMixin { private void osl$networking$handleLogin(Connection connection, ServerPlayerEntity player, CallbackInfo ci) { ServerConnectionEvents.LOGIN.invoker().accept(server, player); } + + @Override + public List osl$networking$getAll() { + return players; + } } diff --git a/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java b/libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java similarity index 76% rename from libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java rename to libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java index ffa9c8d3..ac66d440 100644 --- a/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java +++ b/libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java @@ -12,17 +12,17 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; -import net.minecraft.resource.Identifier; import net.minecraft.server.MinecraftServer; import net.minecraft.server.entity.living.player.ServerPlayerEntity; import net.minecraft.server.network.handler.ServerPlayNetworkHandler; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; @Mixin(ServerPlayNetworkHandler.class) -public class ServerPlayNetworkHandlerMixin implements INetworkHandler { +public class ServerPlayNetworkHandlerMixin implements NetworkHandlerAccess { @Shadow @Final private MinecraftServer server; @Shadow @Final private ServerPlayerEntity player; @@ -30,7 +30,7 @@ public class ServerPlayNetworkHandlerMixin implements INetworkHandler { /** * Channels that the client is listening to. */ - @Unique private Set clientChannels; + @Unique private Set clientChannels; @Inject( method = "onDisconnect", @@ -51,7 +51,7 @@ public class ServerPlayNetworkHandlerMixin implements INetworkHandler { ) ) private void osl$networking$handleCustomPayload(CustomPayloadC2SPacket packet, CallbackInfo ci) { - if (ServerPlayNetworkingImpl.handle(server, (ServerPlayNetworkHandler)(Object)this, player, packet)) { + if (ServerPlayNetworkingImpl.handlePacket(server, (ServerPlayNetworkHandler)(Object)this, player, packet)) { ci.cancel(); } } @@ -62,12 +62,12 @@ public class ServerPlayNetworkHandlerMixin implements INetworkHandler { } @Override - public void osl$networking$registerChannels(Set channels) { - clientChannels = new LinkedHashSet<>(channels); + public boolean osl$networking$isPlayReady(NamespacedIdentifier channel) { + return clientChannels != null && clientChannels.contains(channel); } @Override - public boolean osl$networking$isRegisteredChannel(Identifier channel) { - return clientChannels != null && clientChannels.contains(channel); + public void osl$networking$registerChannels(Set channels) { + clientChannels = new LinkedHashSet<>(channels); } } diff --git a/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/resources/osl.networking.mixins.json b/libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/resources/osl.networking.mixins.json similarity index 70% rename from libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/resources/osl.networking.mixins.json rename to libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/resources/osl.networking.mixins.json index 36ceef9e..f64bbc23 100644 --- a/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/resources/osl.networking.mixins.json +++ b/libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/resources/osl.networking.mixins.json @@ -5,11 +5,14 @@ "compatibilityLevel": "JAVA_8", "mixins": [ "common.CustomPayloadC2SPacketMixin", + "common.CustomPayloadS2CPacketMixin", + "common.MinecraftServerMixin", "common.PlayerManagerMixin", "common.ServerPlayNetworkHandlerMixin" ], "client": [ - "client.ClientPlayNetworkHandlerMixin" + "client.ClientPlayNetworkHandlerMixin", + "client.MinecraftMixin" ], "server": [ ], diff --git a/libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/build.gradle b/libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/build.gradle new file mode 100644 index 00000000..8f761724 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/build.gradle @@ -0,0 +1,5 @@ +setUpModule(project, + 'entrypoints-mc13w16a-04192037-mc1.14.4', + 'lifecycle-events-mc13w36a-09051446-mc1.13', + 'networking-mc13w41a-mc18w30b' +) diff --git a/libraries/networking/networking-mc14w31a-mc1.13-pre2/gradle.properties b/libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/gradle.properties similarity index 100% rename from libraries/networking/networking-mc14w31a-mc1.13-pre2/gradle.properties rename to libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/gradle.properties diff --git a/libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/Networking.java new file mode 100644 index 00000000..4d06185a --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/Networking.java @@ -0,0 +1,56 @@ +package net.ornithemc.osl.networking.impl; + +import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; +import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; + +import net.ornithemc.osl.entrypoints.api.ModInitializer; +import net.ornithemc.osl.entrypoints.api.client.ClientModInitializer; +import net.ornithemc.osl.entrypoints.api.server.ServerModInitializer; +import net.ornithemc.osl.lifecycle.api.client.MinecraftClientEvents; +import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; +import net.ornithemc.osl.networking.api.PacketBuffers; +import net.ornithemc.osl.networking.api.StringChannelIdentifierParser; +import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; +import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; +import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; +import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; + +public class Networking implements ModInitializer, ClientModInitializer, ServerModInitializer { + + @Override + public void init() { + MinecraftServerEvents.START.register(ServerPlayNetworkingImpl::setUp); + MinecraftServerEvents.STOP.register(ServerPlayNetworkingImpl::destroy); + ServerPlayNetworkingImpl.setUpPacketFactory((channel, data) -> + new CustomPayloadS2CPacket(StringChannelIdentifierParser.toString(channel), PacketBuffers.unwrapped(data))); + ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { + // send channel registration data as a response to receiving client channel registration data + ServerPlayNetworkingImpl.sendNoCheck(player, HandshakePayload.CHANNEL, HandshakePayload.server()); + + ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); + ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); + + return true; + }); + } + + @Override + public void initClient() { + MinecraftClientEvents.START.register(ClientPlayNetworkingImpl::setUp); + MinecraftClientEvents.STOP.register(ClientPlayNetworkingImpl::destroy); + ClientPlayNetworkingImpl.setUpPacketFactory((channel, data) -> + new CustomPayloadC2SPacket(StringChannelIdentifierParser.toString(channel), PacketBuffers.unwrapped(data))); + ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { + ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); + ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); + + return true; + }); + } + + @Override + public void initServer() { + // no-op + } +} diff --git a/libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java b/libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java new file mode 100644 index 00000000..ef5dbdfb --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java @@ -0,0 +1,85 @@ +package net.ornithemc.osl.networking.impl.mixin.client; + +import java.util.LinkedHashSet; +import java.util.Set; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.network.handler.ClientPlayNetworkHandler; +import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; +import net.ornithemc.osl.networking.impl.HandshakePayload; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; +import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; + +@Mixin(ClientPlayNetworkHandler.class) +public class ClientPlayNetworkHandlerMixin implements NetworkHandlerAccess { + + @Shadow @Final private Minecraft minecraft; + + /** + * Channels that the server is listening to. + */ + @Unique private Set serverChannels; + + @Inject( + method = "handleLogin", + at = @At( + value = "TAIL" + ) + ) + private void osl$networking$handleLogin(CallbackInfo ci) { + // send channel registration data as soon as login occurs + ClientPlayNetworkingImpl.sendNoCheck(HandshakePayload.CHANNEL, HandshakePayload.client()); + + ClientConnectionEvents.LOGIN.invoker().accept(minecraft); + } + + @Inject( + method = "onDisconnect", + at = @At( + value = "HEAD" + ) + ) + private void osl$networking$handleDisconnect(CallbackInfo ci) { + ClientConnectionEvents.DISCONNECT.invoker().accept(minecraft); + serverChannels = null; + } + + @Inject( + method = "handleCustomPayload", + cancellable = true, + at = @At( + value = "HEAD" + ) + ) + private void osl$networking$handleCustomPayload(CustomPayloadS2CPacket packet, CallbackInfo ci) { + if (ClientPlayNetworkingImpl.handlePacket(minecraft, (ClientPlayNetworkHandler)(Object)this, packet)) { + ci.cancel(); + } + } + + @Override + public boolean osl$networking$isPlayReady() { + return serverChannels != null; + } + + @Override + public boolean osl$networking$isPlayReady(NamespacedIdentifier channel) { + return serverChannels != null && serverChannels.contains(channel); + } + + @Override + public void osl$networking$registerChannels(Set channels) { + serverChannels = new LinkedHashSet<>(channels); + } +} diff --git a/libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java b/libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java new file mode 100644 index 00000000..06467881 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java @@ -0,0 +1,18 @@ +package net.ornithemc.osl.networking.impl.mixin.client; + +import org.spongepowered.asm.mixin.Mixin; + +import net.minecraft.client.Minecraft; +import net.minecraft.util.BlockableEventLoop; + +import net.ornithemc.osl.networking.impl.access.TaskRunnerAccess; + +@Mixin(Minecraft.class) +public abstract class MinecraftMixin implements BlockableEventLoop, TaskRunnerAccess { + + @Override + public boolean osl$networking$submit(Runnable task) { + this.submit(task); + return true; + } +} diff --git a/libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java b/libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java new file mode 100644 index 00000000..64f448dd --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java @@ -0,0 +1,63 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.At.Shift; +import org.spongepowered.asm.mixin.injection.Constant; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.ModifyConstant; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketBuffers; +import net.ornithemc.osl.networking.api.StringChannelIdentifierParser; +import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; + +@Mixin(CustomPayloadC2SPacket.class) +public class CustomPayloadC2SPacketMixin implements CustomPayloadPacketAccess { + + @Shadow private String channel; + @Shadow private PacketByteBuf data; + + @ModifyConstant( + method = "read", + constant = @Constant( + intValue = 20 + ) + ) + private int osl$networking$modifyMaxChannelLength(int maxLength) { + return StringChannelIdentifierParser.MAX_LENGTH; + } + + @Inject( + method = "m_9429910", + cancellable = true, + at = @At( + value = "INVOKE", + shift = Shift.AFTER, + target = "Lnet/minecraft/server/network/handler/ServerPlayPacketHandler;handleCustomPayload(Lnet/minecraft/network/packet/c2s/play/CustomPayloadC2SPacket;)V" + ) + ) + private void osl$networking$skipBufferRelease(CallbackInfo ci) { + // there's a call to ByteBuf.release() that we want to skip + // so that we can queue packet handling to the main thread + // Vanilla does this by throwing an exception but for the sake + // of version compat we cannot use the same approach + ci.cancel(); + } + + @Override + public NamespacedIdentifier osl$networking$getChannel() { + return StringChannelIdentifierParser.fromString(channel); + } + + @Override + public PacketBuffer osl$networking$getData() { + return PacketBuffers.wrapped(data.copy()); + } +} diff --git a/libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadS2CPacketMixin.java b/libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadS2CPacketMixin.java new file mode 100644 index 00000000..69736722 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadS2CPacketMixin.java @@ -0,0 +1,42 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.Constant; +import org.spongepowered.asm.mixin.injection.ModifyConstant; + +import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketBuffers; +import net.ornithemc.osl.networking.api.StringChannelIdentifierParser; +import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; + +@Mixin(CustomPayloadS2CPacket.class) +public class CustomPayloadS2CPacketMixin implements CustomPayloadPacketAccess { + + @Shadow private String channel; + @Shadow private PacketByteBuf data; + + @ModifyConstant( + method = "read", + constant = @Constant( + intValue = 20 + ) + ) + private int osl$networking$modifyMaxChannelLength(int maxLength) { + return StringChannelIdentifierParser.MAX_LENGTH; + } + + @Override + public NamespacedIdentifier osl$networking$getChannel() { + return StringChannelIdentifierParser.fromString(channel); + } + + @Override + public PacketBuffer osl$networking$getData() { + return PacketBuffers.wrapped(data.copy()); + } +} diff --git a/libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/MinecraftServerMixin.java b/libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/MinecraftServerMixin.java new file mode 100644 index 00000000..032c1691 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/MinecraftServerMixin.java @@ -0,0 +1,18 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.BlockableEventLoop; + +import net.ornithemc.osl.networking.impl.access.TaskRunnerAccess; + +@Mixin(MinecraftServer.class) +public abstract class MinecraftServerMixin implements BlockableEventLoop, TaskRunnerAccess { + + @Override + public boolean osl$networking$submit(Runnable task) { + this.submit(task); + return true; + } +} diff --git a/libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java b/libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java new file mode 100644 index 00000000..e88d1f5a --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java @@ -0,0 +1,40 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import java.util.List; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.network.Connection; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.PlayerManager; +import net.minecraft.server.entity.living.player.ServerPlayerEntity; + +import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; +import net.ornithemc.osl.networking.impl.access.PlayerManagerAccess; + +@Mixin(PlayerManager.class) +public class PlayerManagerMixin implements PlayerManagerAccess { + + @Shadow @Final private MinecraftServer server; + @Shadow @Final private List players; + + @Inject( + method = "onLogin", + at = @At( + value = "TAIL" + ) + ) + private void osl$networking$handleLogin(Connection connection, ServerPlayerEntity player, CallbackInfo ci) { + ServerConnectionEvents.LOGIN.invoker().accept(server, player); + } + + @Override + public List osl$networking$getAll() { + return players; + } +} diff --git a/libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java b/libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java new file mode 100644 index 00000000..ac66d440 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java @@ -0,0 +1,73 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import java.util.LinkedHashSet; +import java.util.Set; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.entity.living.player.ServerPlayerEntity; +import net.minecraft.server.network.handler.ServerPlayNetworkHandler; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; +import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; + +@Mixin(ServerPlayNetworkHandler.class) +public class ServerPlayNetworkHandlerMixin implements NetworkHandlerAccess { + + @Shadow @Final private MinecraftServer server; + @Shadow @Final private ServerPlayerEntity player; + + /** + * Channels that the client is listening to. + */ + @Unique private Set clientChannels; + + @Inject( + method = "onDisconnect", + at = @At( + value = "HEAD" + ) + ) + private void osl$networking$handleDisconnect(CallbackInfo ci) { + ServerConnectionEvents.DISCONNECT.invoker().accept(server, player); + clientChannels = null; + } + + @Inject( + method = "handleCustomPayload", + cancellable = true, + at = @At( + value = "HEAD" + ) + ) + private void osl$networking$handleCustomPayload(CustomPayloadC2SPacket packet, CallbackInfo ci) { + if (ServerPlayNetworkingImpl.handlePacket(server, (ServerPlayNetworkHandler)(Object)this, player, packet)) { + ci.cancel(); + } + } + + @Override + public boolean osl$networking$isPlayReady() { + return clientChannels != null; + } + + @Override + public boolean osl$networking$isPlayReady(NamespacedIdentifier channel) { + return clientChannels != null && clientChannels.contains(channel); + } + + @Override + public void osl$networking$registerChannels(Set channels) { + clientChannels = new LinkedHashSet<>(channels); + } +} diff --git a/libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/resources/osl.networking.mixins.json b/libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/resources/osl.networking.mixins.json new file mode 100644 index 00000000..f64bbc23 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/resources/osl.networking.mixins.json @@ -0,0 +1,22 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "net.ornithemc.osl.networking.impl.mixin", + "compatibilityLevel": "JAVA_8", + "mixins": [ + "common.CustomPayloadC2SPacketMixin", + "common.CustomPayloadS2CPacketMixin", + "common.MinecraftServerMixin", + "common.PlayerManagerMixin", + "common.ServerPlayNetworkHandlerMixin" + ], + "client": [ + "client.ClientPlayNetworkHandlerMixin", + "client.MinecraftMixin" + ], + "server": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/build.gradle b/libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/build.gradle new file mode 100644 index 00000000..f5d7d200 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/build.gradle @@ -0,0 +1,5 @@ +setUpModule(project, + 'entrypoints-mc13w16a-04192037-mc1.14.4', + 'lifecycle-events-mc19w04a-mc1.14.4', + 'networking-mc18w31a-mc1.14.4' +) diff --git a/libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/gradle.properties b/libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/gradle.properties new file mode 100644 index 00000000..2e7bb240 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/gradle.properties @@ -0,0 +1,7 @@ +environment = * +min_mc_version = 18w43a +max_mc_version = 1.14.4 +mc_version_range = >=1.14-alpha.18.43.a <=1.14.4 + +minecraft_version = 1.14.4 +feather_build = 2 diff --git a/libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/Networking.java new file mode 100644 index 00000000..431eefe5 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/Networking.java @@ -0,0 +1,56 @@ +package net.ornithemc.osl.networking.impl; + +import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; +import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; + +import net.ornithemc.osl.entrypoints.api.ModInitializer; +import net.ornithemc.osl.entrypoints.api.client.ClientModInitializer; +import net.ornithemc.osl.entrypoints.api.server.ServerModInitializer; +import net.ornithemc.osl.lifecycle.api.client.MinecraftClientEvents; +import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; +import net.ornithemc.osl.networking.api.IdentifierChannelIdentifierParser; +import net.ornithemc.osl.networking.api.PacketBuffers; +import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; +import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; +import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; +import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; + +public class Networking implements ModInitializer, ClientModInitializer, ServerModInitializer { + + @Override + public void init() { + MinecraftServerEvents.START.register(ServerPlayNetworkingImpl::setUp); + MinecraftServerEvents.STOP.register(ServerPlayNetworkingImpl::destroy); + ServerPlayNetworkingImpl.setUpPacketFactory((channel, data) -> + new CustomPayloadS2CPacket(IdentifierChannelIdentifierParser.toIdentifier(channel), PacketBuffers.unwrapped(data))); + ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { + // send channel registration data as a response to receiving client channel registration data + ServerPlayNetworkingImpl.sendNoCheck(player, HandshakePayload.CHANNEL, HandshakePayload.server()); + + ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); + ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); + + return true; + }); + } + + @Override + public void initClient() { + MinecraftClientEvents.START.register(ClientPlayNetworkingImpl::setUp); + MinecraftClientEvents.STOP.register(ClientPlayNetworkingImpl::destroy); + ClientPlayNetworkingImpl.setUpPacketFactory((channel, data) -> + new CustomPayloadC2SPacket(IdentifierChannelIdentifierParser.toIdentifier(channel), PacketBuffers.unwrapped(data))); + ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { + ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); + ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); + + return true; + }); + } + + @Override + public void initServer() { + // no-op + } +} diff --git a/libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java b/libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java new file mode 100644 index 00000000..ef5dbdfb --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java @@ -0,0 +1,85 @@ +package net.ornithemc.osl.networking.impl.mixin.client; + +import java.util.LinkedHashSet; +import java.util.Set; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.network.handler.ClientPlayNetworkHandler; +import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; +import net.ornithemc.osl.networking.impl.HandshakePayload; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; +import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; + +@Mixin(ClientPlayNetworkHandler.class) +public class ClientPlayNetworkHandlerMixin implements NetworkHandlerAccess { + + @Shadow @Final private Minecraft minecraft; + + /** + * Channels that the server is listening to. + */ + @Unique private Set serverChannels; + + @Inject( + method = "handleLogin", + at = @At( + value = "TAIL" + ) + ) + private void osl$networking$handleLogin(CallbackInfo ci) { + // send channel registration data as soon as login occurs + ClientPlayNetworkingImpl.sendNoCheck(HandshakePayload.CHANNEL, HandshakePayload.client()); + + ClientConnectionEvents.LOGIN.invoker().accept(minecraft); + } + + @Inject( + method = "onDisconnect", + at = @At( + value = "HEAD" + ) + ) + private void osl$networking$handleDisconnect(CallbackInfo ci) { + ClientConnectionEvents.DISCONNECT.invoker().accept(minecraft); + serverChannels = null; + } + + @Inject( + method = "handleCustomPayload", + cancellable = true, + at = @At( + value = "HEAD" + ) + ) + private void osl$networking$handleCustomPayload(CustomPayloadS2CPacket packet, CallbackInfo ci) { + if (ClientPlayNetworkingImpl.handlePacket(minecraft, (ClientPlayNetworkHandler)(Object)this, packet)) { + ci.cancel(); + } + } + + @Override + public boolean osl$networking$isPlayReady() { + return serverChannels != null; + } + + @Override + public boolean osl$networking$isPlayReady(NamespacedIdentifier channel) { + return serverChannels != null && serverChannels.contains(channel); + } + + @Override + public void osl$networking$registerChannels(Set channels) { + serverChannels = new LinkedHashSet<>(channels); + } +} diff --git a/libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java b/libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java new file mode 100644 index 00000000..2749c72d --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java @@ -0,0 +1,22 @@ +package net.ornithemc.osl.networking.impl.mixin.client; + +import org.spongepowered.asm.mixin.Mixin; + +import net.minecraft.client.Minecraft; +import net.minecraft.util.BlockableEventLoop; + +import net.ornithemc.osl.networking.impl.access.TaskRunnerAccess; + +@Mixin(Minecraft.class) +public abstract class MinecraftMixin extends BlockableEventLoop implements TaskRunnerAccess { + + private MinecraftMixin(String name) { + super(name); + } + + @Override + public boolean osl$networking$submit(Runnable task) { + this.execute(task); + return true; + } +} diff --git a/libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java b/libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java new file mode 100644 index 00000000..7853cd80 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java @@ -0,0 +1,52 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.At.Shift; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; +import net.minecraft.resource.Identifier; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.api.IdentifierChannelIdentifierParser; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketBuffers; +import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; + +@Mixin(CustomPayloadC2SPacket.class) +public class CustomPayloadC2SPacketMixin implements CustomPayloadPacketAccess { + + @Shadow private Identifier channel; + @Shadow private PacketByteBuf data; + + @Inject( + method = "m_9429910", + cancellable = true, + at = @At( + value = "INVOKE", + shift = Shift.AFTER, + target = "Lnet/minecraft/server/network/handler/ServerPlayPacketHandler;handleCustomPayload(Lnet/minecraft/network/packet/c2s/play/CustomPayloadC2SPacket;)V" + ) + ) + private void osl$networking$skipBufferRelease(CallbackInfo ci) { + // there's a call to ByteBuf.release() that we want to skip + // so that we can queue packet handling to the main thread + // Vanilla does this by throwing an exception but for the sake + // of version compat we cannot use the same approach + ci.cancel(); + } + + @Override + public NamespacedIdentifier osl$networking$getChannel() { + return IdentifierChannelIdentifierParser.fromIdentifier(channel); + } + + @Override + public PacketBuffer osl$networking$getData() { + return PacketBuffers.wrapped(data.copy()); + } +} diff --git a/libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadS2CPacketMixin.java b/libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadS2CPacketMixin.java new file mode 100644 index 00000000..97912aa8 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadS2CPacketMixin.java @@ -0,0 +1,31 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import net.minecraft.network.PacketByteBuf; +import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; +import net.minecraft.resource.Identifier; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.api.IdentifierChannelIdentifierParser; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketBuffers; +import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; + +@Mixin(CustomPayloadS2CPacket.class) +public class CustomPayloadS2CPacketMixin implements CustomPayloadPacketAccess { + + @Shadow private Identifier channel; + @Shadow private PacketByteBuf data; + + @Override + public NamespacedIdentifier osl$networking$getChannel() { + return IdentifierChannelIdentifierParser.fromIdentifier(channel); + } + + @Override + public PacketBuffer osl$networking$getData() { + return PacketBuffers.wrapped(data.copy()); + } +} diff --git a/libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/MinecraftServerMixin.java b/libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/MinecraftServerMixin.java new file mode 100644 index 00000000..eb2bc2be --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/MinecraftServerMixin.java @@ -0,0 +1,22 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.util.BlockableEventLoop; + +import net.ornithemc.osl.networking.impl.access.TaskRunnerAccess; + +@Mixin(MinecraftServer.class) +public abstract class MinecraftServerMixin extends BlockableEventLoop implements TaskRunnerAccess { + + private MinecraftServerMixin(String name) { + super(name); + } + + @Override + public boolean osl$networking$submit(Runnable task) { + this.execute(task); + return true; + } +} diff --git a/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java b/libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java similarity index 100% rename from libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java rename to libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PlayerManagerMixin.java diff --git a/libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java b/libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java new file mode 100644 index 00000000..ac66d440 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java @@ -0,0 +1,73 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import java.util.LinkedHashSet; +import java.util.Set; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.entity.living.player.ServerPlayerEntity; +import net.minecraft.server.network.handler.ServerPlayNetworkHandler; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; +import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; + +@Mixin(ServerPlayNetworkHandler.class) +public class ServerPlayNetworkHandlerMixin implements NetworkHandlerAccess { + + @Shadow @Final private MinecraftServer server; + @Shadow @Final private ServerPlayerEntity player; + + /** + * Channels that the client is listening to. + */ + @Unique private Set clientChannels; + + @Inject( + method = "onDisconnect", + at = @At( + value = "HEAD" + ) + ) + private void osl$networking$handleDisconnect(CallbackInfo ci) { + ServerConnectionEvents.DISCONNECT.invoker().accept(server, player); + clientChannels = null; + } + + @Inject( + method = "handleCustomPayload", + cancellable = true, + at = @At( + value = "HEAD" + ) + ) + private void osl$networking$handleCustomPayload(CustomPayloadC2SPacket packet, CallbackInfo ci) { + if (ServerPlayNetworkingImpl.handlePacket(server, (ServerPlayNetworkHandler)(Object)this, player, packet)) { + ci.cancel(); + } + } + + @Override + public boolean osl$networking$isPlayReady() { + return clientChannels != null; + } + + @Override + public boolean osl$networking$isPlayReady(NamespacedIdentifier channel) { + return clientChannels != null && clientChannels.contains(channel); + } + + @Override + public void osl$networking$registerChannels(Set channels) { + clientChannels = new LinkedHashSet<>(channels); + } +} diff --git a/libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/resources/osl.networking.mixins.json b/libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/resources/osl.networking.mixins.json new file mode 100644 index 00000000..f64bbc23 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/resources/osl.networking.mixins.json @@ -0,0 +1,22 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "net.ornithemc.osl.networking.impl.mixin", + "compatibilityLevel": "JAVA_8", + "mixins": [ + "common.CustomPayloadC2SPacketMixin", + "common.CustomPayloadS2CPacketMixin", + "common.MinecraftServerMixin", + "common.PlayerManagerMixin", + "common.ServerPlayNetworkHandlerMixin" + ], + "client": [ + "client.ClientPlayNetworkHandlerMixin", + "client.MinecraftMixin" + ], + "server": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/build.gradle b/libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/build.gradle new file mode 100644 index 00000000..47646e3c --- /dev/null +++ b/libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/build.gradle @@ -0,0 +1,5 @@ +setUpModule(project, + 'entrypoints-mcin-20091223-1459-mc1.5.2', + 'lifecycle-events-mcinf-20100630-1340-mca1.2.6', + 'networking-mca1.0.16-mca1.2.6' +) diff --git a/libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/gradle.properties b/libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/gradle.properties new file mode 100644 index 00000000..94398336 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/gradle.properties @@ -0,0 +1,10 @@ +environment = client +min_mc_version = a1.0.16 +max_mc_version = a1.2.6 +mc_version_range = >=1.0.0-alpha.0.16 <=1.0.0-alpha.2.6 + +minecraft_version = a1.2.6 +feather_build = 1 +raven_build = 2 +sparrow_build = 2 +nests_build = 6 diff --git a/libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java b/libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java new file mode 100644 index 00000000..eb557624 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java @@ -0,0 +1,74 @@ +package net.ornithemc.osl.networking.impl; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import net.minecraft.network.PacketHandler; +import net.minecraft.network.packet.Packet; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.api.StringChannelIdentifierParser; +import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; +import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; + +public class CustomPayloadPacket extends Packet implements CustomPayloadPacketAccess { + + private String channel; + private int size; + private byte[] data; + + public CustomPayloadPacket() { + } + + public CustomPayloadPacket(NamespacedIdentifier channel, byte[] data) { + this.channel = StringChannelIdentifierParser.toString(channel); + this.data = data; + this.size = data.length; + + if (this.data != null && this.size > Short.MAX_VALUE) { + throw new IllegalArgumentException("Payload may not be larger than 32k"); + } + } + + @Override + public void read(DataInputStream input) throws IOException { + this.channel = input.readUTF(); + this.size = input.readShort(); + if (this.size > 0 && this.size < Short.MAX_VALUE) { + this.data = new byte[this.size]; + input.readFully(this.data); + } + } + + @Override + public void write(DataOutputStream output) throws IOException { + output.writeUTF(this.channel); + output.writeShort(this.size); + if (this.data != null) { + output.write(this.data); + } + } + + @Override + public void handle(PacketHandler handler) { + if (handler instanceof INetworkHandler) { + ((INetworkHandler)handler).osl$networking$handleCustomPayload(this); + } + } + + @Override + public int getSize() { + return 2 + this.channel.length() * 2 + 2 + this.data.length; + } + + @Override + public NamespacedIdentifier osl$networking$getChannel() { + return StringChannelIdentifierParser.fromString(this.channel); + } + + @Override + public byte[] osl$networking$getData() { + return this.data; + } +} diff --git a/libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/Networking.java new file mode 100644 index 00000000..009d2d35 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/Networking.java @@ -0,0 +1,38 @@ +package net.ornithemc.osl.networking.impl; + +import net.ornithemc.osl.entrypoints.api.ModInitializer; +import net.ornithemc.osl.entrypoints.api.client.ClientModInitializer; +import net.ornithemc.osl.entrypoints.api.server.ServerModInitializer; +import net.ornithemc.osl.lifecycle.api.client.MinecraftClientEvents; +import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; +import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; + +public class Networking implements ModInitializer, ClientModInitializer, ServerModInitializer { + + @Override + public void init() { + // no-op + } + + @Override + public void initClient() { + MinecraftClientEvents.START.register(ClientPlayNetworkingImpl::setUp); + MinecraftClientEvents.STOP.register(ClientPlayNetworkingImpl::destroy); + ClientPlayNetworkingImpl.setUpPacketFactory(CustomPayloadPacket::new); + ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { + // send channel registration data as a response to receiving server channel registration data + ClientPlayNetworkingImpl.sendNoCheck(HandshakePayload.CHANNEL, HandshakePayload.client()); + + ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); + ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); + + return true; + }); + } + + @Override + public void initServer() { + // no-op + } +} diff --git a/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java b/libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java similarity index 55% rename from libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java rename to libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java index 420bdcda..283c296d 100644 --- a/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java +++ b/libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java @@ -1,17 +1,9 @@ package net.ornithemc.osl.networking.impl.interfaces.mixin; -import java.util.Set; - import net.ornithemc.osl.networking.impl.CustomPayloadPacket; public interface INetworkHandler { boolean osl$networking$handleCustomPayload(CustomPayloadPacket packet); - boolean osl$networking$isPlayReady(); - - void osl$networking$registerChannels(Set channels); - - boolean osl$networking$isRegisteredChannel(String channel); - } diff --git a/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java b/libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java similarity index 61% rename from libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java rename to libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java index 66b4df3d..2f22e265 100644 --- a/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java +++ b/libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java @@ -3,7 +3,6 @@ import java.util.LinkedHashSet; import java.util.Set; -import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -13,21 +12,26 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.network.handler.ClientNetworkHandler; +import net.minecraft.client.world.MultiplayerWorld; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; import net.ornithemc.osl.networking.impl.CustomPayloadPacket; +import net.ornithemc.osl.networking.impl.HandshakePayload; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; @Mixin(ClientNetworkHandler.class) -public class ClientNetworkHandlerMixin implements INetworkHandler { +public class ClientNetworkHandlerMixin implements NetworkHandlerAccess, INetworkHandler { - @Shadow @Final private Minecraft minecraft; + @Shadow private Minecraft minecraft; + @Shadow private MultiplayerWorld world; /** * Channels that the server is listening to. */ - @Unique private Set serverChannels; + @Unique private Set serverChannels; @Inject( method = "handleLogin", @@ -36,6 +40,9 @@ public class ClientNetworkHandlerMixin implements INetworkHandler { ) ) private void osl$networking$handleLogin(CallbackInfo ci) { + // send channel registration data as soon as login occurs + ClientPlayNetworkingImpl.sendNoCheck(HandshakePayload.CHANNEL, HandshakePayload.client()); + ClientConnectionEvents.LOGIN.invoker().accept(minecraft); } @@ -51,8 +58,8 @@ public class ClientNetworkHandlerMixin implements INetworkHandler { } @Override - public boolean osl$networking$handleCustomPayload(CustomPayloadPacket packet) { - return ClientPlayNetworkingImpl.handle(minecraft, (ClientNetworkHandler)(Object)this, packet); + public boolean osl$networking$canRunOffMainThread() { + return minecraft != null && minecraft.world != null && minecraft.player != null && world != null; } @Override @@ -61,12 +68,17 @@ public class ClientNetworkHandlerMixin implements INetworkHandler { } @Override - public void osl$networking$registerChannels(Set channels) { + public boolean osl$networking$isPlayReady(NamespacedIdentifier channel) { + return serverChannels != null && serverChannels.contains(channel); + } + + @Override + public void osl$networking$registerChannels(Set channels) { serverChannels = new LinkedHashSet<>(channels); } @Override - public boolean osl$networking$isRegisteredChannel(String channel) { - return serverChannels != null && serverChannels.contains(channel); + public boolean osl$networking$handleCustomPayload(CustomPayloadPacket packet) { + return ClientPlayNetworkingImpl.handlePacket(minecraft, (ClientNetworkHandler)(Object)this, packet); } } diff --git a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/HandshakePacketMixin.java b/libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/HandshakePacketMixin.java similarity index 100% rename from libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/HandshakePacketMixin.java rename to libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/HandshakePacketMixin.java diff --git a/libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/LocalClientPlayerEntityMixin.java b/libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/LocalClientPlayerEntityMixin.java new file mode 100644 index 00000000..4315e91a --- /dev/null +++ b/libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/LocalClientPlayerEntityMixin.java @@ -0,0 +1,21 @@ +package net.ornithemc.osl.networking.impl.mixin.client; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; + +import net.minecraft.client.entity.mob.player.LocalClientPlayerEntity; +import net.minecraft.client.network.handler.ClientNetworkHandler; + +import net.ornithemc.osl.networking.impl.access.LocalClientPlayerAccess; + +@Mixin(LocalClientPlayerEntity.class) +public class LocalClientPlayerEntityMixin implements LocalClientPlayerAccess { + + @Shadow + private ClientNetworkHandler networkHandler; + + @Override + public ClientNetworkHandler osl$networking$getNetworkHandler() { + return this.networkHandler; + } +} diff --git a/libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java b/libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java new file mode 100644 index 00000000..85baea9b --- /dev/null +++ b/libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java @@ -0,0 +1,44 @@ +package net.ornithemc.osl.networking.impl.mixin.client; + +import java.util.ArrayDeque; +import java.util.Queue; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.client.Minecraft; + +import net.ornithemc.osl.networking.impl.access.TaskRunnerAccess; + +@Mixin(Minecraft.class) +public class MinecraftMixin implements TaskRunnerAccess { + + @Unique + private Queue tasks = new ArrayDeque<>(); + + @Inject( + method = "tick", + at = @At( + value = "HEAD" + ) + ) + private void osl$networking$runTasks(CallbackInfo ci) { + synchronized (this.tasks) { + while (!this.tasks.isEmpty()) { + this.tasks.poll().run(); + } + } + } + + @Override + public boolean osl$networking$submit(Runnable task) { + synchronized (this.tasks) { + this.tasks.add(task); + } + + return true; + } +} diff --git a/libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ConnectionMixin.java b/libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ConnectionMixin.java new file mode 100644 index 00000000..8cbf1eeb --- /dev/null +++ b/libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ConnectionMixin.java @@ -0,0 +1,33 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import net.minecraft.network.Connection; +import net.minecraft.network.PacketHandler; +import net.minecraft.network.packet.Packet; + +import net.ornithemc.osl.networking.impl.Connections; + +@Mixin(Connection.class) +public class ConnectionMixin { + + @Shadow private PacketHandler listener; + + @Inject( + method = "read", + cancellable = true, + at = @At( + value = "INVOKE", + target = "Ljava/util/List;add(Ljava/lang/Object;)Z" + ) + ) + private void osl$networking$handlePacketsAsync(Packet packet, CallbackInfoReturnable cir) { + if (Connections.checkAsyncHandling(packet, listener)) { + cir.setReturnValue(true); + } + } +} diff --git a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java b/libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java similarity index 100% rename from libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java rename to libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java diff --git a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/resources/osl.networking.mixins.json b/libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/resources/osl.networking.mixins.json similarity index 77% rename from libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/resources/osl.networking.mixins.json rename to libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/resources/osl.networking.mixins.json index 64d62d1d..ded2c522 100644 --- a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/resources/osl.networking.mixins.json +++ b/libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/resources/osl.networking.mixins.json @@ -4,12 +4,14 @@ "package": "net.ornithemc.osl.networking.impl.mixin", "compatibilityLevel": "JAVA_8", "mixins": [ + "common.ConnectionMixin", "common.PacketAccessor" ], "client": [ "client.ClientNetworkHandlerMixin", "client.HandshakePacketMixin", - "client.LocalClientPlayerEntityAccessor" + "client.LocalClientPlayerEntityMixin", + "client.MinecraftMixin" ], "server": [ ], diff --git a/libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/build.gradle b/libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/build.gradle new file mode 100644 index 00000000..2e14f6bb --- /dev/null +++ b/libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/build.gradle @@ -0,0 +1,5 @@ +setUpModule(project, + 'entrypoints-mcin-20091223-1459-mc1.5.2', + 'lifecycle-events-mcb1.4-1507-mcb1.7.3', + 'networking-mcb1.0-mc13w39b' +) diff --git a/libraries/networking/networking-mcb1.0-mcb1.4_01/gradle.properties b/libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/gradle.properties similarity index 100% rename from libraries/networking/networking-mcb1.0-mcb1.4_01/gradle.properties rename to libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/gradle.properties diff --git a/libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java b/libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java new file mode 100644 index 00000000..eb557624 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java @@ -0,0 +1,74 @@ +package net.ornithemc.osl.networking.impl; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import net.minecraft.network.PacketHandler; +import net.minecraft.network.packet.Packet; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.api.StringChannelIdentifierParser; +import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; +import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; + +public class CustomPayloadPacket extends Packet implements CustomPayloadPacketAccess { + + private String channel; + private int size; + private byte[] data; + + public CustomPayloadPacket() { + } + + public CustomPayloadPacket(NamespacedIdentifier channel, byte[] data) { + this.channel = StringChannelIdentifierParser.toString(channel); + this.data = data; + this.size = data.length; + + if (this.data != null && this.size > Short.MAX_VALUE) { + throw new IllegalArgumentException("Payload may not be larger than 32k"); + } + } + + @Override + public void read(DataInputStream input) throws IOException { + this.channel = input.readUTF(); + this.size = input.readShort(); + if (this.size > 0 && this.size < Short.MAX_VALUE) { + this.data = new byte[this.size]; + input.readFully(this.data); + } + } + + @Override + public void write(DataOutputStream output) throws IOException { + output.writeUTF(this.channel); + output.writeShort(this.size); + if (this.data != null) { + output.write(this.data); + } + } + + @Override + public void handle(PacketHandler handler) { + if (handler instanceof INetworkHandler) { + ((INetworkHandler)handler).osl$networking$handleCustomPayload(this); + } + } + + @Override + public int getSize() { + return 2 + this.channel.length() * 2 + 2 + this.data.length; + } + + @Override + public NamespacedIdentifier osl$networking$getChannel() { + return StringChannelIdentifierParser.fromString(this.channel); + } + + @Override + public byte[] osl$networking$getData() { + return this.data; + } +} diff --git a/libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/Networking.java new file mode 100644 index 00000000..9c28c416 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/Networking.java @@ -0,0 +1,49 @@ +package net.ornithemc.osl.networking.impl; + +import net.ornithemc.osl.entrypoints.api.ModInitializer; +import net.ornithemc.osl.entrypoints.api.client.ClientModInitializer; +import net.ornithemc.osl.entrypoints.api.server.ServerModInitializer; +import net.ornithemc.osl.lifecycle.api.client.MinecraftClientEvents; +import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; +import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; +import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; +import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; +import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; + +public class Networking implements ModInitializer, ClientModInitializer, ServerModInitializer { + + @Override + public void init() { + // no-op + } + + @Override + public void initClient() { + MinecraftClientEvents.START.register(ClientPlayNetworkingImpl::setUp); + MinecraftClientEvents.STOP.register(ClientPlayNetworkingImpl::destroy); + ClientPlayNetworkingImpl.setUpPacketFactory(CustomPayloadPacket::new); + ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { + // send channel registration data as a response to receiving server channel registration data + ClientPlayNetworkingImpl.sendNoCheck(HandshakePayload.CHANNEL, HandshakePayload.client()); + + ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); + ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); + + return true; + }); + } + + @Override + public void initServer() { + MinecraftServerEvents.START.register(ServerPlayNetworkingImpl::setUp); + MinecraftServerEvents.STOP.register(ServerPlayNetworkingImpl::destroy); + ServerPlayNetworkingImpl.setUpPacketFactory(CustomPayloadPacket::new); + ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { + ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); + ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); + + return true; + }); + } +} diff --git a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java b/libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java similarity index 55% rename from libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java rename to libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java index 420bdcda..283c296d 100644 --- a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java +++ b/libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java @@ -1,17 +1,9 @@ package net.ornithemc.osl.networking.impl.interfaces.mixin; -import java.util.Set; - import net.ornithemc.osl.networking.impl.CustomPayloadPacket; public interface INetworkHandler { boolean osl$networking$handleCustomPayload(CustomPayloadPacket packet); - boolean osl$networking$isPlayReady(); - - void osl$networking$registerChannels(Set channels); - - boolean osl$networking$isRegisteredChannel(String channel); - } diff --git a/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java b/libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java similarity index 66% rename from libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java rename to libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java index 66b4df3d..c48e552f 100644 --- a/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java +++ b/libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java @@ -3,7 +3,6 @@ import java.util.LinkedHashSet; import java.util.Set; -import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -13,21 +12,25 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.network.handler.ClientNetworkHandler; +import net.minecraft.client.world.MultiplayerWorld; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; import net.ornithemc.osl.networking.impl.CustomPayloadPacket; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; @Mixin(ClientNetworkHandler.class) -public class ClientNetworkHandlerMixin implements INetworkHandler { +public class ClientNetworkHandlerMixin implements NetworkHandlerAccess, INetworkHandler { - @Shadow @Final private Minecraft minecraft; + @Shadow private Minecraft minecraft; + @Shadow private MultiplayerWorld world; /** * Channels that the server is listening to. */ - @Unique private Set serverChannels; + @Unique private Set serverChannels; @Inject( method = "handleLogin", @@ -51,8 +54,8 @@ public class ClientNetworkHandlerMixin implements INetworkHandler { } @Override - public boolean osl$networking$handleCustomPayload(CustomPayloadPacket packet) { - return ClientPlayNetworkingImpl.handle(minecraft, (ClientNetworkHandler)(Object)this, packet); + public boolean osl$networking$canRunOffMainThread() { + return minecraft != null && minecraft.world != null && minecraft.player != null && world != null; } @Override @@ -61,12 +64,17 @@ public class ClientNetworkHandlerMixin implements INetworkHandler { } @Override - public void osl$networking$registerChannels(Set channels) { + public boolean osl$networking$isPlayReady(NamespacedIdentifier channel) { + return serverChannels != null && serverChannels.contains(channel); + } + + @Override + public void osl$networking$registerChannels(Set channels) { serverChannels = new LinkedHashSet<>(channels); } @Override - public boolean osl$networking$isRegisteredChannel(String channel) { - return serverChannels != null && serverChannels.contains(channel); + public boolean osl$networking$handleCustomPayload(CustomPayloadPacket packet) { + return ClientPlayNetworkingImpl.handlePacket(minecraft, (ClientNetworkHandler)(Object)this, packet); } } diff --git a/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/HandshakePacketMixin.java b/libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/HandshakePacketMixin.java similarity index 100% rename from libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/HandshakePacketMixin.java rename to libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/HandshakePacketMixin.java diff --git a/libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java b/libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java new file mode 100644 index 00000000..85baea9b --- /dev/null +++ b/libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java @@ -0,0 +1,44 @@ +package net.ornithemc.osl.networking.impl.mixin.client; + +import java.util.ArrayDeque; +import java.util.Queue; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.client.Minecraft; + +import net.ornithemc.osl.networking.impl.access.TaskRunnerAccess; + +@Mixin(Minecraft.class) +public class MinecraftMixin implements TaskRunnerAccess { + + @Unique + private Queue tasks = new ArrayDeque<>(); + + @Inject( + method = "tick", + at = @At( + value = "HEAD" + ) + ) + private void osl$networking$runTasks(CallbackInfo ci) { + synchronized (this.tasks) { + while (!this.tasks.isEmpty()) { + this.tasks.poll().run(); + } + } + } + + @Override + public boolean osl$networking$submit(Runnable task) { + synchronized (this.tasks) { + this.tasks.add(task); + } + + return true; + } +} diff --git a/libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ConnectionMixin.java b/libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ConnectionMixin.java new file mode 100644 index 00000000..8cbf1eeb --- /dev/null +++ b/libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ConnectionMixin.java @@ -0,0 +1,33 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import net.minecraft.network.Connection; +import net.minecraft.network.PacketHandler; +import net.minecraft.network.packet.Packet; + +import net.ornithemc.osl.networking.impl.Connections; + +@Mixin(Connection.class) +public class ConnectionMixin { + + @Shadow private PacketHandler listener; + + @Inject( + method = "read", + cancellable = true, + at = @At( + value = "INVOKE", + target = "Ljava/util/List;add(Ljava/lang/Object;)Z" + ) + ) + private void osl$networking$handlePacketsAsync(Packet packet, CallbackInfoReturnable cir) { + if (Connections.checkAsyncHandling(packet, listener)) { + cir.setReturnValue(true); + } + } +} diff --git a/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java b/libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java similarity index 100% rename from libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java rename to libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java diff --git a/libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/MinecraftServerMixin.java b/libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/MinecraftServerMixin.java new file mode 100644 index 00000000..5cdbf6c6 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/MinecraftServerMixin.java @@ -0,0 +1,48 @@ +package net.ornithemc.osl.networking.impl.mixin.server; + +import java.util.ArrayDeque; +import java.util.Queue; + +import org.objectweb.asm.Opcodes; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.server.MinecraftServer; + +import net.ornithemc.osl.networking.impl.access.TaskRunnerAccess; + +@Mixin(MinecraftServer.class) +public class MinecraftServerMixin implements TaskRunnerAccess { + + @Unique + private Queue tasks = new ArrayDeque<>(); + + @Inject( + method = "tick", + at = @At( + value = "FIELD", + opcode = Opcodes.PUTFIELD, + target = "Lnet/minecraft/server/MinecraftServer;ticks:I" + ) + ) + private void osl$networking$runTasks(CallbackInfo ci) { + synchronized (this.tasks) { + while (!this.tasks.isEmpty()) { + this.tasks.poll().run(); + } + } + } + + @Override + public boolean osl$networking$submit(Runnable task) { + synchronized (this.tasks) { + this.tasks.add(task); + } + + return true; + } +} diff --git a/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerLoginNetworkHandlerMixin.java b/libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerLoginNetworkHandlerMixin.java similarity index 94% rename from libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerLoginNetworkHandlerMixin.java rename to libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerLoginNetworkHandlerMixin.java index d57902df..4227d62e 100644 --- a/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerLoginNetworkHandlerMixin.java +++ b/libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerLoginNetworkHandlerMixin.java @@ -52,7 +52,7 @@ public class ServerLoginNetworkHandlerMixin { if (player != null) { if (ornithe) { // send channel registration data as soon as login occurs - ServerPlayNetworkingImpl.doSend(player, HandshakePayload.CHANNEL, HandshakePayload.server()); + ServerPlayNetworkingImpl.sendNoCheck(player, HandshakePayload.CHANNEL, HandshakePayload.server()); } ServerConnectionEvents.LOGIN.invoker().accept(server, player); diff --git a/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java b/libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java similarity index 68% rename from libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java rename to libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java index 11335ca1..381c0697 100644 --- a/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java +++ b/libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java @@ -3,7 +3,6 @@ import java.util.LinkedHashSet; import java.util.Set; -import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -15,21 +14,23 @@ import net.minecraft.server.entity.mob.player.ServerPlayerEntity; import net.minecraft.server.network.handler.ServerPlayNetworkHandler; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; import net.ornithemc.osl.networking.impl.CustomPayloadPacket; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; @Mixin(ServerPlayNetworkHandler.class) -public class ServerPlayNetworkHandlerMixin implements INetworkHandler { +public class ServerPlayNetworkHandlerMixin implements NetworkHandlerAccess, INetworkHandler { - @Shadow @Final private MinecraftServer server; - @Shadow @Final private ServerPlayerEntity player; + @Shadow private MinecraftServer server; + @Shadow private ServerPlayerEntity player; /** * Channels that the client is listening to. */ - @Unique private Set clientChannels; + @Unique private Set clientChannels; @Inject( method = "onDisconnect", @@ -43,8 +44,8 @@ public class ServerPlayNetworkHandlerMixin implements INetworkHandler { } @Override - public boolean osl$networking$handleCustomPayload(CustomPayloadPacket packet) { - return ServerPlayNetworkingImpl.handle(server, (ServerPlayNetworkHandler)(Object)this, player, packet); + public boolean osl$networking$canRunOffMainThread() { + return true; } @Override @@ -53,12 +54,17 @@ public class ServerPlayNetworkHandlerMixin implements INetworkHandler { } @Override - public void osl$networking$registerChannels(Set channels) { + public boolean osl$networking$isPlayReady(NamespacedIdentifier channel) { + return clientChannels != null && clientChannels.contains(channel); + } + + @Override + public void osl$networking$registerChannels(Set channels) { clientChannels = new LinkedHashSet<>(channels); } @Override - public boolean osl$networking$isRegisteredChannel(String channel) { - return clientChannels != null && clientChannels.contains(channel); + public boolean osl$networking$handleCustomPayload(CustomPayloadPacket packet) { + return ServerPlayNetworkingImpl.handlePacket(server, (ServerPlayNetworkHandler)(Object)this, player, packet); } } diff --git a/libraries/networking/networking-mcb1.5-mc11w48a/src/main/resources/osl.networking.mixins.json b/libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/resources/osl.networking.mixins.json similarity index 75% rename from libraries/networking/networking-mcb1.5-mc11w48a/src/main/resources/osl.networking.mixins.json rename to libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/resources/osl.networking.mixins.json index e2526e75..71939fcc 100644 --- a/libraries/networking/networking-mcb1.5-mc11w48a/src/main/resources/osl.networking.mixins.json +++ b/libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/resources/osl.networking.mixins.json @@ -4,13 +4,16 @@ "package": "net.ornithemc.osl.networking.impl.mixin", "compatibilityLevel": "JAVA_8", "mixins": [ + "common.ConnectionMixin", "common.PacketAccessor" ], "client": [ "client.ClientNetworkHandlerMixin", - "client.HandshakePacketMixin" + "client.HandshakePacketMixin", + "client.MinecraftMixin" ], "server": [ + "server.MinecraftServerMixin", "server.ServerLoginNetworkHandlerMixin", "server.ServerPlayNetworkHandlerMixin" ], diff --git a/libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/build.gradle b/libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/build.gradle new file mode 100644 index 00000000..1eb75d01 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/build.gradle @@ -0,0 +1,5 @@ +setUpModule(project, + 'entrypoints-mcin-20091223-1459-mc1.5.2', + 'lifecycle-events-mcb1.8-pre1-201109081459-mc11w50a', + 'networking-mcb1.0-mc13w39b' +) diff --git a/libraries/networking/networking-mcb1.5-mc11w48a/gradle.properties b/libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/gradle.properties similarity index 100% rename from libraries/networking/networking-mcb1.5-mc11w48a/gradle.properties rename to libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/gradle.properties diff --git a/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java b/libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java similarity index 57% rename from libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java rename to libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java index 5d859b11..fd63fa5a 100644 --- a/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java +++ b/libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java @@ -8,26 +8,27 @@ import net.minecraft.network.PacketHandler; import net.minecraft.network.packet.Packet; -import net.ornithemc.osl.networking.api.Channels; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.api.StringChannelIdentifierParser; +import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; -public class CustomPayloadPacket extends Packet { +public class CustomPayloadPacket extends Packet implements CustomPayloadPacketAccess { - public String channel; - public int size; - public byte[] data; + private String channel; + private int size; + private byte[] data; public CustomPayloadPacket() { } - public CustomPayloadPacket(String channel, byte[] data) { - this.channel = channel; + public CustomPayloadPacket(NamespacedIdentifier channel, byte[] data) { + this.channel = StringChannelIdentifierParser.toString(channel); this.data = data; - if (data != null) { - this.size = data.length; - if (this.size > Short.MAX_VALUE) { - throw new IllegalArgumentException("Payload may not be larger than 32k"); - } + this.size = data.length; + + if (this.data != null && this.size > Short.MAX_VALUE) { + throw new IllegalArgumentException("Payload may not be larger than 32k"); } } @@ -38,7 +39,7 @@ public CustomPayloadPacket(String channel, byte[] data) { @Override public void read(DataInputStream input) { try { - this.channel = readString(input, Channels.MAX_LENGTH); + this.channel = readString(input, StringChannelIdentifierParser.MAX_LENGTH); this.size = input.readShort(); if (this.size > 0 && this.size < Short.MAX_VALUE) { this.data = new byte[this.size]; @@ -71,6 +72,16 @@ public void handle(PacketHandler handler) { @Override public int getSize() { - return 2 + this.channel.length() * 2 + 2 + this.size; + return 2 + this.channel.length() * 2 + 2 + this.data.length; + } + + @Override + public NamespacedIdentifier osl$networking$getChannel() { + return StringChannelIdentifierParser.fromString(this.channel); + } + + @Override + public byte[] osl$networking$getData() { + return this.data; } } diff --git a/libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java new file mode 100644 index 00000000..9c28c416 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java @@ -0,0 +1,49 @@ +package net.ornithemc.osl.networking.impl; + +import net.ornithemc.osl.entrypoints.api.ModInitializer; +import net.ornithemc.osl.entrypoints.api.client.ClientModInitializer; +import net.ornithemc.osl.entrypoints.api.server.ServerModInitializer; +import net.ornithemc.osl.lifecycle.api.client.MinecraftClientEvents; +import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; +import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; +import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; +import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; +import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; + +public class Networking implements ModInitializer, ClientModInitializer, ServerModInitializer { + + @Override + public void init() { + // no-op + } + + @Override + public void initClient() { + MinecraftClientEvents.START.register(ClientPlayNetworkingImpl::setUp); + MinecraftClientEvents.STOP.register(ClientPlayNetworkingImpl::destroy); + ClientPlayNetworkingImpl.setUpPacketFactory(CustomPayloadPacket::new); + ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { + // send channel registration data as a response to receiving server channel registration data + ClientPlayNetworkingImpl.sendNoCheck(HandshakePayload.CHANNEL, HandshakePayload.client()); + + ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); + ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); + + return true; + }); + } + + @Override + public void initServer() { + MinecraftServerEvents.START.register(ServerPlayNetworkingImpl::setUp); + MinecraftServerEvents.STOP.register(ServerPlayNetworkingImpl::destroy); + ServerPlayNetworkingImpl.setUpPacketFactory(CustomPayloadPacket::new); + ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { + ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); + ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); + + return true; + }); + } +} diff --git a/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java b/libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java similarity index 55% rename from libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java rename to libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java index 420bdcda..283c296d 100644 --- a/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java +++ b/libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java @@ -1,17 +1,9 @@ package net.ornithemc.osl.networking.impl.interfaces.mixin; -import java.util.Set; - import net.ornithemc.osl.networking.impl.CustomPayloadPacket; public interface INetworkHandler { boolean osl$networking$handleCustomPayload(CustomPayloadPacket packet); - boolean osl$networking$isPlayReady(); - - void osl$networking$registerChannels(Set channels); - - boolean osl$networking$isRegisteredChannel(String channel); - } diff --git a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java b/libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java similarity index 66% rename from libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java rename to libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java index 66b4df3d..c48e552f 100644 --- a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java +++ b/libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientNetworkHandlerMixin.java @@ -3,7 +3,6 @@ import java.util.LinkedHashSet; import java.util.Set; -import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -13,21 +12,25 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.network.handler.ClientNetworkHandler; +import net.minecraft.client.world.MultiplayerWorld; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; import net.ornithemc.osl.networking.impl.CustomPayloadPacket; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; @Mixin(ClientNetworkHandler.class) -public class ClientNetworkHandlerMixin implements INetworkHandler { +public class ClientNetworkHandlerMixin implements NetworkHandlerAccess, INetworkHandler { - @Shadow @Final private Minecraft minecraft; + @Shadow private Minecraft minecraft; + @Shadow private MultiplayerWorld world; /** * Channels that the server is listening to. */ - @Unique private Set serverChannels; + @Unique private Set serverChannels; @Inject( method = "handleLogin", @@ -51,8 +54,8 @@ public class ClientNetworkHandlerMixin implements INetworkHandler { } @Override - public boolean osl$networking$handleCustomPayload(CustomPayloadPacket packet) { - return ClientPlayNetworkingImpl.handle(minecraft, (ClientNetworkHandler)(Object)this, packet); + public boolean osl$networking$canRunOffMainThread() { + return minecraft != null && minecraft.world != null && minecraft.player != null && world != null; } @Override @@ -61,12 +64,17 @@ public class ClientNetworkHandlerMixin implements INetworkHandler { } @Override - public void osl$networking$registerChannels(Set channels) { + public boolean osl$networking$isPlayReady(NamespacedIdentifier channel) { + return serverChannels != null && serverChannels.contains(channel); + } + + @Override + public void osl$networking$registerChannels(Set channels) { serverChannels = new LinkedHashSet<>(channels); } @Override - public boolean osl$networking$isRegisteredChannel(String channel) { - return serverChannels != null && serverChannels.contains(channel); + public boolean osl$networking$handleCustomPayload(CustomPayloadPacket packet) { + return ClientPlayNetworkingImpl.handlePacket(minecraft, (ClientNetworkHandler)(Object)this, packet); } } diff --git a/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/HandshakePacketMixin.java b/libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/HandshakePacketMixin.java similarity index 100% rename from libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/HandshakePacketMixin.java rename to libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/HandshakePacketMixin.java diff --git a/libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java b/libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java new file mode 100644 index 00000000..85baea9b --- /dev/null +++ b/libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/MinecraftMixin.java @@ -0,0 +1,44 @@ +package net.ornithemc.osl.networking.impl.mixin.client; + +import java.util.ArrayDeque; +import java.util.Queue; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.client.Minecraft; + +import net.ornithemc.osl.networking.impl.access.TaskRunnerAccess; + +@Mixin(Minecraft.class) +public class MinecraftMixin implements TaskRunnerAccess { + + @Unique + private Queue tasks = new ArrayDeque<>(); + + @Inject( + method = "tick", + at = @At( + value = "HEAD" + ) + ) + private void osl$networking$runTasks(CallbackInfo ci) { + synchronized (this.tasks) { + while (!this.tasks.isEmpty()) { + this.tasks.poll().run(); + } + } + } + + @Override + public boolean osl$networking$submit(Runnable task) { + synchronized (this.tasks) { + this.tasks.add(task); + } + + return true; + } +} diff --git a/libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ConnectionMixin.java b/libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ConnectionMixin.java new file mode 100644 index 00000000..8cbf1eeb --- /dev/null +++ b/libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ConnectionMixin.java @@ -0,0 +1,33 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import net.minecraft.network.Connection; +import net.minecraft.network.PacketHandler; +import net.minecraft.network.packet.Packet; + +import net.ornithemc.osl.networking.impl.Connections; + +@Mixin(Connection.class) +public class ConnectionMixin { + + @Shadow private PacketHandler listener; + + @Inject( + method = "read", + cancellable = true, + at = @At( + value = "INVOKE", + target = "Ljava/util/List;add(Ljava/lang/Object;)Z" + ) + ) + private void osl$networking$handlePacketsAsync(Packet packet, CallbackInfoReturnable cir) { + if (Connections.checkAsyncHandling(packet, listener)) { + cir.setReturnValue(true); + } + } +} diff --git a/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java b/libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java similarity index 100% rename from libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java rename to libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java diff --git a/libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/MinecraftServerMixin.java b/libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/MinecraftServerMixin.java new file mode 100644 index 00000000..5cdbf6c6 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/MinecraftServerMixin.java @@ -0,0 +1,48 @@ +package net.ornithemc.osl.networking.impl.mixin.server; + +import java.util.ArrayDeque; +import java.util.Queue; + +import org.objectweb.asm.Opcodes; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.server.MinecraftServer; + +import net.ornithemc.osl.networking.impl.access.TaskRunnerAccess; + +@Mixin(MinecraftServer.class) +public class MinecraftServerMixin implements TaskRunnerAccess { + + @Unique + private Queue tasks = new ArrayDeque<>(); + + @Inject( + method = "tick", + at = @At( + value = "FIELD", + opcode = Opcodes.PUTFIELD, + target = "Lnet/minecraft/server/MinecraftServer;ticks:I" + ) + ) + private void osl$networking$runTasks(CallbackInfo ci) { + synchronized (this.tasks) { + while (!this.tasks.isEmpty()) { + this.tasks.poll().run(); + } + } + } + + @Override + public boolean osl$networking$submit(Runnable task) { + synchronized (this.tasks) { + this.tasks.add(task); + } + + return true; + } +} diff --git a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerLoginNetworkHandlerMixin.java b/libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerLoginNetworkHandlerMixin.java similarity index 94% rename from libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerLoginNetworkHandlerMixin.java rename to libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerLoginNetworkHandlerMixin.java index d57902df..4227d62e 100644 --- a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerLoginNetworkHandlerMixin.java +++ b/libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerLoginNetworkHandlerMixin.java @@ -52,7 +52,7 @@ public class ServerLoginNetworkHandlerMixin { if (player != null) { if (ornithe) { // send channel registration data as soon as login occurs - ServerPlayNetworkingImpl.doSend(player, HandshakePayload.CHANNEL, HandshakePayload.server()); + ServerPlayNetworkingImpl.sendNoCheck(player, HandshakePayload.CHANNEL, HandshakePayload.server()); } ServerConnectionEvents.LOGIN.invoker().accept(server, player); diff --git a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java b/libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java similarity index 68% rename from libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java rename to libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java index 11335ca1..381c0697 100644 --- a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java +++ b/libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java @@ -3,7 +3,6 @@ import java.util.LinkedHashSet; import java.util.Set; -import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -15,21 +14,23 @@ import net.minecraft.server.entity.mob.player.ServerPlayerEntity; import net.minecraft.server.network.handler.ServerPlayNetworkHandler; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; import net.ornithemc.osl.networking.impl.CustomPayloadPacket; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; @Mixin(ServerPlayNetworkHandler.class) -public class ServerPlayNetworkHandlerMixin implements INetworkHandler { +public class ServerPlayNetworkHandlerMixin implements NetworkHandlerAccess, INetworkHandler { - @Shadow @Final private MinecraftServer server; - @Shadow @Final private ServerPlayerEntity player; + @Shadow private MinecraftServer server; + @Shadow private ServerPlayerEntity player; /** * Channels that the client is listening to. */ - @Unique private Set clientChannels; + @Unique private Set clientChannels; @Inject( method = "onDisconnect", @@ -43,8 +44,8 @@ public class ServerPlayNetworkHandlerMixin implements INetworkHandler { } @Override - public boolean osl$networking$handleCustomPayload(CustomPayloadPacket packet) { - return ServerPlayNetworkingImpl.handle(server, (ServerPlayNetworkHandler)(Object)this, player, packet); + public boolean osl$networking$canRunOffMainThread() { + return true; } @Override @@ -53,12 +54,17 @@ public class ServerPlayNetworkHandlerMixin implements INetworkHandler { } @Override - public void osl$networking$registerChannels(Set channels) { + public boolean osl$networking$isPlayReady(NamespacedIdentifier channel) { + return clientChannels != null && clientChannels.contains(channel); + } + + @Override + public void osl$networking$registerChannels(Set channels) { clientChannels = new LinkedHashSet<>(channels); } @Override - public boolean osl$networking$isRegisteredChannel(String channel) { - return clientChannels != null && clientChannels.contains(channel); + public boolean osl$networking$handleCustomPayload(CustomPayloadPacket packet) { + return ServerPlayNetworkingImpl.handlePacket(server, (ServerPlayNetworkHandler)(Object)this, player, packet); } } diff --git a/libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/resources/osl.networking.mixins.json b/libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/resources/osl.networking.mixins.json new file mode 100644 index 00000000..71939fcc --- /dev/null +++ b/libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/resources/osl.networking.mixins.json @@ -0,0 +1,23 @@ +{ + "required": true, + "minVersion": "0.8", + "package": "net.ornithemc.osl.networking.impl.mixin", + "compatibilityLevel": "JAVA_8", + "mixins": [ + "common.ConnectionMixin", + "common.PacketAccessor" + ], + "client": [ + "client.ClientNetworkHandlerMixin", + "client.HandshakePacketMixin", + "client.MinecraftMixin" + ], + "server": [ + "server.MinecraftServerMixin", + "server.ServerLoginNetworkHandlerMixin", + "server.ServerPlayNetworkHandlerMixin" + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/build.gradle b/libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/build.gradle new file mode 100644 index 00000000..8bb4e9a0 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/build.gradle @@ -0,0 +1,5 @@ +setUpModule(project, + 'entrypoints-mcin-20091223-1459-mc1.5.2', + 'lifecycle-events-mcserver-a0.2.0-mcserver-a0.2.8', + 'networking-mcserver-a0.2.2-mcserver-a0.2.8' +) diff --git a/libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/gradle.properties b/libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/gradle.properties new file mode 100644 index 00000000..dc090d1c --- /dev/null +++ b/libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/gradle.properties @@ -0,0 +1,10 @@ +environment = server +min_mc_version = server-a0.1.2_01 +max_mc_version = server-a0.2.8 +mc_version_range = >=1.0.0-alpha.1.2.1 <=1.0.0-alpha.2.8 + +minecraft_version = server-a0.2.8 +feather_build = 1 +raven_build = 1 +sparrow_build = 1 +nests_build = 3 diff --git a/libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java b/libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java new file mode 100644 index 00000000..eb557624 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java @@ -0,0 +1,74 @@ +package net.ornithemc.osl.networking.impl; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +import net.minecraft.network.PacketHandler; +import net.minecraft.network.packet.Packet; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.api.StringChannelIdentifierParser; +import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; +import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; + +public class CustomPayloadPacket extends Packet implements CustomPayloadPacketAccess { + + private String channel; + private int size; + private byte[] data; + + public CustomPayloadPacket() { + } + + public CustomPayloadPacket(NamespacedIdentifier channel, byte[] data) { + this.channel = StringChannelIdentifierParser.toString(channel); + this.data = data; + this.size = data.length; + + if (this.data != null && this.size > Short.MAX_VALUE) { + throw new IllegalArgumentException("Payload may not be larger than 32k"); + } + } + + @Override + public void read(DataInputStream input) throws IOException { + this.channel = input.readUTF(); + this.size = input.readShort(); + if (this.size > 0 && this.size < Short.MAX_VALUE) { + this.data = new byte[this.size]; + input.readFully(this.data); + } + } + + @Override + public void write(DataOutputStream output) throws IOException { + output.writeUTF(this.channel); + output.writeShort(this.size); + if (this.data != null) { + output.write(this.data); + } + } + + @Override + public void handle(PacketHandler handler) { + if (handler instanceof INetworkHandler) { + ((INetworkHandler)handler).osl$networking$handleCustomPayload(this); + } + } + + @Override + public int getSize() { + return 2 + this.channel.length() * 2 + 2 + this.data.length; + } + + @Override + public NamespacedIdentifier osl$networking$getChannel() { + return StringChannelIdentifierParser.fromString(this.channel); + } + + @Override + public byte[] osl$networking$getData() { + return this.data; + } +} diff --git a/libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/Networking.java new file mode 100644 index 00000000..5fdd6a7e --- /dev/null +++ b/libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/Networking.java @@ -0,0 +1,35 @@ +package net.ornithemc.osl.networking.impl; + +import net.ornithemc.osl.entrypoints.api.ModInitializer; +import net.ornithemc.osl.entrypoints.api.client.ClientModInitializer; +import net.ornithemc.osl.entrypoints.api.server.ServerModInitializer; +import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; +import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; +import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; + +public class Networking implements ModInitializer, ClientModInitializer, ServerModInitializer { + + @Override + public void init() { + // no-op + } + + @Override + public void initClient() { + // no-op + } + + @Override + public void initServer() { + MinecraftServerEvents.START.register(ServerPlayNetworkingImpl::setUp); + MinecraftServerEvents.STOP.register(ServerPlayNetworkingImpl::destroy); + ServerPlayNetworkingImpl.setUpPacketFactory(CustomPayloadPacket::new); + ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { + ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); + ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); + + return true; + }); + } +} diff --git a/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java b/libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java similarity index 55% rename from libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java rename to libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java index 420bdcda..283c296d 100644 --- a/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java +++ b/libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java @@ -1,17 +1,9 @@ package net.ornithemc.osl.networking.impl.interfaces.mixin; -import java.util.Set; - import net.ornithemc.osl.networking.impl.CustomPayloadPacket; public interface INetworkHandler { boolean osl$networking$handleCustomPayload(CustomPayloadPacket packet); - boolean osl$networking$isPlayReady(); - - void osl$networking$registerChannels(Set channels); - - boolean osl$networking$isRegisteredChannel(String channel); - } diff --git a/libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ConnectionMixin.java b/libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ConnectionMixin.java new file mode 100644 index 00000000..8cbf1eeb --- /dev/null +++ b/libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ConnectionMixin.java @@ -0,0 +1,33 @@ +package net.ornithemc.osl.networking.impl.mixin.common; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +import net.minecraft.network.Connection; +import net.minecraft.network.PacketHandler; +import net.minecraft.network.packet.Packet; + +import net.ornithemc.osl.networking.impl.Connections; + +@Mixin(Connection.class) +public class ConnectionMixin { + + @Shadow private PacketHandler listener; + + @Inject( + method = "read", + cancellable = true, + at = @At( + value = "INVOKE", + target = "Ljava/util/List;add(Ljava/lang/Object;)Z" + ) + ) + private void osl$networking$handlePacketsAsync(Packet packet, CallbackInfoReturnable cir) { + if (Connections.checkAsyncHandling(packet, listener)) { + cir.setReturnValue(true); + } + } +} diff --git a/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java b/libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java similarity index 100% rename from libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java rename to libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java diff --git a/libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/MinecraftServerMixin.java b/libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/MinecraftServerMixin.java new file mode 100644 index 00000000..5cdbf6c6 --- /dev/null +++ b/libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/MinecraftServerMixin.java @@ -0,0 +1,48 @@ +package net.ornithemc.osl.networking.impl.mixin.server; + +import java.util.ArrayDeque; +import java.util.Queue; + +import org.objectweb.asm.Opcodes; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Unique; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import net.minecraft.server.MinecraftServer; + +import net.ornithemc.osl.networking.impl.access.TaskRunnerAccess; + +@Mixin(MinecraftServer.class) +public class MinecraftServerMixin implements TaskRunnerAccess { + + @Unique + private Queue tasks = new ArrayDeque<>(); + + @Inject( + method = "tick", + at = @At( + value = "FIELD", + opcode = Opcodes.PUTFIELD, + target = "Lnet/minecraft/server/MinecraftServer;ticks:I" + ) + ) + private void osl$networking$runTasks(CallbackInfo ci) { + synchronized (this.tasks) { + while (!this.tasks.isEmpty()) { + this.tasks.poll().run(); + } + } + } + + @Override + public boolean osl$networking$submit(Runnable task) { + synchronized (this.tasks) { + this.tasks.add(task); + } + + return true; + } +} diff --git a/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerLoginNetworkHandlerMixin.java b/libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerLoginNetworkHandlerMixin.java similarity index 94% rename from libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerLoginNetworkHandlerMixin.java rename to libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerLoginNetworkHandlerMixin.java index d57902df..4227d62e 100644 --- a/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerLoginNetworkHandlerMixin.java +++ b/libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerLoginNetworkHandlerMixin.java @@ -52,7 +52,7 @@ public class ServerLoginNetworkHandlerMixin { if (player != null) { if (ornithe) { // send channel registration data as soon as login occurs - ServerPlayNetworkingImpl.doSend(player, HandshakePayload.CHANNEL, HandshakePayload.server()); + ServerPlayNetworkingImpl.sendNoCheck(player, HandshakePayload.CHANNEL, HandshakePayload.server()); } ServerConnectionEvents.LOGIN.invoker().accept(server, player); diff --git a/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java b/libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java similarity index 68% rename from libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java rename to libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java index 11335ca1..381c0697 100644 --- a/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java +++ b/libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java @@ -3,7 +3,6 @@ import java.util.LinkedHashSet; import java.util.Set; -import org.spongepowered.asm.mixin.Final; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Shadow; import org.spongepowered.asm.mixin.Unique; @@ -15,21 +14,23 @@ import net.minecraft.server.entity.mob.player.ServerPlayerEntity; import net.minecraft.server.network.handler.ServerPlayNetworkHandler; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; import net.ornithemc.osl.networking.impl.CustomPayloadPacket; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; @Mixin(ServerPlayNetworkHandler.class) -public class ServerPlayNetworkHandlerMixin implements INetworkHandler { +public class ServerPlayNetworkHandlerMixin implements NetworkHandlerAccess, INetworkHandler { - @Shadow @Final private MinecraftServer server; - @Shadow @Final private ServerPlayerEntity player; + @Shadow private MinecraftServer server; + @Shadow private ServerPlayerEntity player; /** * Channels that the client is listening to. */ - @Unique private Set clientChannels; + @Unique private Set clientChannels; @Inject( method = "onDisconnect", @@ -43,8 +44,8 @@ public class ServerPlayNetworkHandlerMixin implements INetworkHandler { } @Override - public boolean osl$networking$handleCustomPayload(CustomPayloadPacket packet) { - return ServerPlayNetworkingImpl.handle(server, (ServerPlayNetworkHandler)(Object)this, player, packet); + public boolean osl$networking$canRunOffMainThread() { + return true; } @Override @@ -53,12 +54,17 @@ public class ServerPlayNetworkHandlerMixin implements INetworkHandler { } @Override - public void osl$networking$registerChannels(Set channels) { + public boolean osl$networking$isPlayReady(NamespacedIdentifier channel) { + return clientChannels != null && clientChannels.contains(channel); + } + + @Override + public void osl$networking$registerChannels(Set channels) { clientChannels = new LinkedHashSet<>(channels); } @Override - public boolean osl$networking$isRegisteredChannel(String channel) { - return clientChannels != null && clientChannels.contains(channel); + public boolean osl$networking$handleCustomPayload(CustomPayloadPacket packet) { + return ServerPlayNetworkingImpl.handlePacket(server, (ServerPlayNetworkHandler)(Object)this, player, packet); } } diff --git a/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/resources/osl.networking.mixins.json b/libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/src/main/resources/osl.networking.mixins.json similarity index 84% rename from libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/resources/osl.networking.mixins.json rename to libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/src/main/resources/osl.networking.mixins.json index 2cfc21d4..788e819b 100644 --- a/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/resources/osl.networking.mixins.json +++ b/libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/src/main/resources/osl.networking.mixins.json @@ -4,11 +4,13 @@ "package": "net.ornithemc.osl.networking.impl.mixin", "compatibilityLevel": "JAVA_8", "mixins": [ + "common.ConnectionMixin", "common.PacketAccessor" ], "client": [ ], "server": [ + "server.MinecraftServerMixin", "server.ServerLoginNetworkHandlerMixin", "server.ServerPlayNetworkHandlerMixin" ], diff --git a/libraries/networking-impl/src/main/resources/assets/ornithe-standard-libraries/networking-impl/icon.png b/libraries/networking-impl/src/main/resources/assets/ornithe-standard-libraries/networking-impl/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..ef5885319b1f73488afa5ecd8b44632d99d809a5 GIT binary patch literal 365675 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

q6V{ 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%0Ag2-Q77x&CNHPPG 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

-oLd?y+2dqY!wwKOUrIOg4I0)jZw(#-!R^N1LZ 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 literal 0 HcmV?d00001 diff --git a/libraries/networking-impl/src/main/resources/fabric.mod.json b/libraries/networking-impl/src/main/resources/fabric.mod.json new file mode 100644 index 00000000..d4df3431 --- /dev/null +++ b/libraries/networking-impl/src/main/resources/fabric.mod.json @@ -0,0 +1,41 @@ +{ + "schemaVersion": 1, + "id": "osl-networking-impl", + "version": "${version}", + "name": "Networking Implementation", + "description": "Implementation details of the OSL Networking API.", + "authors": [ + "OrnitheMC", + "Space Walker" + ], + "contact": { + "homepage": "https://ornithemc.net/", + "issues": "https://github.com/OrnitheMC/ornithe-standard-libraries/issues", + "sources": "https://github.com/OrnitheMC/ornithe-standard-libraries" + }, + "license": "Apache-2.0", + "icon": "assets/ornithe-standard-libraries/networking-impl/icon.png", + "environment": "${environment}", + "entrypoints": { + "init": [ + "net.ornithemc.osl.networking.impl.Networking" + ], + "client-init": [ + "net.ornithemc.osl.networking.impl.Networking" + ], + "server-init": [ + "net.ornithemc.osl.networking.impl.Networking" + ] + }, + "mixins": [ + "osl.networking.mixins.json" + ], + "depends": { + "fabricloader": ">=0.16.0", + "minecraft": "${mc_version_range}", + "osl-core": ">=0.4.0", + "osl-entrypoints": ">=0.2.0", + "osl-lifecycle-events": ">=0.4.0", + "osl-networking": ">=0.9.0" + } +} diff --git a/libraries/networking/networking-mc1.13-pre4-mc18w30b/build.gradle b/libraries/networking/networking-mc1.13-pre4-mc18w30b/build.gradle deleted file mode 100644 index cadd1023..00000000 --- a/libraries/networking/networking-mc1.13-pre4-mc18w30b/build.gradle +++ /dev/null @@ -1,4 +0,0 @@ -setUpModule(project, - 'entrypoints-mc13w16a-04192037-mc1.14.4', - 'lifecycle-events-mc18w30a-mc18w50a' -) diff --git a/libraries/networking/networking-mc1.13-pre4-mc18w30b/gradle.properties b/libraries/networking/networking-mc1.13-pre4-mc18w30b/gradle.properties deleted file mode 100644 index d6140262..00000000 --- a/libraries/networking/networking-mc1.13-pre4-mc18w30b/gradle.properties +++ /dev/null @@ -1,7 +0,0 @@ -environment = * -min_mc_version = 1.13-pre4 -max_mc_version = 18w30b -mc_version_range = >=1.13-rc.4 <=1.13.1-alpha.18.30.b - -minecraft_version = 18w30b -feather_build = 1 diff --git a/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java b/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java deleted file mode 100644 index aee6a1cd..00000000 --- a/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java +++ /dev/null @@ -1,13 +0,0 @@ -package net.ornithemc.osl.networking.api; - -import java.io.IOException; - -import net.minecraft.network.PacketByteBuf; - -public interface CustomPayload { - - void read(PacketByteBuf buffer) throws IOException; - - void write(PacketByteBuf buffer) throws IOException; - -} diff --git a/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/PacketByteBufs.java b/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/PacketByteBufs.java deleted file mode 100644 index e1944e62..00000000 --- a/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/PacketByteBufs.java +++ /dev/null @@ -1,31 +0,0 @@ -package net.ornithemc.osl.networking.api; - -import java.io.IOException; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; - -import net.minecraft.network.PacketByteBuf; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; - -public final class PacketByteBufs { - - public static PacketByteBuf make() { - return make(Unpooled.buffer()); - } - - public static PacketByteBuf make(byte[] bytes) { - return make(Unpooled.wrappedBuffer(bytes)); - } - - public static PacketByteBuf make(ByteBuf buf) { - return new PacketByteBuf(buf); - } - - public static PacketByteBuf make(IOConsumer writer) throws IOException { - PacketByteBuf buffer = make(); - writer.accept(buffer); - return buffer; - } -} diff --git a/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java b/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java deleted file mode 100644 index cfb3c548..00000000 --- a/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java +++ /dev/null @@ -1,154 +0,0 @@ -package net.ornithemc.osl.networking.api.client; - -import java.io.IOException; -import java.util.function.Supplier; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.network.handler.ClientPlayNetworkHandler; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.resource.Identifier; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; - -public final class ClientPlayNetworking { - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any valid {@linkplain net.minecraft.resource.Identifier Identifier}. - */ - public static void registerListener(Identifier channel, Supplier initializer, PayloadListener listener) { - ClientPlayNetworkingImpl.registerListener(channel, initializer, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. - * A channel can be any valid {@linkplain net.minecraft.resource.Identifier Identifier}. - */ - public static void registerListenerAsync(Identifier channel, Supplier initializer, PayloadListener listener) { - ClientPlayNetworkingImpl.registerListenerAsync(channel, initializer, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any valid {@linkplain net.minecraft.resource.Identifier Identifier}. - */ - public static void registerListener(Identifier channel, ByteBufListener listener) { - ClientPlayNetworkingImpl.registerListener(channel, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. - * A channel can be any valid {@linkplain net.minecraft.resource.Identifier Identifier}. - */ - public static void registerListenerAsync(Identifier channel, ByteBufListener listener) { - ClientPlayNetworkingImpl.registerListenerAsync(channel, listener); - } - - /** - * Remove the listener registered to the given channel. - */ - public static void unregisterListener(Identifier channel) { - ClientPlayNetworkingImpl.unregisterListener(channel); - } - - /** - * Check whether the connection is ready for data to be sent to the server. - */ - public static boolean isPlayReady() { - return ClientPlayNetworkingImpl.isPlayReady(); - } - - /** - * Check whether the given channel is open for data to be sent through it. - * This method will return {@code false} if the client is not connected to a - * server, or if the server has no listeners for the given channel. - */ - public static boolean canSend(Identifier channel) { - return ClientPlayNetworkingImpl.canSend(channel); - } - - /** - * Send a packet to the server through the given channel. The payload will - * only be written if the channel is open. - */ - public static void send(Identifier channel, CustomPayload payload) { - ClientPlayNetworkingImpl.send(channel, payload); - } - - /** - * Send a packet to the server through the given channel. The writer will - * only be called if the channel is open. - */ - public static void send(Identifier channel, IOConsumer writer) { - ClientPlayNetworkingImpl.send(channel, writer); - } - - /** - * Send a packet to the server through the given channel. - */ - public static void send(Identifier channel, PacketByteBuf data) { - ClientPlayNetworkingImpl.send(channel, data); - } - - /** - * Send a packet to the server through the given channel, without checking - * whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the server. - */ - public static void doSend(Identifier channel, CustomPayload payload) { - ClientPlayNetworkingImpl.doSend(channel, payload); - } - - /** - * Send a packet to the server through the given channel, without checking - * whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the server. - */ - public static void doSend(Identifier channel, IOConsumer writer) { - ClientPlayNetworkingImpl.doSend(channel, writer); - } - - /** - * Send a packet to the server through the given channel, without checking - * whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the server. - */ - public static void doSend(Identifier channel, PacketByteBuf data) { - ClientPlayNetworkingImpl.doSend(channel, data); - } - - public interface PayloadListener { - - /** - * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, T payload) throws IOException; - - } - - public interface ByteBufListener { - - /** - * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, PacketByteBuf data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java b/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java deleted file mode 100644 index 4d0e1a1d..00000000 --- a/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java +++ /dev/null @@ -1,317 +0,0 @@ -package net.ornithemc.osl.networking.api.server; - -import java.io.IOException; -import java.util.function.Supplier; - -import net.minecraft.network.PacketByteBuf; -import net.minecraft.resource.Identifier; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.entity.living.player.ServerPlayerEntity; -import net.minecraft.server.network.handler.ServerPlayNetworkHandler; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -public final class ServerPlayNetworking { - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any valid {@linkplain net.minecraft.resource.Identifier Identifier}. - */ - public static void registerListener(Identifier channel, Supplier initializer, PayloadListener listener) { - ServerPlayNetworkingImpl.registerListener(channel, initializer, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. - * A channel can be any valid {@linkplain net.minecraft.resource.Identifier Identifier}. - */ - public static void registerListenerAsync(Identifier channel, Supplier initializer, PayloadListener listener) { - ServerPlayNetworkingImpl.registerListenerAsync(channel, initializer, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any valid {@linkplain net.minecraft.resource.Identifier Identifier}. - */ - public static void registerListener(Identifier channel, ByteBufListener listener) { - ServerPlayNetworkingImpl.registerListener(channel, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. - * A channel can be any valid {@linkplain net.minecraft.resource.Identifier Identifier}. - */ - public static void registerListenerAsync(Identifier channel, ByteBufListener listener) { - ServerPlayNetworkingImpl.registerListenerAsync(channel, listener); - } - - /** - * Remove the listener registered to the given channel. - */ - public static void unregisterListener(Identifier channel) { - ServerPlayNetworkingImpl.unregisterListener(channel); - } - - /** - * Check whether the connection is ready for data to be sent to the client. - */ - public static boolean isPlayReady(ServerPlayerEntity player) { - return ServerPlayNetworkingImpl.isPlayReady(player); - } - - /** - * Check whether the given channel is open for data to be sent through it. - * This method will return {@code false} if the client has no listeners for - * the given channel. - */ - public static boolean canSend(ServerPlayerEntity player, Identifier channel) { - return ServerPlayNetworkingImpl.canSend(player, channel); - } - - /** - * Send a packet to the given player through the given channel. The payload - * will only be written if the channel is open. - */ - public static void send(ServerPlayerEntity player, Identifier channel, CustomPayload payload) { - ServerPlayNetworkingImpl.send(player, channel, payload); - } - - /** - * Send a packet to the given player through the given channel. The writer - * will only be called if the channel is open. - */ - public static void send(ServerPlayerEntity player, Identifier channel, IOConsumer writer) { - ServerPlayNetworkingImpl.send(player, channel, writer); - } - - /** - * Send a packet to the given player through the given channel. - */ - public static void send(ServerPlayerEntity player, Identifier channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.send(player, channel, data); - } - - /** - * Send a packet to the given players through the given channel. The payload - * will only be written if the channel is open for at least one player. - */ - public static void send(Iterable players, Identifier channel, CustomPayload payload) { - ServerPlayNetworkingImpl.send(players, channel, payload); - } - - /** - * Send a packet to the given players through the given channel. The writer - * will only be called if the channel is open for at least one player. - */ - public static void send(Iterable players, Identifier channel, IOConsumer writer) { - ServerPlayNetworkingImpl.send(players, channel, writer); - } - - /** - * Send a packet to the given players through the given channel. - */ - public static void send(Iterable players, Identifier channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.send(players, channel, data); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel. The payload will only be written if the channel is open for at - * least one player. - */ - public static void send(int dimension, Identifier channel, CustomPayload payload) { - ServerPlayNetworkingImpl.send(dimension, channel, payload); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel. The writer will only be called if the channel is open for at - * least one player. - */ - public static void send(int dimension, Identifier channel, IOConsumer writer) { - ServerPlayNetworkingImpl.send(dimension, channel, writer); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel. - */ - public static void send(int dimension, Identifier channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.send(dimension, channel, data); - } - - /** - * Send a packet to all players through the given channel. The payload will - * only be written if the channel is open for at least one player. - */ - public static void send(Identifier channel, CustomPayload payload) { - ServerPlayNetworkingImpl.send(channel, payload); - } - - /** - * Send a packet to all players through the given channel. The writer will - * only be called if the channel is open for at least one player. - */ - public static void send(Identifier channel, IOConsumer writer) { - ServerPlayNetworkingImpl.send(channel, writer); - } - - /** - * Send a packet to all players through the given channel. - */ - public static void send(Identifier channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.send(channel, data); - } - - /** - * Send a packet to the given player through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(ServerPlayerEntity player, Identifier channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(player, channel, payload); - } - - /** - * Send a packet to the given player through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(ServerPlayerEntity player, Identifier channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(player, channel, writer); - } - - /** - * Send a packet to the given player through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(ServerPlayerEntity player, Identifier channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.doSend(player, channel, data); - } - - /** - * Send a packet to the given players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(Iterable players, Identifier channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(players, channel, payload); - } - - /** - * Send a packet to the given players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(Iterable players, Identifier channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(players, channel, writer); - } - - /** - * Send a packet to the given players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(Iterable players, Identifier channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.doSend(players, channel, data); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel, without checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(int dimension, Identifier channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(dimension, channel, payload); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel, without checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(int dimension, Identifier channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(dimension, channel, writer); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel, without checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(int dimension, Identifier channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.doSend(dimension, channel, data); - } - - /** - * Send a packet to all players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(Identifier channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(channel, payload); - } - - /** - * Send a packet to all players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(Identifier channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(channel, writer); - } - - /** - * Send a packet to all players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(Identifier channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.doSend(channel, data); - } - - public interface PayloadListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, T payload) throws IOException; - - } - - public interface ByteBufListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, PacketByteBuf data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java b/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java deleted file mode 100644 index 7ef2cb48..00000000 --- a/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java +++ /dev/null @@ -1,55 +0,0 @@ -package net.ornithemc.osl.networking.impl; - -import java.io.IOException; -import java.util.LinkedHashSet; -import java.util.Set; - -import net.minecraft.network.PacketByteBuf; -import net.minecraft.resource.Identifier; - -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -public class HandshakePayload implements CustomPayload { - - public static final Identifier CHANNEL = new Identifier("osl", "handshake"); - - public Set channels; - - public HandshakePayload() { - } - - public HandshakePayload(Set channels) { - this.channels = channels; - } - - public static HandshakePayload client() { - return new HandshakePayload(ClientPlayNetworkingImpl.LISTENERS.keySet()); - } - - public static HandshakePayload server() { - return new HandshakePayload(ServerPlayNetworkingImpl.LISTENERS.keySet()); - } - - @Override - public void read(PacketByteBuf buffer) throws IOException { - channels = new LinkedHashSet<>(); - int channelCount = buffer.readInt(); - - if (channelCount > 0) { - for (int i = 0; i < channelCount; i++) { - channels.add(buffer.readIdentifier()); - } - } - } - - @Override - public void write(PacketByteBuf buffer) throws IOException { - buffer.writeInt(channels.size()); - - for (Identifier channel : channels) { - buffer.writeIdentifier(channel); - } - } -} diff --git a/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/NetworkListener.java b/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/NetworkListener.java deleted file mode 100644 index 7e34822c..00000000 --- a/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/NetworkListener.java +++ /dev/null @@ -1,20 +0,0 @@ -package net.ornithemc.osl.networking.impl; - -public class NetworkListener { - - private final T listener; - private final boolean async; - - public NetworkListener(T listener, boolean async) { - this.listener = listener; - this.async = async; - } - - public T get() { - return listener; - } - - public boolean isAsync() { - return async; - } -} diff --git a/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/Networking.java deleted file mode 100644 index 601d2f5d..00000000 --- a/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/Networking.java +++ /dev/null @@ -1,57 +0,0 @@ -package net.ornithemc.osl.networking.impl; - -import net.ornithemc.osl.entrypoints.api.ModInitializer; -import net.ornithemc.osl.entrypoints.api.client.ClientModInitializer; -import net.ornithemc.osl.entrypoints.api.server.ServerModInitializer; -import net.ornithemc.osl.lifecycle.api.client.MinecraftClientEvents; -import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; -import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking; -import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking; -import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -public class Networking implements ModInitializer, ClientModInitializer, ServerModInitializer { - - @Override - public void init() { - MinecraftServerEvents.START.register(server -> { - ServerPlayNetworkingImpl.setUp(server); - }); - MinecraftServerEvents.STOP.register(server -> { - ServerPlayNetworkingImpl.destroy(server); - }); - ServerPlayNetworking.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { - // send channel registration data as a response to receiving client channel registration data - ServerPlayNetworkingImpl.doSend(player, HandshakePayload.CHANNEL, HandshakePayload.server()); - - ((INetworkHandler)handler).osl$networking$registerChannels(payload.channels); - ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); - - return true; - }); - } - - @Override - public void initClient() { - MinecraftClientEvents.START.register(minecraft -> { - ClientPlayNetworkingImpl.setUp(minecraft); - }); - MinecraftClientEvents.STOP.register(minecraft -> { - ClientPlayNetworkingImpl.destroy(minecraft); - }); - ClientPlayNetworking.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { - ((INetworkHandler)handler).osl$networking$registerChannels(payload.channels); - ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); - - return true; - }); - } - - @Override - public void initServer() { - // empty impl - } -} diff --git a/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java b/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java deleted file mode 100644 index 5faf509d..00000000 --- a/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java +++ /dev/null @@ -1,183 +0,0 @@ -package net.ornithemc.osl.networking.impl.client; - -import java.io.IOException; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.function.Supplier; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.network.handler.ClientPlayNetworkHandler; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.network.PacketUtils; -import net.minecraft.network.packet.Packet; -import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; -import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; -import net.minecraft.resource.Identifier; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.api.PacketByteBufs; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.ByteBufListener; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.PayloadListener; -import net.ornithemc.osl.networking.impl.NetworkListener; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; - -public final class ClientPlayNetworkingImpl { - - private static final Logger LOGGER = LogManager.getLogger("OSL|Client Play Networking"); - - private static Minecraft minecraft; - - public static void setUp(Minecraft minecraft) { - if (ClientPlayNetworkingImpl.minecraft == minecraft) { - throw new IllegalStateException("tried to set up client networking when it was already set up!"); - } - - ClientPlayNetworkingImpl.minecraft = minecraft; - } - - public static void destroy(Minecraft minecraft) { - if (ClientPlayNetworkingImpl.minecraft != minecraft) { - throw new IllegalStateException("tried to destroy client networking when it was not set up!"); - } - - ClientPlayNetworkingImpl.minecraft = null; - } - - public static final Map> LISTENERS = new LinkedHashMap<>(); - - public static void registerListener(Identifier channel, Supplier initializer, PayloadListener listener) { - registerListener(channel, initializer, listener, false); - } - - public static void registerListenerAsync(Identifier channel, Supplier initializer, PayloadListener listener) { - registerListener(channel, initializer, listener, true); - } - - private static void registerListener(Identifier channel, Supplier initializer, PayloadListener listener, boolean async) { - registerListenerImpl(channel, (minecraft, handler, data) -> { - T payload = initializer.get(); - payload.read(data); - - return listener.handle(minecraft, handler, payload); - }, async); - } - - public static void registerListener(Identifier channel, ByteBufListener listener) { - registerListener(channel, listener, false); - } - - public static void registerListenerAsync(Identifier channel, ByteBufListener listener) { - registerListener(channel, listener, true); - } - - private static void registerListener(Identifier channel, ByteBufListener listener, boolean async) { - registerListenerImpl(channel, listener::handle, async); - } - - private static void registerListenerImpl(Identifier channel, Listener listener, boolean async) { - LISTENERS.compute(channel, (key, value) -> { - if (value != null) { - throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); - } - - return new NetworkListener<>(listener, async); - }); - } - - public static void unregisterListener(Identifier channel) { - LISTENERS.remove(channel); - } - - public static boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, CustomPayloadS2CPacket packet) { - Identifier channel = packet.getChannel(); - NetworkListener listener = LISTENERS.get(channel); - - if (listener != null) { - if (!listener.isAsync()) { - PacketUtils.ensureOnSameThread(packet, handler, minecraft); - } - - try { - return listener.get().handle(minecraft, handler, packet.getData()); - } catch (IOException e) { - LOGGER.warn("error handling custom payload on channel \'" + channel + "\'", e); - return true; - } - } - - return false; - } - - public static boolean isPlayReady() { - INetworkHandler handler = (INetworkHandler)minecraft.getNetworkHandler(); - return handler != null && handler.osl$networking$isPlayReady(); - } - - public static boolean canSend(Identifier channel) { - INetworkHandler handler = (INetworkHandler)minecraft.getNetworkHandler(); - return handler != null && handler.osl$networking$isRegisteredChannel(channel); - } - - public static void send(Identifier channel, CustomPayload payload) { - if (canSend(channel)) { - doSend(channel, payload); - } - } - - public static void send(Identifier channel, IOConsumer writer) { - if (canSend(channel)) { - doSend(channel, writer); - } - } - - public static void send(Identifier channel, PacketByteBuf data) { - if (canSend(channel)) { - doSend(channel, data); - } - } - - public static void doSend(Identifier channel, CustomPayload payload) { - sendPacket(makePacket(channel, payload)); - } - - public static void doSend(Identifier channel, IOConsumer writer) { - sendPacket(makePacket(channel, writer)); - } - - public static void doSend(Identifier channel, PacketByteBuf data) { - sendPacket(makePacket(channel, data)); - } - - private static Packet makePacket(Identifier channel, CustomPayload payload) { - return makePacket(channel, payload::write); - } - - private static Packet makePacket(Identifier channel, IOConsumer writer) { - try { - return new CustomPayloadC2SPacket(channel, PacketByteBufs.make(writer)); - } catch (IOException e) { - LOGGER.warn("error writing custom payload to channel \'" + channel + "\'", e); - return null; - } - } - - private static Packet makePacket(Identifier channel, PacketByteBuf data) { - return new CustomPayloadC2SPacket(channel, data); - } - - private static void sendPacket(Packet packet) { - if (packet != null) { - minecraft.getNetworkHandler().sendPacket(packet); - } - } - - private interface Listener { - - boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, PacketByteBuf data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/ICustomPayloadPacket.java b/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/ICustomPayloadPacket.java deleted file mode 100644 index e4a813f5..00000000 --- a/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/ICustomPayloadPacket.java +++ /dev/null @@ -1,12 +0,0 @@ -package net.ornithemc.osl.networking.impl.interfaces.mixin; - -import net.minecraft.network.PacketByteBuf; -import net.minecraft.resource.Identifier; - -public interface ICustomPayloadPacket { - - Identifier osl$networking$getChannel(); - - PacketByteBuf osl$networking$getData(); - -} diff --git a/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java b/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java deleted file mode 100644 index e06f34db..00000000 --- a/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java +++ /dev/null @@ -1,15 +0,0 @@ -package net.ornithemc.osl.networking.impl.interfaces.mixin; - -import java.util.Set; - -import net.minecraft.resource.Identifier; - -public interface INetworkHandler { - - boolean osl$networking$isPlayReady(); - - void osl$networking$registerChannels(Set channels); - - boolean osl$networking$isRegisteredChannel(Identifier channel); - -} diff --git a/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java b/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java deleted file mode 100644 index 5719c0a7..00000000 --- a/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java +++ /dev/null @@ -1,27 +0,0 @@ -package net.ornithemc.osl.networking.impl.mixin.common; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -import net.minecraft.network.PacketByteBuf; -import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; -import net.minecraft.resource.Identifier; - -import net.ornithemc.osl.networking.impl.interfaces.mixin.ICustomPayloadPacket; - -@Mixin(CustomPayloadC2SPacket.class) -public class CustomPayloadC2SPacketMixin implements ICustomPayloadPacket { - - @Shadow private Identifier channel; - @Shadow private PacketByteBuf data; - - @Override - public Identifier osl$networking$getChannel() { - return channel; - } - - @Override - public PacketByteBuf osl$networking$getData() { - return data; - } -} diff --git a/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java b/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java deleted file mode 100644 index d0448b0c..00000000 --- a/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java +++ /dev/null @@ -1,286 +0,0 @@ -package net.ornithemc.osl.networking.impl.server; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.function.Supplier; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import net.minecraft.network.PacketByteBuf; -import net.minecraft.network.PacketUtils; -import net.minecraft.network.packet.Packet; -import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; -import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; -import net.minecraft.resource.Identifier; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.entity.living.player.ServerPlayerEntity; -import net.minecraft.server.network.handler.ServerPlayNetworkHandler; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.api.PacketByteBufs; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.ByteBufListener; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.PayloadListener; -import net.ornithemc.osl.networking.impl.NetworkListener; -import net.ornithemc.osl.networking.impl.interfaces.mixin.ICustomPayloadPacket; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; - -public final class ServerPlayNetworkingImpl { - - private static final Logger LOGGER = LogManager.getLogger("OSL|Server Play Networking"); - - private static MinecraftServer server; - - public static void setUp(MinecraftServer server) { - if (ServerPlayNetworkingImpl.server == server) { - throw new IllegalStateException("tried to set up server networking when it was already set up!"); - } - - ServerPlayNetworkingImpl.server = server; - } - - public static void destroy(MinecraftServer server) { - if (ServerPlayNetworkingImpl.server != server) { - throw new IllegalStateException("tried to destroy server networking when it was not set up!"); - } - - ServerPlayNetworkingImpl.server = null; - } - - public static final Map> LISTENERS = new LinkedHashMap<>(); - - public static void registerListener(Identifier channel, Supplier initializer, PayloadListener listener) { - registerListener(channel, initializer, listener, false); - } - - public static void registerListenerAsync(Identifier channel, Supplier initializer, PayloadListener listener) { - registerListener(channel, initializer, listener, true); - } - - private static void registerListener(Identifier channel, Supplier initializer, PayloadListener listener, boolean async) { - registerListenerImpl(channel, (server, handler, player, data) -> { - T payload = initializer.get(); - payload.read(data); - - return listener.handle(server, handler, player, payload); - }, async); - } - - public static void registerListener(Identifier channel, ByteBufListener listener) { - registerListener(channel, listener, false); - } - - public static void registerListenerAsync(Identifier channel, ByteBufListener listener) { - registerListener(channel, listener, true); - } - - private static void registerListener(Identifier channel, ByteBufListener listener, boolean async) { - registerListenerImpl(channel, listener::handle, async); - } - - private static void registerListenerImpl(Identifier channel, Listener listener, boolean async) { - LISTENERS.compute(channel, (key, value) -> { - if (value != null) { - throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); - } - - return new NetworkListener<>(listener, async); - }); - } - - public static void unregisterListener(Identifier channel) { - LISTENERS.remove(channel); - } - - public static boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, CustomPayloadC2SPacket packet) { - ICustomPayloadPacket p = (ICustomPayloadPacket)packet; - - Identifier channel = p.osl$networking$getChannel(); - NetworkListener listener = LISTENERS.get(channel); - - if (listener != null) { - if (!listener.isAsync()) { - PacketUtils.ensureOnSameThread(packet, handler, server); - } - - try { - return listener.get().handle(server, handler, player, p.osl$networking$getData()); - } catch (IOException e) { - LOGGER.warn("error handling custom payload on channel \'" + channel + "\'", e); - return true; - } - } - - return false; - } - - public static boolean isPlayReady(ServerPlayerEntity player) { - INetworkHandler handler = (INetworkHandler)player.networkHandler; - return handler != null && handler.osl$networking$isPlayReady(); - } - - public static boolean canSend(ServerPlayerEntity player, Identifier channel) { - INetworkHandler handler = (INetworkHandler)player.networkHandler; - return handler != null && handler.osl$networking$isRegisteredChannel(channel); - } - - public static void send(ServerPlayerEntity player, Identifier channel, CustomPayload payload) { - if (canSend(player, channel)) { - doSend(player, channel, payload); - } - } - - public static void send(ServerPlayerEntity player, Identifier channel, IOConsumer writer) { - if (canSend(player, channel)) { - doSend(player, channel, writer); - } - } - - public static void send(ServerPlayerEntity player, Identifier channel, PacketByteBuf data) { - if (canSend(player, channel)) { - doSend(player, channel, data); - } - } - - public static void send(Iterable players, Identifier channel, CustomPayload payload) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, payload)); - } - - public static void send(Iterable players, Identifier channel, IOConsumer writer) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, writer)); - } - - public static void send(Iterable players, Identifier channel, PacketByteBuf data) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, data)); - } - - public static void send(int dimension, Identifier channel, CustomPayload payload) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)), channel, payload); - } - - public static void send(int dimension, Identifier channel, IOConsumer writer) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)), channel, writer); - } - - public static void send(int dimension, Identifier channel, PacketByteBuf data) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)),channel, data); - } - - public static void send(Identifier channel, CustomPayload payload) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, payload); - } - - public static void send(Identifier channel, IOConsumer writer) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, writer); - } - - public static void send(Identifier channel, PacketByteBuf data) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, data); - } - - public static void doSend(ServerPlayerEntity player, Identifier channel, CustomPayload payload) { - sendPacket(player, makePacket(channel, payload)); - } - - public static void doSend(ServerPlayerEntity player, Identifier channel, IOConsumer writer) { - sendPacket(player, makePacket(channel, writer)); - } - - public static void doSend(ServerPlayerEntity player, Identifier channel, PacketByteBuf data) { - sendPacket(player, makePacket(channel, data)); - } - - public static void doSend(Iterable players, Identifier channel, CustomPayload payload) { - sendPacket(players, makePacket(channel, payload)); - } - - public static void doSend(Iterable players, Identifier channel, IOConsumer writer) { - sendPacket(players, makePacket(channel, writer)); - } - - public static void doSend(Iterable players, Identifier channel, PacketByteBuf data) { - sendPacket(players, makePacket(channel, data)); - } - - public static void doSend(int dimension, Identifier channel, CustomPayload payload) { - doSend(collectPlayers(p -> p.dimension == dimension), channel, payload); - } - - public static void doSend(int dimension, Identifier channel, IOConsumer writer) { - doSend(collectPlayers(p -> p.dimension == dimension), channel, writer); - } - - public static void doSend(int dimension, Identifier channel, PacketByteBuf data) { - doSend(collectPlayers(p -> p.dimension == dimension),channel, data); - } - - public static void doSend(Identifier channel, CustomPayload payload) { - doSend(collectPlayers(p -> true), channel, payload); - } - - public static void doSend(Identifier channel, IOConsumer writer) { - doSend(collectPlayers(p -> true), channel, writer); - } - - public static void doSend(Identifier channel, PacketByteBuf data) { - doSend(collectPlayers(p -> true), channel, data); - } - - private static Iterable collectPlayers(Predicate filter) { - return collectPlayers(server.getPlayerManager().getAll(), filter); - } - - private static Iterable collectPlayers(Iterable src, Predicate filter) { - List players = new ArrayList<>(); - - for (ServerPlayerEntity player : src) { - if (filter.test(player)) { - players.add(player); - } - } - - return players; - } - - private static Packet makePacket(Identifier channel, CustomPayload payload) { - return makePacket(channel, payload::write); - } - - private static Packet makePacket(Identifier channel, IOConsumer writer) { - try { - return new CustomPayloadS2CPacket(channel, PacketByteBufs.make(writer)); - } catch (IOException e) { - LOGGER.warn("error writing custom payload to channel \'" + channel + "\'", e); - return null; - } - } - - private static Packet makePacket(Identifier channel, PacketByteBuf data) { - return new CustomPayloadS2CPacket(channel, data); - } - - private static void sendPacket(ServerPlayerEntity player, Packet packet) { - if (packet != null) { - player.networkHandler.sendPacket(packet); - } - } - - private static void sendPacket(Iterable players, Packet packet) { - if (packet != null) { - for (ServerPlayerEntity player : players) { - sendPacket(player, packet); - } - } - } - - private interface Listener { - - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, PacketByteBuf data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mc11w49a-mc12w16a/build.gradle b/libraries/networking/networking-mc11w49a-mc12w16a/build.gradle deleted file mode 100644 index 48639a05..00000000 --- a/libraries/networking/networking-mc11w49a-mc12w16a/build.gradle +++ /dev/null @@ -1,4 +0,0 @@ -setUpModule(project, - 'entrypoints-mcin-20091223-1459-mc1.5.2', - 'lifecycle-events-mc12w01a-mc12w17a' -) diff --git a/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java b/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java deleted file mode 100644 index 237d7e67..00000000 --- a/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java +++ /dev/null @@ -1,13 +0,0 @@ -package net.ornithemc.osl.networking.api; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; - -public interface CustomPayload { - - void read(DataInputStream input) throws IOException; - - void write(DataOutputStream output) throws IOException; - -} diff --git a/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java b/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java deleted file mode 100644 index f68e894c..00000000 --- a/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java +++ /dev/null @@ -1,23 +0,0 @@ -package net.ornithemc.osl.networking.api; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; - -public final class DataStreams { - - public static DataInputStream input(byte[] bytes) { - return new DataInputStream(new ByteArrayInputStream(bytes == null ? new byte[0] : bytes)); - } - - public static ByteArrayOutputStream output(IOConsumer writer) throws IOException { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - DataOutputStream os = new DataOutputStream(bos); - writer.accept(os); - return bos; - } -} diff --git a/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java b/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java deleted file mode 100644 index f0963ed6..00000000 --- a/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java +++ /dev/null @@ -1,70 +0,0 @@ -package net.ornithemc.osl.networking.api.client; - -import java.util.function.Consumer; - -import net.minecraft.client.Minecraft; - -import net.ornithemc.osl.core.api.events.Event; - -/** - * Events related to the client side of a client-server connection. - */ -public class ClientConnectionEvents { - - /** - * This event is fired after a successful login occurs. - * - *

- * Note that channel registration happens after login, - * and until then data cannot safely be sent to the server. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ClientConnectionEvents.LOGIN.register(minecraft -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> LOGIN = Event.consumer(); - /** - * This event is fired after login, once channel registration is complete. - * - *

- * This marks the moment data can safely be sent to the server. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ClientConnectionEvents.PLAY_READY.register(minecraft -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> PLAY_READY = Event.consumer(); - /** - * This event is fired when the client disconnects from the server. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ClientConnectionEvents.DISCONNECT.register(minecraft -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> DISCONNECT = Event.consumer(); - -} diff --git a/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java b/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java deleted file mode 100644 index e1594802..00000000 --- a/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java +++ /dev/null @@ -1,158 +0,0 @@ -package net.ornithemc.osl.networking.api.client; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.function.Supplier; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.network.handler.ClientNetworkHandler; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; - -public final class ClientPlayNetworking { - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - ClientPlayNetworkingImpl.registerListener(channel, initializer, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListener(String channel, StreamListener listener) { - ClientPlayNetworkingImpl.registerListener(channel, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - ClientPlayNetworkingImpl.registerListenerRaw(channel, listener); - } - - /** - * Remove the listener registered to the given channel. - */ - public static void unregisterListener(String channel) { - ClientPlayNetworkingImpl.unregisterListener(channel); - } - - /** - * Check whether the connection is ready for data to be sent to the server. - */ - public static boolean isPlayReady() { - return ClientPlayNetworkingImpl.isPlayReady(); - } - - /** - * Check whether the given channel is open for data to be sent through it. - * This method will return {@code false} if the client is not connected to a - * server, or if the server has no listeners for the given channel. - */ - public static boolean canSend(String channel) { - return ClientPlayNetworkingImpl.canSend(channel); - } - - /** - * Send a packet to the server through the given channel. The payload will - * only be written if the channel is open. - */ - public static void send(String channel, CustomPayload payload) { - ClientPlayNetworkingImpl.send(channel, payload); - } - - /** - * Send a packet to the server through the given channel. The writer will - * only be called if the channel is open. - */ - public static void send(String channel, IOConsumer writer) { - ClientPlayNetworkingImpl.send(channel, writer); - } - - /** - * Send a packet to the server through the given channel. - */ - public static void send(String channel, byte[] data) { - ClientPlayNetworkingImpl.send(channel, data); - } - - /** - * Send a packet to the server through the given channel, without checking - * whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the server. - */ - public static void doSend(String channel, CustomPayload payload) { - ClientPlayNetworkingImpl.doSend(channel, payload); - } - - /** - * Send a packet to the server through the given channel, without checking - * whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the server. - */ - public static void doSend(String channel, IOConsumer writer) { - ClientPlayNetworkingImpl.doSend(channel, writer); - } - - /** - * Send a packet to the server through the given channel, without checking - * whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the server. - */ - public static void doSend(String channel, byte[] data) { - ClientPlayNetworkingImpl.doSend(channel, data); - } - - public interface PayloadListener { - - /** - * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(Minecraft minecraft, ClientNetworkHandler handler, T payload) throws IOException; - - } - - public interface StreamListener { - - /** - * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(Minecraft minecraft, ClientNetworkHandler handler, DataInputStream data) throws IOException; - - } - - public interface ByteArrayListener { - - /** - * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(Minecraft minecraft, ClientNetworkHandler handler, byte[] data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java b/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java deleted file mode 100644 index dbe85275..00000000 --- a/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java +++ /dev/null @@ -1,71 +0,0 @@ -package net.ornithemc.osl.networking.api.server; - -import java.util.function.BiConsumer; - -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.entity.mob.player.ServerPlayerEntity; - -import net.ornithemc.osl.core.api.events.Event; - -/** - * Events related to the server side of a client-server connection. - */ -public class ServerConnectionEvents { - - /** - * This event is fired after a successful login occurs. - * - *

- * Note that channel registration happens after login, - * and until then data cannot safely be sent to the client. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ServerConnectionEvents.LOGIN.register((server, player) -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> LOGIN = Event.biConsumer(); - /** - * This event is fired after login, once channel registration is complete. - * - *

- * This marks the moment data can safely be sent to the client. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ServerConnectionEvents.PLAY_READY.register((server, player) -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> PLAY_READY = Event.biConsumer(); - /** - * This event is fired when a client disconnects from the server. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ServerConnectionEvents.DISCONNECT.register((server, player) -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> DISCONNECT = Event.biConsumer(); - -} diff --git a/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java b/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java deleted file mode 100644 index 7eda8cca..00000000 --- a/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java +++ /dev/null @@ -1,321 +0,0 @@ -package net.ornithemc.osl.networking.api.server; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.function.Supplier; - -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.entity.mob.player.ServerPlayerEntity; -import net.minecraft.server.network.handler.ServerPlayNetworkHandler; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -public final class ServerPlayNetworking { - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - ServerPlayNetworkingImpl.registerListener(channel, initializer, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListener(String channel, StreamListener listener) { - ServerPlayNetworkingImpl.registerListener(channel, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - ServerPlayNetworkingImpl.registerListenerRaw(channel, listener); - } - - /** - * Remove the listener registered to the given channel. - */ - public static void unregisterListener(String channel) { - ServerPlayNetworkingImpl.unregisterListener(channel); - } - - /** - * Check whether the connection is ready for data to be sent to the client. - */ - public static boolean isPlayReady(ServerPlayerEntity player) { - return ServerPlayNetworkingImpl.isPlayReady(player); - } - - /** - * Check whether the given channel is open for data to be sent through it. - * This method will return {@code false} if the client has no listeners for - * the given channel. - */ - public static boolean canSend(ServerPlayerEntity player, String channel) { - return ServerPlayNetworkingImpl.canSend(player, channel); - } - - /** - * Send a packet to the given player through the given channel. The payload - * will only be written if the channel is open. - */ - public static void send(ServerPlayerEntity player, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.send(player, channel, payload); - } - - /** - * Send a packet to the given player through the given channel. The writer - * will only be called if the channel is open. - */ - public static void send(ServerPlayerEntity player, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.send(player, channel, writer); - } - - /** - * Send a packet to the given player through the given channel. - */ - public static void send(ServerPlayerEntity player, String channel, byte[] data) { - ServerPlayNetworkingImpl.send(player, channel, data); - } - - /** - * Send a packet to the given players through the given channel. The payload - * will only be written if the channel is open for at least one player. - */ - public static void send(Iterable players, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.send(players, channel, payload); - } - - /** - * Send a packet to the given players through the given channel. The writer - * will only be called if the channel is open for at least one player. - */ - public static void send(Iterable players, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.send(players, channel, writer); - } - - /** - * Send a packet to the given players through the given channel. - */ - public static void send(Iterable players, String channel, byte[] data) { - ServerPlayNetworkingImpl.send(players, channel, data); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel. The payload will only be written if the channel is open for at - * least one player. - */ - public static void send(int dimension, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.send(dimension, channel, payload); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel. The writer will only be called if the channel is open for at - * least one player. - */ - public static void send(int dimension, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.send(dimension, channel, writer); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel. - */ - public static void send(int dimension, String channel, byte[] data) { - ServerPlayNetworkingImpl.send(dimension, channel, data); - } - - /** - * Send a packet to all players through the given channel. The payload will - * only be written if the channel is open for at least one player. - */ - public static void send(String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.send(channel, payload); - } - - /** - * Send a packet to all players through the given channel. The writer will - * only be called if the channel is open for at least one player. - */ - public static void send(String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.send(channel, writer); - } - - /** - * Send a packet to all players through the given channel. - */ - public static void send(String channel, byte[] data) { - ServerPlayNetworkingImpl.send(channel, data); - } - - /** - * Send a packet to the given player through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(ServerPlayerEntity player, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(player, channel, payload); - } - - /** - * Send a packet to the given player through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(ServerPlayerEntity player, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(player, channel, writer); - } - - /** - * Send a packet to the given player through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(ServerPlayerEntity player, String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(player, channel, data); - } - - /** - * Send a packet to the given players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(Iterable players, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(players, channel, payload); - } - - /** - * Send a packet to the given players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(Iterable players, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(players, channel, writer); - } - - /** - * Send a packet to the given players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(Iterable players, String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(players, channel, data); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel, without checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(int dimension, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(dimension, channel, payload); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel, without checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(int dimension, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(dimension, channel, writer); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel, without checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(int dimension, String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(dimension, channel, data); - } - - /** - * Send a packet to all players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(channel, payload); - } - - /** - * Send a packet to all players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(channel, writer); - } - - /** - * Send a packet to all players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(channel, data); - } - - public interface PayloadListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, T payload) throws IOException; - - } - - public interface StreamListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, DataInputStream data) throws IOException; - - } - - public interface ByteArrayListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java b/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java deleted file mode 100644 index 18cff165..00000000 --- a/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java +++ /dev/null @@ -1,57 +0,0 @@ -package net.ornithemc.osl.networking.impl; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.LinkedHashSet; -import java.util.Set; - -import net.minecraft.network.packet.Packet; - -import net.ornithemc.osl.networking.api.Channels; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -public class HandshakePayload implements CustomPayload { - - public static final String CHANNEL = "OSL|Handshake"; - - public Set channels; - - public HandshakePayload() { - } - - public HandshakePayload(Set channels) { - this.channels = channels; - } - - public static HandshakePayload client() { - return new HandshakePayload(ClientPlayNetworkingImpl.LISTENERS.keySet()); - } - - public static HandshakePayload server() { - return new HandshakePayload(ServerPlayNetworkingImpl.LISTENERS.keySet()); - } - - @Override - public void read(DataInputStream input) throws IOException { - channels = new LinkedHashSet<>(); - int channelCount = input.readInt(); - - if (channelCount > 0) { - for (int i = 0; i < channelCount; i++) { - channels.add(Packet.readString(input, Channels.MAX_LENGTH)); - } - } - } - - @Override - public void write(DataOutputStream output) throws IOException { - output.writeInt(channels.size()); - - for (String channel : channels) { - Packet.writeString(channel, output); - } - } -} diff --git a/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java deleted file mode 100644 index 86a22831..00000000 --- a/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java +++ /dev/null @@ -1,57 +0,0 @@ -package net.ornithemc.osl.networking.impl; - -import net.ornithemc.osl.entrypoints.api.ModInitializer; -import net.ornithemc.osl.entrypoints.api.client.ClientModInitializer; -import net.ornithemc.osl.entrypoints.api.server.ServerModInitializer; -import net.ornithemc.osl.lifecycle.api.client.MinecraftClientEvents; -import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; -import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking; -import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking; -import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -public class Networking implements ModInitializer, ClientModInitializer, ServerModInitializer { - - @Override - public void init() { - // empty impl - } - - @Override - public void initClient() { - MinecraftClientEvents.START.register(minecraft -> { - ClientPlayNetworkingImpl.setUp(minecraft); - }); - MinecraftClientEvents.STOP.register(minecraft -> { - ClientPlayNetworkingImpl.destroy(minecraft); - }); - ClientPlayNetworking.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { - ((INetworkHandler)handler).osl$networking$registerChannels(payload.channels); - ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); - - return true; - }); - } - - @Override - public void initServer() { - MinecraftServerEvents.START.register(server -> { - ServerPlayNetworkingImpl.setUp(server); - }); - MinecraftServerEvents.STOP.register(server -> { - ServerPlayNetworkingImpl.destroy(server); - }); - ServerPlayNetworking.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { - // send channel registration data as a response to receiving client channel registration data - ServerPlayNetworkingImpl.doSend(player, HandshakePayload.CHANNEL, HandshakePayload.server()); - - ((INetworkHandler)handler).osl$networking$registerChannels(payload.channels); - ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); - - return true; - }); - } -} diff --git a/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java b/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java deleted file mode 100644 index 6371ab97..00000000 --- a/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java +++ /dev/null @@ -1,179 +0,0 @@ -package net.ornithemc.osl.networking.impl.client; - -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.function.Supplier; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.network.handler.ClientNetworkHandler; -import net.minecraft.network.packet.CustomPayloadPacket; -import net.minecraft.network.packet.Packet; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.Channels; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.api.DataStreams; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.ByteArrayListener; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.PayloadListener; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.StreamListener; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; - -public final class ClientPlayNetworkingImpl { - - private static final Logger LOGGER = LogManager.getLogger("OSL|Client Play Networking"); - - private static Minecraft minecraft; - - public static void setUp(Minecraft minecraft) { - if (ClientPlayNetworkingImpl.minecraft == minecraft) { - throw new IllegalStateException("tried to set up client networking when it was already set up!"); - } - - ClientPlayNetworkingImpl.minecraft = minecraft; - } - - public static void destroy(Minecraft minecraft) { - if (ClientPlayNetworkingImpl.minecraft != minecraft) { - throw new IllegalStateException("tried to destroy client networking when it was not set up!"); - } - - ClientPlayNetworkingImpl.minecraft = null; - } - - public static final Map LISTENERS = new LinkedHashMap<>(); - - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - registerListenerImpl(channel, (minecraft, handler, data) -> { - T payload = initializer.get(); - payload.read(DataStreams.input(data)); - - return listener.handle(minecraft, handler, payload); - }); - } - - public static void registerListener(String channel, StreamListener listener) { - registerListenerImpl(channel, (minecraft, handler, data) -> { - return listener.handle(minecraft, handler, DataStreams.input(data)); - }); - } - - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - registerListenerImpl(channel, listener::handle); - } - - private static void registerListenerImpl(String channel, Listener listener) { - LISTENERS.compute(channel, (key, value) -> { - Channels.validate(channel); - - if (value != null) { - throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); - } - - return listener; - }); - } - - public static void unregisterListener(String channel) { - LISTENERS.remove(channel); - } - - public static boolean handle(Minecraft minecraft, ClientNetworkHandler handler, CustomPayloadPacket packet) { - Listener listener = LISTENERS.get(packet.channel); - - if (listener != null) { - try { - return listener.handle(minecraft, handler, packet.data); - } catch (IOException e) { - LOGGER.warn("error handling custom payload on channel \'" + packet.channel + "\'", e); - return true; - } - } - - return false; - } - - public static boolean isPlayReady() { - INetworkHandler handler = (INetworkHandler)minecraft.getNetworkHandler(); - return handler != null && handler.osl$networking$isPlayReady(); - } - - public static boolean canSend(String channel) { - INetworkHandler handler = (INetworkHandler)minecraft.getNetworkHandler(); - return handler != null && handler.osl$networking$isRegisteredChannel(channel); - } - - public static void send(String channel, CustomPayload payload) { - if (canSend(channel)) { - doSend(channel, payload); - } - } - - public static void send(String channel, IOConsumer writer) { - if (canSend(channel)) { - doSend(channel, writer); - } - } - - public static void send(String channel, byte[] data) { - if (canSend(channel)) { - doSend(channel, data); - } - } - - public static void doSend(String channel, CustomPayload payload) { - sendPacket(makePacket(channel, payload)); - } - - public static void doSend(String channel, IOConsumer writer) { - sendPacket(makePacket(channel, writer)); - } - - public static void doSend(String channel, byte[] data) { - sendPacket(makePacket(channel, data)); - } - - private static Packet makePacket(String channel, CustomPayload payload) { - return makePacket(channel, payload::write); - } - - private static Packet makePacket(String channel, IOConsumer writer) { - try { - return makePacket(channel, DataStreams.output(writer).toByteArray()); - } catch (IOException e) { - LOGGER.warn("error writing custom payload to channel \'" + channel + "\'", e); - return null; - } - } - - private static Packet makePacket(String channel, byte[] data) { - CustomPayloadPacket packet = new CustomPayloadPacket(); - - packet.channel = channel; - packet.data = data; - if (data != null) { - packet.size = data.length; - if (packet.size > 32767) { - throw new IllegalArgumentException("Payload may not be larger than 32k"); - } - } - - return packet; - } - - private static void sendPacket(Packet packet) { - if (packet != null) { - minecraft.getNetworkHandler().sendPacket(packet); - } - } - - private interface Listener { - - boolean handle(Minecraft minecraft, ClientNetworkHandler handler, byte[] data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadPacketMixin.java b/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadPacketMixin.java deleted file mode 100644 index 64e9d6b1..00000000 --- a/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadPacketMixin.java +++ /dev/null @@ -1,23 +0,0 @@ -package net.ornithemc.osl.networking.impl.mixin.common; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.Constant; -import org.spongepowered.asm.mixin.injection.ModifyConstant; - -import net.minecraft.network.packet.CustomPayloadPacket; - -import net.ornithemc.osl.networking.api.Channels; - -@Mixin(CustomPayloadPacket.class) -public class CustomPayloadPacketMixin { - - @ModifyConstant( - method = "read", - constant = @Constant( - intValue = 16 - ) - ) - private int osl$networking$modifyMaxChannelLength(int maxLength) { - return Channels.MAX_LENGTH; - } -} diff --git a/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java b/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java deleted file mode 100644 index 4d56cdbb..00000000 --- a/libraries/networking/networking-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java +++ /dev/null @@ -1,280 +0,0 @@ -package net.ornithemc.osl.networking.impl.server; - -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.function.Supplier; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import net.minecraft.network.packet.CustomPayloadPacket; -import net.minecraft.network.packet.Packet; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.entity.mob.player.ServerPlayerEntity; -import net.minecraft.server.network.handler.ServerPlayNetworkHandler; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.Channels; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.api.DataStreams; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.ByteArrayListener; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.PayloadListener; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.StreamListener; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; - -public final class ServerPlayNetworkingImpl { - - private static final Logger LOGGER = LogManager.getLogger("OSL|Server Play Networking"); - - private static MinecraftServer server; - - public static void setUp(MinecraftServer server) { - if (ServerPlayNetworkingImpl.server == server) { - throw new IllegalStateException("tried to set up server networking when it was already set up!"); - } - - ServerPlayNetworkingImpl.server = server; - } - - public static void destroy(MinecraftServer server) { - if (ServerPlayNetworkingImpl.server != server) { - throw new IllegalStateException("tried to destroy server networking when it was not set up!"); - } - - ServerPlayNetworkingImpl.server = null; - } - - public static final Map LISTENERS = new LinkedHashMap<>(); - - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - registerListenerImpl(channel, (server, handler, player, data) -> { - T payload = initializer.get(); - payload.read(DataStreams.input(data)); - - return listener.handle(server, handler, player, payload); - }); - } - - public static void registerListener(String channel, StreamListener listener) { - registerListenerImpl(channel, (server, handler, player, data) -> { - return listener.handle(server, handler, player, DataStreams.input(data)); - }); - } - - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - registerListenerImpl(channel, listener::handle); - } - - private static void registerListenerImpl(String channel, Listener listener) { - LISTENERS.compute(channel, (key, value) -> { - Channels.validate(channel); - - if (value != null) { - throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); - } - - return listener; - }); - } - - public static void unregisterListener(String channel) { - LISTENERS.remove(channel); - } - - public static boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, CustomPayloadPacket packet) { - Listener listener = LISTENERS.get(packet.channel); - - if (listener != null) { - try { - return listener.handle(server, handler, player, packet.data); - } catch (IOException e) { - LOGGER.warn("error handling custom payload on channel \'" + packet.channel + "\'", e); - return true; - } - } - - return false; - } - - public static boolean isPlayReady(ServerPlayerEntity player) { - INetworkHandler handler = (INetworkHandler)player.networkHandler; - return handler != null && handler.osl$networking$isPlayReady(); - } - - public static boolean canSend(ServerPlayerEntity player, String channel) { - INetworkHandler handler = (INetworkHandler)player.networkHandler; - return handler != null && handler.osl$networking$isRegisteredChannel(channel); - } - - public static void send(ServerPlayerEntity player, String channel, CustomPayload payload) { - if (canSend(player, channel)) { - doSend(player, channel, payload); - } - } - - public static void send(ServerPlayerEntity player, String channel, IOConsumer writer) { - if (canSend(player, channel)) { - doSend(player, channel, writer); - } - } - - public static void send(ServerPlayerEntity player, String channel, byte[] data) { - if (canSend(player, channel)) { - doSend(player, channel, data); - } - } - - public static void send(Iterable players, String channel, CustomPayload payload) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, payload)); - } - - public static void send(Iterable players, String channel, IOConsumer writer) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, writer)); - } - - public static void send(Iterable players, String channel, byte[] data) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, data)); - } - - public static void send(int dimension, String channel, CustomPayload payload) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)), channel, payload); - } - - public static void send(int dimension, String channel, IOConsumer writer) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)), channel, writer); - } - - public static void send(int dimension, String channel, byte[] data) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)),channel, data); - } - - public static void send(String channel, CustomPayload payload) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, payload); - } - - public static void send(String channel, IOConsumer writer) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, writer); - } - - public static void send(String channel, byte[] data) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, data); - } - - public static void doSend(ServerPlayerEntity player, String channel, CustomPayload payload) { - sendPacket(player, makePacket(channel, payload)); - } - - public static void doSend(ServerPlayerEntity player, String channel, IOConsumer writer) { - sendPacket(player, makePacket(channel, writer)); - } - - public static void doSend(ServerPlayerEntity player, String channel, byte[] data) { - sendPacket(player, makePacket(channel, data)); - } - - public static void doSend(Iterable players, String channel, CustomPayload payload) { - sendPacket(players, makePacket(channel, payload)); - } - - public static void doSend(Iterable players, String channel, IOConsumer writer) { - sendPacket(players, makePacket(channel, writer)); - } - - public static void doSend(Iterable players, String channel, byte[] data) { - sendPacket(players, makePacket(channel, data)); - } - - public static void doSend(int dimension, String channel, CustomPayload payload) { - doSend(collectPlayers(p -> p.dimension == dimension), channel, payload); - } - - public static void doSend(int dimension, String channel, IOConsumer writer) { - doSend(collectPlayers(p -> p.dimension == dimension), channel, writer); - } - - public static void doSend(int dimension, String channel, byte[] data) { - doSend(collectPlayers(p -> p.dimension == dimension),channel, data); - } - - public static void doSend(String channel, CustomPayload payload) { - doSend(collectPlayers(p -> true), channel, payload); - } - - public static void doSend(String channel, IOConsumer writer) { - doSend(collectPlayers(p -> true), channel, writer); - } - - public static void doSend(String channel, byte[] data) { - doSend(collectPlayers(p -> true), channel, data); - } - - @SuppressWarnings("unchecked") // thanks proguard - private static Iterable collectPlayers(Predicate filter) { - return collectPlayers(server.playerManager.players, filter); - } - - private static Iterable collectPlayers(Iterable src, Predicate filter) { - List players = new ArrayList<>(); - - for (ServerPlayerEntity player : src) { - if (filter.test(player)) { - players.add(player); - } - } - - return players; - } - - private static Packet makePacket(String channel, CustomPayload payload) { - return makePacket(channel, payload::write); - } - - private static Packet makePacket(String channel, IOConsumer writer) { - try { - return makePacket(channel, DataStreams.output(writer).toByteArray()); - } catch (IOException e) { - LOGGER.warn("error writing custom payload to channel \'" + channel + "\'", e); - return null; - } - } - - private static Packet makePacket(String channel, byte[] data) { - CustomPayloadPacket packet = new CustomPayloadPacket(); - - packet.channel = channel; - packet.data = data; - if (data != null) { - packet.size = data.length; - if (packet.size > Short.MAX_VALUE) { - throw new IllegalArgumentException("Payload may not be larger than 32k"); - } - } - - return packet; - } - - private static void sendPacket(ServerPlayerEntity player, Packet packet) { - if (packet != null) { - player.networkHandler.sendPacket(packet); - } - } - - private static void sendPacket(Iterable players, Packet packet) { - if (packet != null) { - for (ServerPlayerEntity player : players) { - sendPacket(player, packet); - } - } - } - - private interface Listener { - - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mc12w17a-mc12w17a/build.gradle b/libraries/networking/networking-mc12w17a-mc12w17a/build.gradle deleted file mode 100644 index 48639a05..00000000 --- a/libraries/networking/networking-mc12w17a-mc12w17a/build.gradle +++ /dev/null @@ -1,4 +0,0 @@ -setUpModule(project, - 'entrypoints-mcin-20091223-1459-mc1.5.2', - 'lifecycle-events-mc12w01a-mc12w17a' -) diff --git a/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java b/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java deleted file mode 100644 index 237d7e67..00000000 --- a/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java +++ /dev/null @@ -1,13 +0,0 @@ -package net.ornithemc.osl.networking.api; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; - -public interface CustomPayload { - - void read(DataInputStream input) throws IOException; - - void write(DataOutputStream output) throws IOException; - -} diff --git a/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java b/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java deleted file mode 100644 index f68e894c..00000000 --- a/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java +++ /dev/null @@ -1,23 +0,0 @@ -package net.ornithemc.osl.networking.api; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; - -public final class DataStreams { - - public static DataInputStream input(byte[] bytes) { - return new DataInputStream(new ByteArrayInputStream(bytes == null ? new byte[0] : bytes)); - } - - public static ByteArrayOutputStream output(IOConsumer writer) throws IOException { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - DataOutputStream os = new DataOutputStream(bos); - writer.accept(os); - return bos; - } -} diff --git a/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java b/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java deleted file mode 100644 index f0963ed6..00000000 --- a/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java +++ /dev/null @@ -1,70 +0,0 @@ -package net.ornithemc.osl.networking.api.client; - -import java.util.function.Consumer; - -import net.minecraft.client.Minecraft; - -import net.ornithemc.osl.core.api.events.Event; - -/** - * Events related to the client side of a client-server connection. - */ -public class ClientConnectionEvents { - - /** - * This event is fired after a successful login occurs. - * - *

- * Note that channel registration happens after login, - * and until then data cannot safely be sent to the server. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ClientConnectionEvents.LOGIN.register(minecraft -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> LOGIN = Event.consumer(); - /** - * This event is fired after login, once channel registration is complete. - * - *

- * This marks the moment data can safely be sent to the server. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ClientConnectionEvents.PLAY_READY.register(minecraft -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> PLAY_READY = Event.consumer(); - /** - * This event is fired when the client disconnects from the server. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ClientConnectionEvents.DISCONNECT.register(minecraft -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> DISCONNECT = Event.consumer(); - -} diff --git a/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java b/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java deleted file mode 100644 index e1594802..00000000 --- a/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java +++ /dev/null @@ -1,158 +0,0 @@ -package net.ornithemc.osl.networking.api.client; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.function.Supplier; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.network.handler.ClientNetworkHandler; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; - -public final class ClientPlayNetworking { - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - ClientPlayNetworkingImpl.registerListener(channel, initializer, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListener(String channel, StreamListener listener) { - ClientPlayNetworkingImpl.registerListener(channel, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - ClientPlayNetworkingImpl.registerListenerRaw(channel, listener); - } - - /** - * Remove the listener registered to the given channel. - */ - public static void unregisterListener(String channel) { - ClientPlayNetworkingImpl.unregisterListener(channel); - } - - /** - * Check whether the connection is ready for data to be sent to the server. - */ - public static boolean isPlayReady() { - return ClientPlayNetworkingImpl.isPlayReady(); - } - - /** - * Check whether the given channel is open for data to be sent through it. - * This method will return {@code false} if the client is not connected to a - * server, or if the server has no listeners for the given channel. - */ - public static boolean canSend(String channel) { - return ClientPlayNetworkingImpl.canSend(channel); - } - - /** - * Send a packet to the server through the given channel. The payload will - * only be written if the channel is open. - */ - public static void send(String channel, CustomPayload payload) { - ClientPlayNetworkingImpl.send(channel, payload); - } - - /** - * Send a packet to the server through the given channel. The writer will - * only be called if the channel is open. - */ - public static void send(String channel, IOConsumer writer) { - ClientPlayNetworkingImpl.send(channel, writer); - } - - /** - * Send a packet to the server through the given channel. - */ - public static void send(String channel, byte[] data) { - ClientPlayNetworkingImpl.send(channel, data); - } - - /** - * Send a packet to the server through the given channel, without checking - * whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the server. - */ - public static void doSend(String channel, CustomPayload payload) { - ClientPlayNetworkingImpl.doSend(channel, payload); - } - - /** - * Send a packet to the server through the given channel, without checking - * whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the server. - */ - public static void doSend(String channel, IOConsumer writer) { - ClientPlayNetworkingImpl.doSend(channel, writer); - } - - /** - * Send a packet to the server through the given channel, without checking - * whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the server. - */ - public static void doSend(String channel, byte[] data) { - ClientPlayNetworkingImpl.doSend(channel, data); - } - - public interface PayloadListener { - - /** - * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(Minecraft minecraft, ClientNetworkHandler handler, T payload) throws IOException; - - } - - public interface StreamListener { - - /** - * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(Minecraft minecraft, ClientNetworkHandler handler, DataInputStream data) throws IOException; - - } - - public interface ByteArrayListener { - - /** - * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(Minecraft minecraft, ClientNetworkHandler handler, byte[] data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java b/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java deleted file mode 100644 index dbe85275..00000000 --- a/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java +++ /dev/null @@ -1,71 +0,0 @@ -package net.ornithemc.osl.networking.api.server; - -import java.util.function.BiConsumer; - -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.entity.mob.player.ServerPlayerEntity; - -import net.ornithemc.osl.core.api.events.Event; - -/** - * Events related to the server side of a client-server connection. - */ -public class ServerConnectionEvents { - - /** - * This event is fired after a successful login occurs. - * - *

- * Note that channel registration happens after login, - * and until then data cannot safely be sent to the client. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ServerConnectionEvents.LOGIN.register((server, player) -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> LOGIN = Event.biConsumer(); - /** - * This event is fired after login, once channel registration is complete. - * - *

- * This marks the moment data can safely be sent to the client. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ServerConnectionEvents.PLAY_READY.register((server, player) -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> PLAY_READY = Event.biConsumer(); - /** - * This event is fired when a client disconnects from the server. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ServerConnectionEvents.DISCONNECT.register((server, player) -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> DISCONNECT = Event.biConsumer(); - -} diff --git a/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java b/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java deleted file mode 100644 index 7eda8cca..00000000 --- a/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java +++ /dev/null @@ -1,321 +0,0 @@ -package net.ornithemc.osl.networking.api.server; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.function.Supplier; - -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.entity.mob.player.ServerPlayerEntity; -import net.minecraft.server.network.handler.ServerPlayNetworkHandler; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -public final class ServerPlayNetworking { - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - ServerPlayNetworkingImpl.registerListener(channel, initializer, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListener(String channel, StreamListener listener) { - ServerPlayNetworkingImpl.registerListener(channel, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - ServerPlayNetworkingImpl.registerListenerRaw(channel, listener); - } - - /** - * Remove the listener registered to the given channel. - */ - public static void unregisterListener(String channel) { - ServerPlayNetworkingImpl.unregisterListener(channel); - } - - /** - * Check whether the connection is ready for data to be sent to the client. - */ - public static boolean isPlayReady(ServerPlayerEntity player) { - return ServerPlayNetworkingImpl.isPlayReady(player); - } - - /** - * Check whether the given channel is open for data to be sent through it. - * This method will return {@code false} if the client has no listeners for - * the given channel. - */ - public static boolean canSend(ServerPlayerEntity player, String channel) { - return ServerPlayNetworkingImpl.canSend(player, channel); - } - - /** - * Send a packet to the given player through the given channel. The payload - * will only be written if the channel is open. - */ - public static void send(ServerPlayerEntity player, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.send(player, channel, payload); - } - - /** - * Send a packet to the given player through the given channel. The writer - * will only be called if the channel is open. - */ - public static void send(ServerPlayerEntity player, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.send(player, channel, writer); - } - - /** - * Send a packet to the given player through the given channel. - */ - public static void send(ServerPlayerEntity player, String channel, byte[] data) { - ServerPlayNetworkingImpl.send(player, channel, data); - } - - /** - * Send a packet to the given players through the given channel. The payload - * will only be written if the channel is open for at least one player. - */ - public static void send(Iterable players, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.send(players, channel, payload); - } - - /** - * Send a packet to the given players through the given channel. The writer - * will only be called if the channel is open for at least one player. - */ - public static void send(Iterable players, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.send(players, channel, writer); - } - - /** - * Send a packet to the given players through the given channel. - */ - public static void send(Iterable players, String channel, byte[] data) { - ServerPlayNetworkingImpl.send(players, channel, data); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel. The payload will only be written if the channel is open for at - * least one player. - */ - public static void send(int dimension, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.send(dimension, channel, payload); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel. The writer will only be called if the channel is open for at - * least one player. - */ - public static void send(int dimension, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.send(dimension, channel, writer); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel. - */ - public static void send(int dimension, String channel, byte[] data) { - ServerPlayNetworkingImpl.send(dimension, channel, data); - } - - /** - * Send a packet to all players through the given channel. The payload will - * only be written if the channel is open for at least one player. - */ - public static void send(String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.send(channel, payload); - } - - /** - * Send a packet to all players through the given channel. The writer will - * only be called if the channel is open for at least one player. - */ - public static void send(String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.send(channel, writer); - } - - /** - * Send a packet to all players through the given channel. - */ - public static void send(String channel, byte[] data) { - ServerPlayNetworkingImpl.send(channel, data); - } - - /** - * Send a packet to the given player through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(ServerPlayerEntity player, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(player, channel, payload); - } - - /** - * Send a packet to the given player through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(ServerPlayerEntity player, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(player, channel, writer); - } - - /** - * Send a packet to the given player through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(ServerPlayerEntity player, String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(player, channel, data); - } - - /** - * Send a packet to the given players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(Iterable players, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(players, channel, payload); - } - - /** - * Send a packet to the given players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(Iterable players, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(players, channel, writer); - } - - /** - * Send a packet to the given players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(Iterable players, String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(players, channel, data); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel, without checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(int dimension, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(dimension, channel, payload); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel, without checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(int dimension, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(dimension, channel, writer); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel, without checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(int dimension, String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(dimension, channel, data); - } - - /** - * Send a packet to all players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(channel, payload); - } - - /** - * Send a packet to all players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(channel, writer); - } - - /** - * Send a packet to all players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(channel, data); - } - - public interface PayloadListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, T payload) throws IOException; - - } - - public interface StreamListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, DataInputStream data) throws IOException; - - } - - public interface ByteArrayListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java b/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java deleted file mode 100644 index 18cff165..00000000 --- a/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java +++ /dev/null @@ -1,57 +0,0 @@ -package net.ornithemc.osl.networking.impl; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.LinkedHashSet; -import java.util.Set; - -import net.minecraft.network.packet.Packet; - -import net.ornithemc.osl.networking.api.Channels; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -public class HandshakePayload implements CustomPayload { - - public static final String CHANNEL = "OSL|Handshake"; - - public Set channels; - - public HandshakePayload() { - } - - public HandshakePayload(Set channels) { - this.channels = channels; - } - - public static HandshakePayload client() { - return new HandshakePayload(ClientPlayNetworkingImpl.LISTENERS.keySet()); - } - - public static HandshakePayload server() { - return new HandshakePayload(ServerPlayNetworkingImpl.LISTENERS.keySet()); - } - - @Override - public void read(DataInputStream input) throws IOException { - channels = new LinkedHashSet<>(); - int channelCount = input.readInt(); - - if (channelCount > 0) { - for (int i = 0; i < channelCount; i++) { - channels.add(Packet.readString(input, Channels.MAX_LENGTH)); - } - } - } - - @Override - public void write(DataOutputStream output) throws IOException { - output.writeInt(channels.size()); - - for (String channel : channels) { - Packet.writeString(channel, output); - } - } -} diff --git a/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java deleted file mode 100644 index 86a22831..00000000 --- a/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java +++ /dev/null @@ -1,57 +0,0 @@ -package net.ornithemc.osl.networking.impl; - -import net.ornithemc.osl.entrypoints.api.ModInitializer; -import net.ornithemc.osl.entrypoints.api.client.ClientModInitializer; -import net.ornithemc.osl.entrypoints.api.server.ServerModInitializer; -import net.ornithemc.osl.lifecycle.api.client.MinecraftClientEvents; -import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; -import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking; -import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking; -import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -public class Networking implements ModInitializer, ClientModInitializer, ServerModInitializer { - - @Override - public void init() { - // empty impl - } - - @Override - public void initClient() { - MinecraftClientEvents.START.register(minecraft -> { - ClientPlayNetworkingImpl.setUp(minecraft); - }); - MinecraftClientEvents.STOP.register(minecraft -> { - ClientPlayNetworkingImpl.destroy(minecraft); - }); - ClientPlayNetworking.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { - ((INetworkHandler)handler).osl$networking$registerChannels(payload.channels); - ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); - - return true; - }); - } - - @Override - public void initServer() { - MinecraftServerEvents.START.register(server -> { - ServerPlayNetworkingImpl.setUp(server); - }); - MinecraftServerEvents.STOP.register(server -> { - ServerPlayNetworkingImpl.destroy(server); - }); - ServerPlayNetworking.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { - // send channel registration data as a response to receiving client channel registration data - ServerPlayNetworkingImpl.doSend(player, HandshakePayload.CHANNEL, HandshakePayload.server()); - - ((INetworkHandler)handler).osl$networking$registerChannels(payload.channels); - ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); - - return true; - }); - } -} diff --git a/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java b/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java deleted file mode 100644 index 6371ab97..00000000 --- a/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java +++ /dev/null @@ -1,179 +0,0 @@ -package net.ornithemc.osl.networking.impl.client; - -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.function.Supplier; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.network.handler.ClientNetworkHandler; -import net.minecraft.network.packet.CustomPayloadPacket; -import net.minecraft.network.packet.Packet; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.Channels; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.api.DataStreams; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.ByteArrayListener; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.PayloadListener; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.StreamListener; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; - -public final class ClientPlayNetworkingImpl { - - private static final Logger LOGGER = LogManager.getLogger("OSL|Client Play Networking"); - - private static Minecraft minecraft; - - public static void setUp(Minecraft minecraft) { - if (ClientPlayNetworkingImpl.minecraft == minecraft) { - throw new IllegalStateException("tried to set up client networking when it was already set up!"); - } - - ClientPlayNetworkingImpl.minecraft = minecraft; - } - - public static void destroy(Minecraft minecraft) { - if (ClientPlayNetworkingImpl.minecraft != minecraft) { - throw new IllegalStateException("tried to destroy client networking when it was not set up!"); - } - - ClientPlayNetworkingImpl.minecraft = null; - } - - public static final Map LISTENERS = new LinkedHashMap<>(); - - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - registerListenerImpl(channel, (minecraft, handler, data) -> { - T payload = initializer.get(); - payload.read(DataStreams.input(data)); - - return listener.handle(minecraft, handler, payload); - }); - } - - public static void registerListener(String channel, StreamListener listener) { - registerListenerImpl(channel, (minecraft, handler, data) -> { - return listener.handle(minecraft, handler, DataStreams.input(data)); - }); - } - - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - registerListenerImpl(channel, listener::handle); - } - - private static void registerListenerImpl(String channel, Listener listener) { - LISTENERS.compute(channel, (key, value) -> { - Channels.validate(channel); - - if (value != null) { - throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); - } - - return listener; - }); - } - - public static void unregisterListener(String channel) { - LISTENERS.remove(channel); - } - - public static boolean handle(Minecraft minecraft, ClientNetworkHandler handler, CustomPayloadPacket packet) { - Listener listener = LISTENERS.get(packet.channel); - - if (listener != null) { - try { - return listener.handle(minecraft, handler, packet.data); - } catch (IOException e) { - LOGGER.warn("error handling custom payload on channel \'" + packet.channel + "\'", e); - return true; - } - } - - return false; - } - - public static boolean isPlayReady() { - INetworkHandler handler = (INetworkHandler)minecraft.getNetworkHandler(); - return handler != null && handler.osl$networking$isPlayReady(); - } - - public static boolean canSend(String channel) { - INetworkHandler handler = (INetworkHandler)minecraft.getNetworkHandler(); - return handler != null && handler.osl$networking$isRegisteredChannel(channel); - } - - public static void send(String channel, CustomPayload payload) { - if (canSend(channel)) { - doSend(channel, payload); - } - } - - public static void send(String channel, IOConsumer writer) { - if (canSend(channel)) { - doSend(channel, writer); - } - } - - public static void send(String channel, byte[] data) { - if (canSend(channel)) { - doSend(channel, data); - } - } - - public static void doSend(String channel, CustomPayload payload) { - sendPacket(makePacket(channel, payload)); - } - - public static void doSend(String channel, IOConsumer writer) { - sendPacket(makePacket(channel, writer)); - } - - public static void doSend(String channel, byte[] data) { - sendPacket(makePacket(channel, data)); - } - - private static Packet makePacket(String channel, CustomPayload payload) { - return makePacket(channel, payload::write); - } - - private static Packet makePacket(String channel, IOConsumer writer) { - try { - return makePacket(channel, DataStreams.output(writer).toByteArray()); - } catch (IOException e) { - LOGGER.warn("error writing custom payload to channel \'" + channel + "\'", e); - return null; - } - } - - private static Packet makePacket(String channel, byte[] data) { - CustomPayloadPacket packet = new CustomPayloadPacket(); - - packet.channel = channel; - packet.data = data; - if (data != null) { - packet.size = data.length; - if (packet.size > 32767) { - throw new IllegalArgumentException("Payload may not be larger than 32k"); - } - } - - return packet; - } - - private static void sendPacket(Packet packet) { - if (packet != null) { - minecraft.getNetworkHandler().sendPacket(packet); - } - } - - private interface Listener { - - boolean handle(Minecraft minecraft, ClientNetworkHandler handler, byte[] data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadPacketMixin.java b/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadPacketMixin.java deleted file mode 100644 index 64e9d6b1..00000000 --- a/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadPacketMixin.java +++ /dev/null @@ -1,23 +0,0 @@ -package net.ornithemc.osl.networking.impl.mixin.common; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.Constant; -import org.spongepowered.asm.mixin.injection.ModifyConstant; - -import net.minecraft.network.packet.CustomPayloadPacket; - -import net.ornithemc.osl.networking.api.Channels; - -@Mixin(CustomPayloadPacket.class) -public class CustomPayloadPacketMixin { - - @ModifyConstant( - method = "read", - constant = @Constant( - intValue = 16 - ) - ) - private int osl$networking$modifyMaxChannelLength(int maxLength) { - return Channels.MAX_LENGTH; - } -} diff --git a/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java b/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java deleted file mode 100644 index 4d56cdbb..00000000 --- a/libraries/networking/networking-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java +++ /dev/null @@ -1,280 +0,0 @@ -package net.ornithemc.osl.networking.impl.server; - -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.function.Supplier; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import net.minecraft.network.packet.CustomPayloadPacket; -import net.minecraft.network.packet.Packet; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.entity.mob.player.ServerPlayerEntity; -import net.minecraft.server.network.handler.ServerPlayNetworkHandler; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.Channels; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.api.DataStreams; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.ByteArrayListener; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.PayloadListener; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.StreamListener; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; - -public final class ServerPlayNetworkingImpl { - - private static final Logger LOGGER = LogManager.getLogger("OSL|Server Play Networking"); - - private static MinecraftServer server; - - public static void setUp(MinecraftServer server) { - if (ServerPlayNetworkingImpl.server == server) { - throw new IllegalStateException("tried to set up server networking when it was already set up!"); - } - - ServerPlayNetworkingImpl.server = server; - } - - public static void destroy(MinecraftServer server) { - if (ServerPlayNetworkingImpl.server != server) { - throw new IllegalStateException("tried to destroy server networking when it was not set up!"); - } - - ServerPlayNetworkingImpl.server = null; - } - - public static final Map LISTENERS = new LinkedHashMap<>(); - - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - registerListenerImpl(channel, (server, handler, player, data) -> { - T payload = initializer.get(); - payload.read(DataStreams.input(data)); - - return listener.handle(server, handler, player, payload); - }); - } - - public static void registerListener(String channel, StreamListener listener) { - registerListenerImpl(channel, (server, handler, player, data) -> { - return listener.handle(server, handler, player, DataStreams.input(data)); - }); - } - - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - registerListenerImpl(channel, listener::handle); - } - - private static void registerListenerImpl(String channel, Listener listener) { - LISTENERS.compute(channel, (key, value) -> { - Channels.validate(channel); - - if (value != null) { - throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); - } - - return listener; - }); - } - - public static void unregisterListener(String channel) { - LISTENERS.remove(channel); - } - - public static boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, CustomPayloadPacket packet) { - Listener listener = LISTENERS.get(packet.channel); - - if (listener != null) { - try { - return listener.handle(server, handler, player, packet.data); - } catch (IOException e) { - LOGGER.warn("error handling custom payload on channel \'" + packet.channel + "\'", e); - return true; - } - } - - return false; - } - - public static boolean isPlayReady(ServerPlayerEntity player) { - INetworkHandler handler = (INetworkHandler)player.networkHandler; - return handler != null && handler.osl$networking$isPlayReady(); - } - - public static boolean canSend(ServerPlayerEntity player, String channel) { - INetworkHandler handler = (INetworkHandler)player.networkHandler; - return handler != null && handler.osl$networking$isRegisteredChannel(channel); - } - - public static void send(ServerPlayerEntity player, String channel, CustomPayload payload) { - if (canSend(player, channel)) { - doSend(player, channel, payload); - } - } - - public static void send(ServerPlayerEntity player, String channel, IOConsumer writer) { - if (canSend(player, channel)) { - doSend(player, channel, writer); - } - } - - public static void send(ServerPlayerEntity player, String channel, byte[] data) { - if (canSend(player, channel)) { - doSend(player, channel, data); - } - } - - public static void send(Iterable players, String channel, CustomPayload payload) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, payload)); - } - - public static void send(Iterable players, String channel, IOConsumer writer) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, writer)); - } - - public static void send(Iterable players, String channel, byte[] data) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, data)); - } - - public static void send(int dimension, String channel, CustomPayload payload) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)), channel, payload); - } - - public static void send(int dimension, String channel, IOConsumer writer) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)), channel, writer); - } - - public static void send(int dimension, String channel, byte[] data) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)),channel, data); - } - - public static void send(String channel, CustomPayload payload) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, payload); - } - - public static void send(String channel, IOConsumer writer) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, writer); - } - - public static void send(String channel, byte[] data) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, data); - } - - public static void doSend(ServerPlayerEntity player, String channel, CustomPayload payload) { - sendPacket(player, makePacket(channel, payload)); - } - - public static void doSend(ServerPlayerEntity player, String channel, IOConsumer writer) { - sendPacket(player, makePacket(channel, writer)); - } - - public static void doSend(ServerPlayerEntity player, String channel, byte[] data) { - sendPacket(player, makePacket(channel, data)); - } - - public static void doSend(Iterable players, String channel, CustomPayload payload) { - sendPacket(players, makePacket(channel, payload)); - } - - public static void doSend(Iterable players, String channel, IOConsumer writer) { - sendPacket(players, makePacket(channel, writer)); - } - - public static void doSend(Iterable players, String channel, byte[] data) { - sendPacket(players, makePacket(channel, data)); - } - - public static void doSend(int dimension, String channel, CustomPayload payload) { - doSend(collectPlayers(p -> p.dimension == dimension), channel, payload); - } - - public static void doSend(int dimension, String channel, IOConsumer writer) { - doSend(collectPlayers(p -> p.dimension == dimension), channel, writer); - } - - public static void doSend(int dimension, String channel, byte[] data) { - doSend(collectPlayers(p -> p.dimension == dimension),channel, data); - } - - public static void doSend(String channel, CustomPayload payload) { - doSend(collectPlayers(p -> true), channel, payload); - } - - public static void doSend(String channel, IOConsumer writer) { - doSend(collectPlayers(p -> true), channel, writer); - } - - public static void doSend(String channel, byte[] data) { - doSend(collectPlayers(p -> true), channel, data); - } - - @SuppressWarnings("unchecked") // thanks proguard - private static Iterable collectPlayers(Predicate filter) { - return collectPlayers(server.playerManager.players, filter); - } - - private static Iterable collectPlayers(Iterable src, Predicate filter) { - List players = new ArrayList<>(); - - for (ServerPlayerEntity player : src) { - if (filter.test(player)) { - players.add(player); - } - } - - return players; - } - - private static Packet makePacket(String channel, CustomPayload payload) { - return makePacket(channel, payload::write); - } - - private static Packet makePacket(String channel, IOConsumer writer) { - try { - return makePacket(channel, DataStreams.output(writer).toByteArray()); - } catch (IOException e) { - LOGGER.warn("error writing custom payload to channel \'" + channel + "\'", e); - return null; - } - } - - private static Packet makePacket(String channel, byte[] data) { - CustomPayloadPacket packet = new CustomPayloadPacket(); - - packet.channel = channel; - packet.data = data; - if (data != null) { - packet.size = data.length; - if (packet.size > Short.MAX_VALUE) { - throw new IllegalArgumentException("Payload may not be larger than 32k"); - } - } - - return packet; - } - - private static void sendPacket(ServerPlayerEntity player, Packet packet) { - if (packet != null) { - player.networkHandler.sendPacket(packet); - } - } - - private static void sendPacket(Iterable players, Packet packet) { - if (packet != null) { - for (ServerPlayerEntity player : players) { - sendPacket(player, packet); - } - } - } - - private interface Listener { - - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mc12w18a-mc12w19a/build.gradle b/libraries/networking/networking-mc12w18a-mc12w19a/build.gradle deleted file mode 100644 index a722cfca..00000000 --- a/libraries/networking/networking-mc12w18a-mc12w19a/build.gradle +++ /dev/null @@ -1,4 +0,0 @@ -setUpModule(project, - 'entrypoints-mcin-20091223-1459-mc1.5.2', - 'lifecycle-events-mc12w18a-mc12w19a' -) diff --git a/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java b/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java deleted file mode 100644 index 237d7e67..00000000 --- a/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java +++ /dev/null @@ -1,13 +0,0 @@ -package net.ornithemc.osl.networking.api; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; - -public interface CustomPayload { - - void read(DataInputStream input) throws IOException; - - void write(DataOutputStream output) throws IOException; - -} diff --git a/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java b/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java deleted file mode 100644 index f68e894c..00000000 --- a/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java +++ /dev/null @@ -1,23 +0,0 @@ -package net.ornithemc.osl.networking.api; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; - -public final class DataStreams { - - public static DataInputStream input(byte[] bytes) { - return new DataInputStream(new ByteArrayInputStream(bytes == null ? new byte[0] : bytes)); - } - - public static ByteArrayOutputStream output(IOConsumer writer) throws IOException { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - DataOutputStream os = new DataOutputStream(bos); - writer.accept(os); - return bos; - } -} diff --git a/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java b/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java deleted file mode 100644 index e1594802..00000000 --- a/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java +++ /dev/null @@ -1,158 +0,0 @@ -package net.ornithemc.osl.networking.api.client; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.function.Supplier; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.network.handler.ClientNetworkHandler; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; - -public final class ClientPlayNetworking { - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - ClientPlayNetworkingImpl.registerListener(channel, initializer, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListener(String channel, StreamListener listener) { - ClientPlayNetworkingImpl.registerListener(channel, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - ClientPlayNetworkingImpl.registerListenerRaw(channel, listener); - } - - /** - * Remove the listener registered to the given channel. - */ - public static void unregisterListener(String channel) { - ClientPlayNetworkingImpl.unregisterListener(channel); - } - - /** - * Check whether the connection is ready for data to be sent to the server. - */ - public static boolean isPlayReady() { - return ClientPlayNetworkingImpl.isPlayReady(); - } - - /** - * Check whether the given channel is open for data to be sent through it. - * This method will return {@code false} if the client is not connected to a - * server, or if the server has no listeners for the given channel. - */ - public static boolean canSend(String channel) { - return ClientPlayNetworkingImpl.canSend(channel); - } - - /** - * Send a packet to the server through the given channel. The payload will - * only be written if the channel is open. - */ - public static void send(String channel, CustomPayload payload) { - ClientPlayNetworkingImpl.send(channel, payload); - } - - /** - * Send a packet to the server through the given channel. The writer will - * only be called if the channel is open. - */ - public static void send(String channel, IOConsumer writer) { - ClientPlayNetworkingImpl.send(channel, writer); - } - - /** - * Send a packet to the server through the given channel. - */ - public static void send(String channel, byte[] data) { - ClientPlayNetworkingImpl.send(channel, data); - } - - /** - * Send a packet to the server through the given channel, without checking - * whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the server. - */ - public static void doSend(String channel, CustomPayload payload) { - ClientPlayNetworkingImpl.doSend(channel, payload); - } - - /** - * Send a packet to the server through the given channel, without checking - * whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the server. - */ - public static void doSend(String channel, IOConsumer writer) { - ClientPlayNetworkingImpl.doSend(channel, writer); - } - - /** - * Send a packet to the server through the given channel, without checking - * whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the server. - */ - public static void doSend(String channel, byte[] data) { - ClientPlayNetworkingImpl.doSend(channel, data); - } - - public interface PayloadListener { - - /** - * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(Minecraft minecraft, ClientNetworkHandler handler, T payload) throws IOException; - - } - - public interface StreamListener { - - /** - * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(Minecraft minecraft, ClientNetworkHandler handler, DataInputStream data) throws IOException; - - } - - public interface ByteArrayListener { - - /** - * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(Minecraft minecraft, ClientNetworkHandler handler, byte[] data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java b/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java deleted file mode 100644 index 7eda8cca..00000000 --- a/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java +++ /dev/null @@ -1,321 +0,0 @@ -package net.ornithemc.osl.networking.api.server; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.function.Supplier; - -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.entity.mob.player.ServerPlayerEntity; -import net.minecraft.server.network.handler.ServerPlayNetworkHandler; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -public final class ServerPlayNetworking { - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - ServerPlayNetworkingImpl.registerListener(channel, initializer, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListener(String channel, StreamListener listener) { - ServerPlayNetworkingImpl.registerListener(channel, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - ServerPlayNetworkingImpl.registerListenerRaw(channel, listener); - } - - /** - * Remove the listener registered to the given channel. - */ - public static void unregisterListener(String channel) { - ServerPlayNetworkingImpl.unregisterListener(channel); - } - - /** - * Check whether the connection is ready for data to be sent to the client. - */ - public static boolean isPlayReady(ServerPlayerEntity player) { - return ServerPlayNetworkingImpl.isPlayReady(player); - } - - /** - * Check whether the given channel is open for data to be sent through it. - * This method will return {@code false} if the client has no listeners for - * the given channel. - */ - public static boolean canSend(ServerPlayerEntity player, String channel) { - return ServerPlayNetworkingImpl.canSend(player, channel); - } - - /** - * Send a packet to the given player through the given channel. The payload - * will only be written if the channel is open. - */ - public static void send(ServerPlayerEntity player, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.send(player, channel, payload); - } - - /** - * Send a packet to the given player through the given channel. The writer - * will only be called if the channel is open. - */ - public static void send(ServerPlayerEntity player, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.send(player, channel, writer); - } - - /** - * Send a packet to the given player through the given channel. - */ - public static void send(ServerPlayerEntity player, String channel, byte[] data) { - ServerPlayNetworkingImpl.send(player, channel, data); - } - - /** - * Send a packet to the given players through the given channel. The payload - * will only be written if the channel is open for at least one player. - */ - public static void send(Iterable players, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.send(players, channel, payload); - } - - /** - * Send a packet to the given players through the given channel. The writer - * will only be called if the channel is open for at least one player. - */ - public static void send(Iterable players, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.send(players, channel, writer); - } - - /** - * Send a packet to the given players through the given channel. - */ - public static void send(Iterable players, String channel, byte[] data) { - ServerPlayNetworkingImpl.send(players, channel, data); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel. The payload will only be written if the channel is open for at - * least one player. - */ - public static void send(int dimension, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.send(dimension, channel, payload); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel. The writer will only be called if the channel is open for at - * least one player. - */ - public static void send(int dimension, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.send(dimension, channel, writer); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel. - */ - public static void send(int dimension, String channel, byte[] data) { - ServerPlayNetworkingImpl.send(dimension, channel, data); - } - - /** - * Send a packet to all players through the given channel. The payload will - * only be written if the channel is open for at least one player. - */ - public static void send(String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.send(channel, payload); - } - - /** - * Send a packet to all players through the given channel. The writer will - * only be called if the channel is open for at least one player. - */ - public static void send(String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.send(channel, writer); - } - - /** - * Send a packet to all players through the given channel. - */ - public static void send(String channel, byte[] data) { - ServerPlayNetworkingImpl.send(channel, data); - } - - /** - * Send a packet to the given player through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(ServerPlayerEntity player, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(player, channel, payload); - } - - /** - * Send a packet to the given player through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(ServerPlayerEntity player, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(player, channel, writer); - } - - /** - * Send a packet to the given player through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(ServerPlayerEntity player, String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(player, channel, data); - } - - /** - * Send a packet to the given players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(Iterable players, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(players, channel, payload); - } - - /** - * Send a packet to the given players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(Iterable players, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(players, channel, writer); - } - - /** - * Send a packet to the given players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(Iterable players, String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(players, channel, data); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel, without checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(int dimension, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(dimension, channel, payload); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel, without checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(int dimension, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(dimension, channel, writer); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel, without checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(int dimension, String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(dimension, channel, data); - } - - /** - * Send a packet to all players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(channel, payload); - } - - /** - * Send a packet to all players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(channel, writer); - } - - /** - * Send a packet to all players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(channel, data); - } - - public interface PayloadListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, T payload) throws IOException; - - } - - public interface StreamListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, DataInputStream data) throws IOException; - - } - - public interface ByteArrayListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java b/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java deleted file mode 100644 index 18cff165..00000000 --- a/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java +++ /dev/null @@ -1,57 +0,0 @@ -package net.ornithemc.osl.networking.impl; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.LinkedHashSet; -import java.util.Set; - -import net.minecraft.network.packet.Packet; - -import net.ornithemc.osl.networking.api.Channels; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -public class HandshakePayload implements CustomPayload { - - public static final String CHANNEL = "OSL|Handshake"; - - public Set channels; - - public HandshakePayload() { - } - - public HandshakePayload(Set channels) { - this.channels = channels; - } - - public static HandshakePayload client() { - return new HandshakePayload(ClientPlayNetworkingImpl.LISTENERS.keySet()); - } - - public static HandshakePayload server() { - return new HandshakePayload(ServerPlayNetworkingImpl.LISTENERS.keySet()); - } - - @Override - public void read(DataInputStream input) throws IOException { - channels = new LinkedHashSet<>(); - int channelCount = input.readInt(); - - if (channelCount > 0) { - for (int i = 0; i < channelCount; i++) { - channels.add(Packet.readString(input, Channels.MAX_LENGTH)); - } - } - } - - @Override - public void write(DataOutputStream output) throws IOException { - output.writeInt(channels.size()); - - for (String channel : channels) { - Packet.writeString(channel, output); - } - } -} diff --git a/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java deleted file mode 100644 index 601d2f5d..00000000 --- a/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java +++ /dev/null @@ -1,57 +0,0 @@ -package net.ornithemc.osl.networking.impl; - -import net.ornithemc.osl.entrypoints.api.ModInitializer; -import net.ornithemc.osl.entrypoints.api.client.ClientModInitializer; -import net.ornithemc.osl.entrypoints.api.server.ServerModInitializer; -import net.ornithemc.osl.lifecycle.api.client.MinecraftClientEvents; -import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; -import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking; -import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking; -import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -public class Networking implements ModInitializer, ClientModInitializer, ServerModInitializer { - - @Override - public void init() { - MinecraftServerEvents.START.register(server -> { - ServerPlayNetworkingImpl.setUp(server); - }); - MinecraftServerEvents.STOP.register(server -> { - ServerPlayNetworkingImpl.destroy(server); - }); - ServerPlayNetworking.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { - // send channel registration data as a response to receiving client channel registration data - ServerPlayNetworkingImpl.doSend(player, HandshakePayload.CHANNEL, HandshakePayload.server()); - - ((INetworkHandler)handler).osl$networking$registerChannels(payload.channels); - ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); - - return true; - }); - } - - @Override - public void initClient() { - MinecraftClientEvents.START.register(minecraft -> { - ClientPlayNetworkingImpl.setUp(minecraft); - }); - MinecraftClientEvents.STOP.register(minecraft -> { - ClientPlayNetworkingImpl.destroy(minecraft); - }); - ClientPlayNetworking.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { - ((INetworkHandler)handler).osl$networking$registerChannels(payload.channels); - ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); - - return true; - }); - } - - @Override - public void initServer() { - // empty impl - } -} diff --git a/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java b/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java deleted file mode 100644 index b7e45de5..00000000 --- a/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java +++ /dev/null @@ -1,168 +0,0 @@ -package net.ornithemc.osl.networking.impl.client; - -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.function.Supplier; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.network.handler.ClientNetworkHandler; -import net.minecraft.network.packet.CustomPayloadPacket; -import net.minecraft.network.packet.Packet; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.Channels; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.api.DataStreams; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.ByteArrayListener; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.PayloadListener; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.StreamListener; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; - -public final class ClientPlayNetworkingImpl { - - private static final Logger LOGGER = LogManager.getLogger("OSL|Client Play Networking"); - - private static Minecraft minecraft; - - public static void setUp(Minecraft minecraft) { - if (ClientPlayNetworkingImpl.minecraft == minecraft) { - throw new IllegalStateException("tried to set up client networking when it was already set up!"); - } - - ClientPlayNetworkingImpl.minecraft = minecraft; - } - - public static void destroy(Minecraft minecraft) { - if (ClientPlayNetworkingImpl.minecraft != minecraft) { - throw new IllegalStateException("tried to destroy client networking when it was not set up!"); - } - - ClientPlayNetworkingImpl.minecraft = null; - } - - public static final Map LISTENERS = new LinkedHashMap<>(); - - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - registerListenerImpl(channel, (minecraft, handler, data) -> { - T payload = initializer.get(); - payload.read(DataStreams.input(data)); - - return listener.handle(minecraft, handler, payload); - }); - } - - public static void registerListener(String channel, StreamListener listener) { - registerListenerImpl(channel, (minecraft, handler, data) -> { - return listener.handle(minecraft, handler, DataStreams.input(data)); - }); - } - - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - registerListenerImpl(channel, listener::handle); - } - - private static void registerListenerImpl(String channel, Listener listener) { - LISTENERS.compute(channel, (key, value) -> { - Channels.validate(channel); - - if (value != null) { - throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); - } - - return listener; - }); - } - - public static void unregisterListener(String channel) { - LISTENERS.remove(channel); - } - - public static boolean handle(Minecraft minecraft, ClientNetworkHandler handler, CustomPayloadPacket packet) { - Listener listener = LISTENERS.get(packet.channel); - - if (listener != null) { - try { - return listener.handle(minecraft, handler, packet.data); - } catch (IOException e) { - LOGGER.warn("error handling custom payload on channel \'" + packet.channel + "\'", e); - return true; - } - } - - return false; - } - - public static boolean isPlayReady() { - INetworkHandler handler = (INetworkHandler)minecraft.getNetworkHandler(); - return handler != null && handler.osl$networking$isPlayReady(); - } - - public static boolean canSend(String channel) { - INetworkHandler handler = (INetworkHandler)minecraft.getNetworkHandler(); - return handler != null && handler.osl$networking$isRegisteredChannel(channel); - } - - public static void send(String channel, CustomPayload payload) { - if (canSend(channel)) { - doSend(channel, payload); - } - } - - public static void send(String channel, IOConsumer writer) { - if (canSend(channel)) { - doSend(channel, writer); - } - } - - public static void send(String channel, byte[] data) { - if (canSend(channel)) { - doSend(channel, data); - } - } - - public static void doSend(String channel, CustomPayload payload) { - sendPacket(makePacket(channel, payload)); - } - - public static void doSend(String channel, IOConsumer writer) { - sendPacket(makePacket(channel, writer)); - } - - public static void doSend(String channel, byte[] data) { - sendPacket(makePacket(channel, data)); - } - - private static Packet makePacket(String channel, CustomPayload payload) { - return makePacket(channel, payload::write); - } - - private static Packet makePacket(String channel, IOConsumer writer) { - try { - return new CustomPayloadPacket(channel, DataStreams.output(writer).toByteArray()); - } catch (IOException e) { - LOGGER.warn("error writing custom payload to channel \'" + channel + "\'", e); - return null; - } - } - - private static Packet makePacket(String channel, byte[] data) { - return new CustomPayloadPacket(channel, data); - } - - private static void sendPacket(Packet packet) { - if (packet != null) { - minecraft.getNetworkHandler().sendPacket(packet); - } - } - - private interface Listener { - - boolean handle(Minecraft minecraft, ClientNetworkHandler handler, byte[] data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java b/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java deleted file mode 100644 index a5519db4..00000000 --- a/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java +++ /dev/null @@ -1,13 +0,0 @@ -package net.ornithemc.osl.networking.impl.interfaces.mixin; - -import java.util.Set; - -public interface INetworkHandler { - - boolean osl$networking$isPlayReady(); - - void osl$networking$registerChannels(Set channels); - - boolean osl$networking$isRegisteredChannel(String channel); - -} diff --git a/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadPacketMixin.java b/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadPacketMixin.java deleted file mode 100644 index aeb43506..00000000 --- a/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadPacketMixin.java +++ /dev/null @@ -1,23 +0,0 @@ -package net.ornithemc.osl.networking.impl.mixin.common; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.Constant; -import org.spongepowered.asm.mixin.injection.ModifyConstant; - -import net.minecraft.network.packet.CustomPayloadPacket; - -import net.ornithemc.osl.networking.api.Channels; - -@Mixin(CustomPayloadPacket.class) -public class CustomPayloadPacketMixin { - - @ModifyConstant( - method = "read", - constant = @Constant( - intValue = 20 - ) - ) - private int osl$networking$modifyMaxChannelLength(int maxLength) { - return Channels.MAX_LENGTH; - } -} diff --git a/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java b/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java deleted file mode 100644 index 17ba40b5..00000000 --- a/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java +++ /dev/null @@ -1,269 +0,0 @@ -package net.ornithemc.osl.networking.impl.server; - -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.function.Supplier; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import net.minecraft.network.packet.CustomPayloadPacket; -import net.minecraft.network.packet.Packet; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.entity.mob.player.ServerPlayerEntity; -import net.minecraft.server.network.handler.ServerPlayNetworkHandler; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.Channels; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.api.DataStreams; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.ByteArrayListener; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.PayloadListener; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.StreamListener; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; - -public final class ServerPlayNetworkingImpl { - - private static final Logger LOGGER = LogManager.getLogger("OSL|Server Play Networking"); - - private static MinecraftServer server; - - public static void setUp(MinecraftServer server) { - if (ServerPlayNetworkingImpl.server == server) { - throw new IllegalStateException("tried to set up server networking when it was already set up!"); - } - - ServerPlayNetworkingImpl.server = server; - } - - public static void destroy(MinecraftServer server) { - if (ServerPlayNetworkingImpl.server != server) { - throw new IllegalStateException("tried to destroy server networking when it was not set up!"); - } - - ServerPlayNetworkingImpl.server = null; - } - - public static final Map LISTENERS = new LinkedHashMap<>(); - - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - registerListenerImpl(channel, (server, handler, player, data) -> { - T payload = initializer.get(); - payload.read(DataStreams.input(data)); - - return listener.handle(server, handler, player, payload); - }); - } - - public static void registerListener(String channel, StreamListener listener) { - registerListenerImpl(channel, (server, handler, player, data) -> { - return listener.handle(server, handler, player, DataStreams.input(data)); - }); - } - - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - registerListenerImpl(channel, listener::handle); - } - - private static void registerListenerImpl(String channel, Listener listener) { - LISTENERS.compute(channel, (key, value) -> { - Channels.validate(channel); - - if (value != null) { - throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); - } - - return listener; - }); - } - - public static void unregisterListener(String channel) { - LISTENERS.remove(channel); - } - - public static boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, CustomPayloadPacket packet) { - Listener listener = LISTENERS.get(packet.channel); - - if (listener != null) { - try { - return listener.handle(server, handler, player, packet.data); - } catch (IOException e) { - LOGGER.warn("error handling custom payload on channel \'" + packet.channel + "\'", e); - return true; - } - } - - return false; - } - - public static boolean isPlayReady(ServerPlayerEntity player) { - INetworkHandler handler = (INetworkHandler)player.networkHandler; - return handler != null && handler.osl$networking$isPlayReady(); - } - - public static boolean canSend(ServerPlayerEntity player, String channel) { - INetworkHandler handler = (INetworkHandler)player.networkHandler; - return handler != null && handler.osl$networking$isRegisteredChannel(channel); - } - - public static void send(ServerPlayerEntity player, String channel, CustomPayload payload) { - if (canSend(player, channel)) { - doSend(player, channel, payload); - } - } - - public static void send(ServerPlayerEntity player, String channel, IOConsumer writer) { - if (canSend(player, channel)) { - doSend(player, channel, writer); - } - } - - public static void send(ServerPlayerEntity player, String channel, byte[] data) { - if (canSend(player, channel)) { - doSend(player, channel, data); - } - } - - public static void send(Iterable players, String channel, CustomPayload payload) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, payload)); - } - - public static void send(Iterable players, String channel, IOConsumer writer) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, writer)); - } - - public static void send(Iterable players, String channel, byte[] data) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, data)); - } - - public static void send(int dimension, String channel, CustomPayload payload) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)), channel, payload); - } - - public static void send(int dimension, String channel, IOConsumer writer) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)), channel, writer); - } - - public static void send(int dimension, String channel, byte[] data) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)),channel, data); - } - - public static void send(String channel, CustomPayload payload) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, payload); - } - - public static void send(String channel, IOConsumer writer) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, writer); - } - - public static void send(String channel, byte[] data) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, data); - } - - public static void doSend(ServerPlayerEntity player, String channel, CustomPayload payload) { - sendPacket(player, makePacket(channel, payload)); - } - - public static void doSend(ServerPlayerEntity player, String channel, IOConsumer writer) { - sendPacket(player, makePacket(channel, writer)); - } - - public static void doSend(ServerPlayerEntity player, String channel, byte[] data) { - sendPacket(player, makePacket(channel, data)); - } - - public static void doSend(Iterable players, String channel, CustomPayload payload) { - sendPacket(players, makePacket(channel, payload)); - } - - public static void doSend(Iterable players, String channel, IOConsumer writer) { - sendPacket(players, makePacket(channel, writer)); - } - - public static void doSend(Iterable players, String channel, byte[] data) { - sendPacket(players, makePacket(channel, data)); - } - - public static void doSend(int dimension, String channel, CustomPayload payload) { - doSend(collectPlayers(p -> p.dimension == dimension), channel, payload); - } - - public static void doSend(int dimension, String channel, IOConsumer writer) { - doSend(collectPlayers(p -> p.dimension == dimension), channel, writer); - } - - public static void doSend(int dimension, String channel, byte[] data) { - doSend(collectPlayers(p -> p.dimension == dimension),channel, data); - } - - public static void doSend(String channel, CustomPayload payload) { - doSend(collectPlayers(p -> true), channel, payload); - } - - public static void doSend(String channel, IOConsumer writer) { - doSend(collectPlayers(p -> true), channel, writer); - } - - public static void doSend(String channel, byte[] data) { - doSend(collectPlayers(p -> true), channel, data); - } - - @SuppressWarnings("unchecked") // thanks proguard - private static Iterable collectPlayers(Predicate filter) { - return collectPlayers(server.playerManager.players, filter); - } - - private static Iterable collectPlayers(Iterable src, Predicate filter) { - List players = new ArrayList<>(); - - for (ServerPlayerEntity player : src) { - if (filter.test(player)) { - players.add(player); - } - } - - return players; - } - - private static Packet makePacket(String channel, CustomPayload payload) { - return makePacket(channel, payload::write); - } - - private static Packet makePacket(String channel, IOConsumer writer) { - try { - return new CustomPayloadPacket(channel, DataStreams.output(writer).toByteArray()); - } catch (IOException e) { - LOGGER.warn("error writing custom payload to channel \'" + channel + "\'", e); - return null; - } - } - - private static Packet makePacket(String channel, byte[] data) { - return new CustomPayloadPacket(channel, data); - } - - private static void sendPacket(ServerPlayerEntity player, Packet packet) { - if (packet != null) { - player.networkHandler.sendPacket(packet); - } - } - - private static void sendPacket(Iterable players, Packet packet) { - if (packet != null) { - for (ServerPlayerEntity player : players) { - sendPacket(player, packet); - } - } - } - - private interface Listener { - - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java b/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java deleted file mode 100644 index 237d7e67..00000000 --- a/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java +++ /dev/null @@ -1,13 +0,0 @@ -package net.ornithemc.osl.networking.api; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; - -public interface CustomPayload { - - void read(DataInputStream input) throws IOException; - - void write(DataOutputStream output) throws IOException; - -} diff --git a/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java b/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java deleted file mode 100644 index f68e894c..00000000 --- a/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java +++ /dev/null @@ -1,23 +0,0 @@ -package net.ornithemc.osl.networking.api; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; - -public final class DataStreams { - - public static DataInputStream input(byte[] bytes) { - return new DataInputStream(new ByteArrayInputStream(bytes == null ? new byte[0] : bytes)); - } - - public static ByteArrayOutputStream output(IOConsumer writer) throws IOException { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - DataOutputStream os = new DataOutputStream(bos); - writer.accept(os); - return bos; - } -} diff --git a/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java b/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java deleted file mode 100644 index d5adcfb8..00000000 --- a/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java +++ /dev/null @@ -1,82 +0,0 @@ -package net.ornithemc.osl.networking.api.client; - -import java.util.function.Consumer; - -import net.minecraft.client.Minecraft; - -import net.ornithemc.osl.core.api.events.Event; - -/** - * Events related to the client side of a client-server connection. - */ -public class ClientConnectionEvents { - - /** - * This event is fired after a successful login occurs. - * - *

- * Note that channel registration happens after login, - * and until then data cannot safely be sent to the server. - * - *

- * This applies to connections to dedicated servers as - * well as connections to integrated servers. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ClientConnectionEvents.LOGIN.register(minecraft -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> LOGIN = Event.consumer(); - /** - * This event is fired after login, once channel registration is complete. - * - *

- * This marks the moment data can safely be sent to the server. - * - *

- * This applies to connections to dedicated servers as - * well as connections to integrated servers. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ClientConnectionEvents.PLAY_READY.register(minecraft -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> PLAY_READY = Event.consumer(); - /** - * This event is fired when the client disconnects from the server. - * - *

- * This applies to connections to dedicated servers as - * well as connections to integrated servers. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ClientConnectionEvents.DISCONNECT.register(minecraft -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> DISCONNECT = Event.consumer(); - -} diff --git a/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java b/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java deleted file mode 100644 index e1594802..00000000 --- a/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java +++ /dev/null @@ -1,158 +0,0 @@ -package net.ornithemc.osl.networking.api.client; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.function.Supplier; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.network.handler.ClientNetworkHandler; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; - -public final class ClientPlayNetworking { - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - ClientPlayNetworkingImpl.registerListener(channel, initializer, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListener(String channel, StreamListener listener) { - ClientPlayNetworkingImpl.registerListener(channel, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - ClientPlayNetworkingImpl.registerListenerRaw(channel, listener); - } - - /** - * Remove the listener registered to the given channel. - */ - public static void unregisterListener(String channel) { - ClientPlayNetworkingImpl.unregisterListener(channel); - } - - /** - * Check whether the connection is ready for data to be sent to the server. - */ - public static boolean isPlayReady() { - return ClientPlayNetworkingImpl.isPlayReady(); - } - - /** - * Check whether the given channel is open for data to be sent through it. - * This method will return {@code false} if the client is not connected to a - * server, or if the server has no listeners for the given channel. - */ - public static boolean canSend(String channel) { - return ClientPlayNetworkingImpl.canSend(channel); - } - - /** - * Send a packet to the server through the given channel. The payload will - * only be written if the channel is open. - */ - public static void send(String channel, CustomPayload payload) { - ClientPlayNetworkingImpl.send(channel, payload); - } - - /** - * Send a packet to the server through the given channel. The writer will - * only be called if the channel is open. - */ - public static void send(String channel, IOConsumer writer) { - ClientPlayNetworkingImpl.send(channel, writer); - } - - /** - * Send a packet to the server through the given channel. - */ - public static void send(String channel, byte[] data) { - ClientPlayNetworkingImpl.send(channel, data); - } - - /** - * Send a packet to the server through the given channel, without checking - * whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the server. - */ - public static void doSend(String channel, CustomPayload payload) { - ClientPlayNetworkingImpl.doSend(channel, payload); - } - - /** - * Send a packet to the server through the given channel, without checking - * whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the server. - */ - public static void doSend(String channel, IOConsumer writer) { - ClientPlayNetworkingImpl.doSend(channel, writer); - } - - /** - * Send a packet to the server through the given channel, without checking - * whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the server. - */ - public static void doSend(String channel, byte[] data) { - ClientPlayNetworkingImpl.doSend(channel, data); - } - - public interface PayloadListener { - - /** - * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(Minecraft minecraft, ClientNetworkHandler handler, T payload) throws IOException; - - } - - public interface StreamListener { - - /** - * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(Minecraft minecraft, ClientNetworkHandler handler, DataInputStream data) throws IOException; - - } - - public interface ByteArrayListener { - - /** - * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(Minecraft minecraft, ClientNetworkHandler handler, byte[] data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java b/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java deleted file mode 100644 index e248c524..00000000 --- a/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java +++ /dev/null @@ -1,83 +0,0 @@ -package net.ornithemc.osl.networking.api.server; - -import java.util.function.BiConsumer; - -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.entity.living.player.ServerPlayerEntity; - -import net.ornithemc.osl.core.api.events.Event; - -/** - * Events related to the server side of a client-server connection. - */ -public class ServerConnectionEvents { - - /** - * This event is fired after a successful login occurs. - * - *

- * Note that channel registration happens after login, - * and until then data cannot safely be sent to the client. - * - *

- * This applies to connections to dedicated servers as - * well as connections to integrated servers. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ServerConnectionEvents.LOGIN.register((server, player) -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> LOGIN = Event.biConsumer(); - /** - * This event is fired after login, once channel registration is complete. - * - *

- * This marks the moment data can safely be sent to the client. - * - *

- * This applies to connections to dedicated servers as - * well as connections to integrated servers. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ServerConnectionEvents.PLAY_READY.register((server, player) -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> PLAY_READY = Event.biConsumer(); - /** - * This event is fired when a client disconnects from the server. - * - *

- * This applies to connections to dedicated servers as - * well as connections to integrated servers. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ServerConnectionEvents.DISCONNECT.register((server, player) -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> DISCONNECT = Event.biConsumer(); - -} diff --git a/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java b/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java deleted file mode 100644 index 83d990f4..00000000 --- a/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java +++ /dev/null @@ -1,321 +0,0 @@ -package net.ornithemc.osl.networking.api.server; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.function.Supplier; - -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.entity.living.player.ServerPlayerEntity; -import net.minecraft.server.network.handler.ServerPlayNetworkHandler; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -public final class ServerPlayNetworking { - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - ServerPlayNetworkingImpl.registerListener(channel, initializer, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListener(String channel, StreamListener listener) { - ServerPlayNetworkingImpl.registerListener(channel, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - ServerPlayNetworkingImpl.registerListenerRaw(channel, listener); - } - - /** - * Remove the listener registered to the given channel. - */ - public static void unregisterListener(String channel) { - ServerPlayNetworkingImpl.unregisterListener(channel); - } - - /** - * Check whether the connection is ready for data to be sent to the client. - */ - public static boolean isPlayReady(ServerPlayerEntity player) { - return ServerPlayNetworkingImpl.isPlayReady(player); - } - - /** - * Check whether the given channel is open for data to be sent through it. - * This method will return {@code false} if the client has no listeners for - * the given channel. - */ - public static boolean canSend(ServerPlayerEntity player, String channel) { - return ServerPlayNetworkingImpl.canSend(player, channel); - } - - /** - * Send a packet to the given player through the given channel. The payload - * will only be written if the channel is open. - */ - public static void send(ServerPlayerEntity player, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.send(player, channel, payload); - } - - /** - * Send a packet to the given player through the given channel. The writer - * will only be called if the channel is open. - */ - public static void send(ServerPlayerEntity player, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.send(player, channel, writer); - } - - /** - * Send a packet to the given player through the given channel. - */ - public static void send(ServerPlayerEntity player, String channel, byte[] data) { - ServerPlayNetworkingImpl.send(player, channel, data); - } - - /** - * Send a packet to the given players through the given channel. The payload - * will only be written if the channel is open for at least one player. - */ - public static void send(Iterable players, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.send(players, channel, payload); - } - - /** - * Send a packet to the given players through the given channel. The writer - * will only be called if the channel is open for at least one player. - */ - public static void send(Iterable players, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.send(players, channel, writer); - } - - /** - * Send a packet to the given players through the given channel. - */ - public static void send(Iterable players, String channel, byte[] data) { - ServerPlayNetworkingImpl.send(players, channel, data); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel. The payload will only be written if the channel is open for at - * least one player. - */ - public static void send(int dimension, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.send(dimension, channel, payload); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel. The writer will only be called if the channel is open for at - * least one player. - */ - public static void send(int dimension, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.send(dimension, channel, writer); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel. - */ - public static void send(int dimension, String channel, byte[] data) { - ServerPlayNetworkingImpl.send(dimension, channel, data); - } - - /** - * Send a packet to all players through the given channel. The payload will - * only be written if the channel is open for at least one player. - */ - public static void send(String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.send(channel, payload); - } - - /** - * Send a packet to all players through the given channel. The writer will - * only be called if the channel is open for at least one player. - */ - public static void send(String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.send(channel, writer); - } - - /** - * Send a packet to all players through the given channel. - */ - public static void send(String channel, byte[] data) { - ServerPlayNetworkingImpl.send(channel, data); - } - - /** - * Send a packet to the given player through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(ServerPlayerEntity player, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(player, channel, payload); - } - - /** - * Send a packet to the given player through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(ServerPlayerEntity player, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(player, channel, writer); - } - - /** - * Send a packet to the given player through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(ServerPlayerEntity player, String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(player, channel, data); - } - - /** - * Send a packet to the given players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(Iterable players, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(players, channel, payload); - } - - /** - * Send a packet to the given players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(Iterable players, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(players, channel, writer); - } - - /** - * Send a packet to the given players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(Iterable players, String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(players, channel, data); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel, without checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(int dimension, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(dimension, channel, payload); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel, without checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(int dimension, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(dimension, channel, writer); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel, without checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(int dimension, String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(dimension, channel, data); - } - - /** - * Send a packet to all players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(channel, payload); - } - - /** - * Send a packet to all players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(channel, writer); - } - - /** - * Send a packet to all players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(channel, data); - } - - public interface PayloadListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, T payload) throws IOException; - - } - - public interface StreamListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, DataInputStream data) throws IOException; - - } - - public interface ByteArrayListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java b/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java deleted file mode 100644 index 18cff165..00000000 --- a/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java +++ /dev/null @@ -1,57 +0,0 @@ -package net.ornithemc.osl.networking.impl; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.LinkedHashSet; -import java.util.Set; - -import net.minecraft.network.packet.Packet; - -import net.ornithemc.osl.networking.api.Channels; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -public class HandshakePayload implements CustomPayload { - - public static final String CHANNEL = "OSL|Handshake"; - - public Set channels; - - public HandshakePayload() { - } - - public HandshakePayload(Set channels) { - this.channels = channels; - } - - public static HandshakePayload client() { - return new HandshakePayload(ClientPlayNetworkingImpl.LISTENERS.keySet()); - } - - public static HandshakePayload server() { - return new HandshakePayload(ServerPlayNetworkingImpl.LISTENERS.keySet()); - } - - @Override - public void read(DataInputStream input) throws IOException { - channels = new LinkedHashSet<>(); - int channelCount = input.readInt(); - - if (channelCount > 0) { - for (int i = 0; i < channelCount; i++) { - channels.add(Packet.readString(input, Channels.MAX_LENGTH)); - } - } - } - - @Override - public void write(DataOutputStream output) throws IOException { - output.writeInt(channels.size()); - - for (String channel : channels) { - Packet.writeString(channel, output); - } - } -} diff --git a/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/Networking.java deleted file mode 100644 index 601d2f5d..00000000 --- a/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/Networking.java +++ /dev/null @@ -1,57 +0,0 @@ -package net.ornithemc.osl.networking.impl; - -import net.ornithemc.osl.entrypoints.api.ModInitializer; -import net.ornithemc.osl.entrypoints.api.client.ClientModInitializer; -import net.ornithemc.osl.entrypoints.api.server.ServerModInitializer; -import net.ornithemc.osl.lifecycle.api.client.MinecraftClientEvents; -import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; -import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking; -import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking; -import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -public class Networking implements ModInitializer, ClientModInitializer, ServerModInitializer { - - @Override - public void init() { - MinecraftServerEvents.START.register(server -> { - ServerPlayNetworkingImpl.setUp(server); - }); - MinecraftServerEvents.STOP.register(server -> { - ServerPlayNetworkingImpl.destroy(server); - }); - ServerPlayNetworking.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { - // send channel registration data as a response to receiving client channel registration data - ServerPlayNetworkingImpl.doSend(player, HandshakePayload.CHANNEL, HandshakePayload.server()); - - ((INetworkHandler)handler).osl$networking$registerChannels(payload.channels); - ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); - - return true; - }); - } - - @Override - public void initClient() { - MinecraftClientEvents.START.register(minecraft -> { - ClientPlayNetworkingImpl.setUp(minecraft); - }); - MinecraftClientEvents.STOP.register(minecraft -> { - ClientPlayNetworkingImpl.destroy(minecraft); - }); - ClientPlayNetworking.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { - ((INetworkHandler)handler).osl$networking$registerChannels(payload.channels); - ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); - - return true; - }); - } - - @Override - public void initServer() { - // empty impl - } -} diff --git a/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java b/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java deleted file mode 100644 index b7e45de5..00000000 --- a/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java +++ /dev/null @@ -1,168 +0,0 @@ -package net.ornithemc.osl.networking.impl.client; - -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.function.Supplier; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.network.handler.ClientNetworkHandler; -import net.minecraft.network.packet.CustomPayloadPacket; -import net.minecraft.network.packet.Packet; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.Channels; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.api.DataStreams; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.ByteArrayListener; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.PayloadListener; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.StreamListener; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; - -public final class ClientPlayNetworkingImpl { - - private static final Logger LOGGER = LogManager.getLogger("OSL|Client Play Networking"); - - private static Minecraft minecraft; - - public static void setUp(Minecraft minecraft) { - if (ClientPlayNetworkingImpl.minecraft == minecraft) { - throw new IllegalStateException("tried to set up client networking when it was already set up!"); - } - - ClientPlayNetworkingImpl.minecraft = minecraft; - } - - public static void destroy(Minecraft minecraft) { - if (ClientPlayNetworkingImpl.minecraft != minecraft) { - throw new IllegalStateException("tried to destroy client networking when it was not set up!"); - } - - ClientPlayNetworkingImpl.minecraft = null; - } - - public static final Map LISTENERS = new LinkedHashMap<>(); - - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - registerListenerImpl(channel, (minecraft, handler, data) -> { - T payload = initializer.get(); - payload.read(DataStreams.input(data)); - - return listener.handle(minecraft, handler, payload); - }); - } - - public static void registerListener(String channel, StreamListener listener) { - registerListenerImpl(channel, (minecraft, handler, data) -> { - return listener.handle(minecraft, handler, DataStreams.input(data)); - }); - } - - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - registerListenerImpl(channel, listener::handle); - } - - private static void registerListenerImpl(String channel, Listener listener) { - LISTENERS.compute(channel, (key, value) -> { - Channels.validate(channel); - - if (value != null) { - throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); - } - - return listener; - }); - } - - public static void unregisterListener(String channel) { - LISTENERS.remove(channel); - } - - public static boolean handle(Minecraft minecraft, ClientNetworkHandler handler, CustomPayloadPacket packet) { - Listener listener = LISTENERS.get(packet.channel); - - if (listener != null) { - try { - return listener.handle(minecraft, handler, packet.data); - } catch (IOException e) { - LOGGER.warn("error handling custom payload on channel \'" + packet.channel + "\'", e); - return true; - } - } - - return false; - } - - public static boolean isPlayReady() { - INetworkHandler handler = (INetworkHandler)minecraft.getNetworkHandler(); - return handler != null && handler.osl$networking$isPlayReady(); - } - - public static boolean canSend(String channel) { - INetworkHandler handler = (INetworkHandler)minecraft.getNetworkHandler(); - return handler != null && handler.osl$networking$isRegisteredChannel(channel); - } - - public static void send(String channel, CustomPayload payload) { - if (canSend(channel)) { - doSend(channel, payload); - } - } - - public static void send(String channel, IOConsumer writer) { - if (canSend(channel)) { - doSend(channel, writer); - } - } - - public static void send(String channel, byte[] data) { - if (canSend(channel)) { - doSend(channel, data); - } - } - - public static void doSend(String channel, CustomPayload payload) { - sendPacket(makePacket(channel, payload)); - } - - public static void doSend(String channel, IOConsumer writer) { - sendPacket(makePacket(channel, writer)); - } - - public static void doSend(String channel, byte[] data) { - sendPacket(makePacket(channel, data)); - } - - private static Packet makePacket(String channel, CustomPayload payload) { - return makePacket(channel, payload::write); - } - - private static Packet makePacket(String channel, IOConsumer writer) { - try { - return new CustomPayloadPacket(channel, DataStreams.output(writer).toByteArray()); - } catch (IOException e) { - LOGGER.warn("error writing custom payload to channel \'" + channel + "\'", e); - return null; - } - } - - private static Packet makePacket(String channel, byte[] data) { - return new CustomPayloadPacket(channel, data); - } - - private static void sendPacket(Packet packet) { - if (packet != null) { - minecraft.getNetworkHandler().sendPacket(packet); - } - } - - private interface Listener { - - boolean handle(Minecraft minecraft, ClientNetworkHandler handler, byte[] data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java b/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java deleted file mode 100644 index a5519db4..00000000 --- a/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java +++ /dev/null @@ -1,13 +0,0 @@ -package net.ornithemc.osl.networking.impl.interfaces.mixin; - -import java.util.Set; - -public interface INetworkHandler { - - boolean osl$networking$isPlayReady(); - - void osl$networking$registerChannels(Set channels); - - boolean osl$networking$isRegisteredChannel(String channel); - -} diff --git a/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadPacketMixin.java b/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadPacketMixin.java deleted file mode 100644 index aeb43506..00000000 --- a/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadPacketMixin.java +++ /dev/null @@ -1,23 +0,0 @@ -package net.ornithemc.osl.networking.impl.mixin.common; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.injection.Constant; -import org.spongepowered.asm.mixin.injection.ModifyConstant; - -import net.minecraft.network.packet.CustomPayloadPacket; - -import net.ornithemc.osl.networking.api.Channels; - -@Mixin(CustomPayloadPacket.class) -public class CustomPayloadPacketMixin { - - @ModifyConstant( - method = "read", - constant = @Constant( - intValue = 20 - ) - ) - private int osl$networking$modifyMaxChannelLength(int maxLength) { - return Channels.MAX_LENGTH; - } -} diff --git a/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java b/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java deleted file mode 100644 index de25d533..00000000 --- a/libraries/networking/networking-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java +++ /dev/null @@ -1,269 +0,0 @@ -package net.ornithemc.osl.networking.impl.server; - -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.function.Supplier; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import net.minecraft.network.packet.CustomPayloadPacket; -import net.minecraft.network.packet.Packet; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.entity.living.player.ServerPlayerEntity; -import net.minecraft.server.network.handler.ServerPlayNetworkHandler; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.Channels; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.api.DataStreams; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.ByteArrayListener; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.PayloadListener; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.StreamListener; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; - -public final class ServerPlayNetworkingImpl { - - private static final Logger LOGGER = LogManager.getLogger("OSL|Server Play Networking"); - - private static MinecraftServer server; - - public static void setUp(MinecraftServer server) { - if (ServerPlayNetworkingImpl.server == server) { - throw new IllegalStateException("tried to set up server networking when it was already set up!"); - } - - ServerPlayNetworkingImpl.server = server; - } - - public static void destroy(MinecraftServer server) { - if (ServerPlayNetworkingImpl.server != server) { - throw new IllegalStateException("tried to destroy server networking when it was not set up!"); - } - - ServerPlayNetworkingImpl.server = null; - } - - public static final Map LISTENERS = new LinkedHashMap<>(); - - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - registerListenerImpl(channel, (server, handler, player, data) -> { - T payload = initializer.get(); - payload.read(DataStreams.input(data)); - - return listener.handle(server, handler, player, payload); - }); - } - - public static void registerListener(String channel, StreamListener listener) { - registerListenerImpl(channel, (server, handler, player, data) -> { - return listener.handle(server, handler, player, DataStreams.input(data)); - }); - } - - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - registerListenerImpl(channel, listener::handle); - } - - private static void registerListenerImpl(String channel, Listener listener) { - LISTENERS.compute(channel, (key, value) -> { - Channels.validate(channel); - - if (value != null) { - throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); - } - - return listener; - }); - } - - public static void unregisterListener(String channel) { - LISTENERS.remove(channel); - } - - public static boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, CustomPayloadPacket packet) { - Listener listener = LISTENERS.get(packet.channel); - - if (listener != null) { - try { - return listener.handle(server, handler, player, packet.data); - } catch (IOException e) { - LOGGER.warn("error handling custom payload on channel \'" + packet.channel + "\'", e); - return true; - } - } - - return false; - } - - public static boolean isPlayReady(ServerPlayerEntity player) { - INetworkHandler handler = (INetworkHandler)player.networkHandler; - return handler != null && handler.osl$networking$isPlayReady(); - } - - public static boolean canSend(ServerPlayerEntity player, String channel) { - INetworkHandler handler = (INetworkHandler)player.networkHandler; - return handler != null && handler.osl$networking$isRegisteredChannel(channel); - } - - public static void send(ServerPlayerEntity player, String channel, CustomPayload payload) { - if (canSend(player, channel)) { - doSend(player, channel, payload); - } - } - - public static void send(ServerPlayerEntity player, String channel, IOConsumer writer) { - if (canSend(player, channel)) { - doSend(player, channel, writer); - } - } - - public static void send(ServerPlayerEntity player, String channel, byte[] data) { - if (canSend(player, channel)) { - doSend(player, channel, data); - } - } - - public static void send(Iterable players, String channel, CustomPayload payload) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, payload)); - } - - public static void send(Iterable players, String channel, IOConsumer writer) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, writer)); - } - - public static void send(Iterable players, String channel, byte[] data) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, data)); - } - - public static void send(int dimension, String channel, CustomPayload payload) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)), channel, payload); - } - - public static void send(int dimension, String channel, IOConsumer writer) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)), channel, writer); - } - - public static void send(int dimension, String channel, byte[] data) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)),channel, data); - } - - public static void send(String channel, CustomPayload payload) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, payload); - } - - public static void send(String channel, IOConsumer writer) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, writer); - } - - public static void send(String channel, byte[] data) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, data); - } - - public static void doSend(ServerPlayerEntity player, String channel, CustomPayload payload) { - sendPacket(player, makePacket(channel, payload)); - } - - public static void doSend(ServerPlayerEntity player, String channel, IOConsumer writer) { - sendPacket(player, makePacket(channel, writer)); - } - - public static void doSend(ServerPlayerEntity player, String channel, byte[] data) { - sendPacket(player, makePacket(channel, data)); - } - - public static void doSend(Iterable players, String channel, CustomPayload payload) { - sendPacket(players, makePacket(channel, payload)); - } - - public static void doSend(Iterable players, String channel, IOConsumer writer) { - sendPacket(players, makePacket(channel, writer)); - } - - public static void doSend(Iterable players, String channel, byte[] data) { - sendPacket(players, makePacket(channel, data)); - } - - public static void doSend(int dimension, String channel, CustomPayload payload) { - doSend(collectPlayers(p -> p.dimension == dimension), channel, payload); - } - - public static void doSend(int dimension, String channel, IOConsumer writer) { - doSend(collectPlayers(p -> p.dimension == dimension), channel, writer); - } - - public static void doSend(int dimension, String channel, byte[] data) { - doSend(collectPlayers(p -> p.dimension == dimension),channel, data); - } - - public static void doSend(String channel, CustomPayload payload) { - doSend(collectPlayers(p -> true), channel, payload); - } - - public static void doSend(String channel, IOConsumer writer) { - doSend(collectPlayers(p -> true), channel, writer); - } - - public static void doSend(String channel, byte[] data) { - doSend(collectPlayers(p -> true), channel, data); - } - - @SuppressWarnings("unchecked") // thanks proguard - private static Iterable collectPlayers(Predicate filter) { - return collectPlayers(server.getPlayerManager().players, filter); - } - - private static Iterable collectPlayers(Iterable src, Predicate filter) { - List players = new ArrayList<>(); - - for (ServerPlayerEntity player : src) { - if (filter.test(player)) { - players.add(player); - } - } - - return players; - } - - private static Packet makePacket(String channel, CustomPayload payload) { - return makePacket(channel, payload::write); - } - - private static Packet makePacket(String channel, IOConsumer writer) { - try { - return new CustomPayloadPacket(channel, DataStreams.output(writer).toByteArray()); - } catch (IOException e) { - LOGGER.warn("error writing custom payload to channel \'" + channel + "\'", e); - return null; - } - } - - private static Packet makePacket(String channel, byte[] data) { - return new CustomPayloadPacket(channel, data); - } - - private static void sendPacket(ServerPlayerEntity player, Packet packet) { - if (packet != null) { - player.networkHandler.sendPacket(packet); - } - } - - private static void sendPacket(Iterable players, Packet packet) { - if (packet != null) { - for (ServerPlayerEntity player : players) { - sendPacket(player, packet); - } - } - } - - private interface Listener { - - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java b/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java deleted file mode 100644 index aee6a1cd..00000000 --- a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java +++ /dev/null @@ -1,13 +0,0 @@ -package net.ornithemc.osl.networking.api; - -import java.io.IOException; - -import net.minecraft.network.PacketByteBuf; - -public interface CustomPayload { - - void read(PacketByteBuf buffer) throws IOException; - - void write(PacketByteBuf buffer) throws IOException; - -} diff --git a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/api/PacketByteBufs.java b/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/api/PacketByteBufs.java deleted file mode 100644 index 93b76c29..00000000 --- a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/api/PacketByteBufs.java +++ /dev/null @@ -1,31 +0,0 @@ -package net.ornithemc.osl.networking.api; - -import java.io.IOException; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; - -import net.minecraft.network.PacketByteBuf; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; - -public final class PacketByteBufs { - - public static PacketByteBuf make() { - return make(Unpooled.buffer()); - } - - public static PacketByteBuf make(byte[] bytes) { - return bytes == null ? make() : make(Unpooled.wrappedBuffer(bytes)); - } - - public static PacketByteBuf make(ByteBuf buf) { - return buf == null ? make() : new PacketByteBuf(buf); - } - - public static PacketByteBuf make(IOConsumer writer) throws IOException { - PacketByteBuf buffer = make(); - writer.accept(buffer); - return buffer; - } -} diff --git a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java b/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java deleted file mode 100644 index d5adcfb8..00000000 --- a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java +++ /dev/null @@ -1,82 +0,0 @@ -package net.ornithemc.osl.networking.api.client; - -import java.util.function.Consumer; - -import net.minecraft.client.Minecraft; - -import net.ornithemc.osl.core.api.events.Event; - -/** - * Events related to the client side of a client-server connection. - */ -public class ClientConnectionEvents { - - /** - * This event is fired after a successful login occurs. - * - *

- * Note that channel registration happens after login, - * and until then data cannot safely be sent to the server. - * - *

- * This applies to connections to dedicated servers as - * well as connections to integrated servers. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ClientConnectionEvents.LOGIN.register(minecraft -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> LOGIN = Event.consumer(); - /** - * This event is fired after login, once channel registration is complete. - * - *

- * This marks the moment data can safely be sent to the server. - * - *

- * This applies to connections to dedicated servers as - * well as connections to integrated servers. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ClientConnectionEvents.PLAY_READY.register(minecraft -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> PLAY_READY = Event.consumer(); - /** - * This event is fired when the client disconnects from the server. - * - *

- * This applies to connections to dedicated servers as - * well as connections to integrated servers. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ClientConnectionEvents.DISCONNECT.register(minecraft -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> DISCONNECT = Event.consumer(); - -} diff --git a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java b/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java deleted file mode 100644 index 67cc2c08..00000000 --- a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java +++ /dev/null @@ -1,174 +0,0 @@ -package net.ornithemc.osl.networking.api.client; - -import java.io.IOException; -import java.util.function.Supplier; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.network.handler.ClientPlayNetworkHandler; -import net.minecraft.network.PacketByteBuf; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; - -public final class ClientPlayNetworking { - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - ClientPlayNetworkingImpl.registerListener(channel, initializer, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListener(String channel, ByteBufListener listener) { - ClientPlayNetworkingImpl.registerListener(channel, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - ClientPlayNetworkingImpl.registerListenerRaw(channel, listener); - } - - /** - * Remove the listener registered to the given channel. - */ - public static void unregisterListener(String channel) { - ClientPlayNetworkingImpl.unregisterListener(channel); - } - - /** - * Check whether the connection is ready for data to be sent to the server. - */ - public static boolean isPlayReady() { - return ClientPlayNetworkingImpl.isPlayReady(); - } - - /** - * Check whether the given channel is open for data to be sent through it. - * This method will return {@code false} if the client is not connected to a - * server, or if the server has no listeners for the given channel. - */ - public static boolean canSend(String channel) { - return ClientPlayNetworkingImpl.canSend(channel); - } - - /** - * Send a packet to the server through the given channel. The payload will - * only be written if the channel is open. - */ - public static void send(String channel, CustomPayload payload) { - ClientPlayNetworkingImpl.send(channel, payload); - } - - /** - * Send a packet to the server through the given channel. The writer will - * only be called if the channel is open. - */ - public static void send(String channel, IOConsumer writer) { - ClientPlayNetworkingImpl.send(channel, writer); - } - - /** - * Send a packet to the server through the given channel. - */ - public static void send(String channel, PacketByteBuf data) { - ClientPlayNetworkingImpl.send(channel, data); - } - - /** - * Send a packet to the server through the given channel. - */ - public static void send(String channel, byte[] data) { - ClientPlayNetworkingImpl.send(channel, data); - } - - /** - * Send a packet to the server through the given channel, without checking - * whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the server. - */ - public static void doSend(String channel, CustomPayload payload) { - ClientPlayNetworkingImpl.doSend(channel, payload); - } - - /** - * Send a packet to the server through the given channel, without checking - * whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the server. - */ - public static void doSend(String channel, IOConsumer writer) { - ClientPlayNetworkingImpl.doSend(channel, writer); - } - - /** - * Send a packet to the server through the given channel, without checking - * whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the server. - */ - public static void doSend(String channel, PacketByteBuf data) { - ClientPlayNetworkingImpl.doSend(channel, data); - } - - /** - * Send a packet to the server through the given channel, without checking - * whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the server. - */ - public static void doSend(String channel, byte[] data) { - ClientPlayNetworkingImpl.doSend(channel, data); - } - - public interface PayloadListener { - - /** - * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, T payload) throws IOException; - - } - - public interface ByteBufListener { - - /** - * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, PacketByteBuf data) throws IOException; - - } - - public interface ByteArrayListener { - - /** - * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, byte[] data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java b/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java deleted file mode 100644 index 5ad5c022..00000000 --- a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java +++ /dev/null @@ -1,55 +0,0 @@ -package net.ornithemc.osl.networking.impl; - -import java.io.IOException; -import java.util.LinkedHashSet; -import java.util.Set; - -import net.minecraft.network.PacketByteBuf; - -import net.ornithemc.osl.networking.api.Channels; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -public class HandshakePayload implements CustomPayload { - - public static final String CHANNEL = "OSL|Handshake"; - - public Set channels; - - public HandshakePayload() { - } - - public HandshakePayload(Set channels) { - this.channels = channels; - } - - public static HandshakePayload client() { - return new HandshakePayload(ClientPlayNetworkingImpl.LISTENERS.keySet()); - } - - public static HandshakePayload server() { - return new HandshakePayload(ServerPlayNetworkingImpl.LISTENERS.keySet()); - } - - @Override - public void read(PacketByteBuf buffer) throws IOException { - channels = new LinkedHashSet<>(); - int channelCount = buffer.readInt(); - - if (channelCount > 0) { - for (int i = 0; i < channelCount; i++) { - channels.add(buffer.readString(Channels.MAX_LENGTH)); - } - } - } - - @Override - public void write(PacketByteBuf buffer) throws IOException { - buffer.writeInt(channels.size()); - - for (String channel : channels) { - buffer.writeString(channel); - } - } -} diff --git a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/Networking.java deleted file mode 100644 index 601d2f5d..00000000 --- a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/Networking.java +++ /dev/null @@ -1,57 +0,0 @@ -package net.ornithemc.osl.networking.impl; - -import net.ornithemc.osl.entrypoints.api.ModInitializer; -import net.ornithemc.osl.entrypoints.api.client.ClientModInitializer; -import net.ornithemc.osl.entrypoints.api.server.ServerModInitializer; -import net.ornithemc.osl.lifecycle.api.client.MinecraftClientEvents; -import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; -import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking; -import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking; -import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -public class Networking implements ModInitializer, ClientModInitializer, ServerModInitializer { - - @Override - public void init() { - MinecraftServerEvents.START.register(server -> { - ServerPlayNetworkingImpl.setUp(server); - }); - MinecraftServerEvents.STOP.register(server -> { - ServerPlayNetworkingImpl.destroy(server); - }); - ServerPlayNetworking.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { - // send channel registration data as a response to receiving client channel registration data - ServerPlayNetworkingImpl.doSend(player, HandshakePayload.CHANNEL, HandshakePayload.server()); - - ((INetworkHandler)handler).osl$networking$registerChannels(payload.channels); - ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); - - return true; - }); - } - - @Override - public void initClient() { - MinecraftClientEvents.START.register(minecraft -> { - ClientPlayNetworkingImpl.setUp(minecraft); - }); - MinecraftClientEvents.STOP.register(minecraft -> { - ClientPlayNetworkingImpl.destroy(minecraft); - }); - ClientPlayNetworking.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { - ((INetworkHandler)handler).osl$networking$registerChannels(payload.channels); - ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); - - return true; - }); - } - - @Override - public void initServer() { - // empty impl - } -} diff --git a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java b/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java deleted file mode 100644 index 3174f5ee..00000000 --- a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java +++ /dev/null @@ -1,184 +0,0 @@ -package net.ornithemc.osl.networking.impl.client; - -import java.io.IOException; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.function.Supplier; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.network.handler.ClientPlayNetworkHandler; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.network.packet.Packet; -import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; -import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.Channels; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.api.PacketByteBufs; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.ByteArrayListener; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.ByteBufListener; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.PayloadListener; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; - -public final class ClientPlayNetworkingImpl { - - private static final Logger LOGGER = LogManager.getLogger("OSL|Client Play Networking"); - - private static Minecraft minecraft; - - public static void setUp(Minecraft minecraft) { - if (ClientPlayNetworkingImpl.minecraft == minecraft) { - throw new IllegalStateException("tried to set up client networking when it was already set up!"); - } - - ClientPlayNetworkingImpl.minecraft = minecraft; - } - - public static void destroy(Minecraft minecraft) { - if (ClientPlayNetworkingImpl.minecraft != minecraft) { - throw new IllegalStateException("tried to destroy client networking when it was not set up!"); - } - - ClientPlayNetworkingImpl.minecraft = null; - } - - public static final Map LISTENERS = new LinkedHashMap<>(); - - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - registerListenerImpl(channel, (minecraft, handler, data) -> { - T payload = initializer.get(); - payload.read(PacketByteBufs.make(data)); - - return listener.handle(minecraft, handler, payload); - }); - } - - public static void registerListener(String channel, ByteBufListener listener) { - registerListenerImpl(channel, (minecraft, handler, data) -> { - return listener.handle(minecraft, handler, PacketByteBufs.make(data)); - }); - } - - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - registerListenerImpl(channel, listener::handle); - } - - private static void registerListenerImpl(String channel, Listener listener) { - LISTENERS.compute(channel, (key, value) -> { - Channels.validate(channel); - - if (value != null) { - throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); - } - - return listener; - }); - } - - public static void unregisterListener(String channel) { - LISTENERS.remove(channel); - } - - public static boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, CustomPayloadS2CPacket packet) { - String channel = packet.getChannel(); - Listener listener = LISTENERS.get(channel); - - if (listener != null) { - try { - return listener.handle(minecraft, handler, packet.getData()); - } catch (IOException e) { - LOGGER.warn("error handling custom payload on channel \'" + channel + "\'", e); - return true; - } - } - - return false; - } - - public static boolean isPlayReady() { - INetworkHandler handler = (INetworkHandler)minecraft.getNetworkHandler(); - return handler != null && handler.osl$networking$isPlayReady(); - } - - public static boolean canSend(String channel) { - INetworkHandler handler = (INetworkHandler)minecraft.getNetworkHandler(); - return handler != null && handler.osl$networking$isRegisteredChannel(channel); - } - - public static void send(String channel, CustomPayload payload) { - if (canSend(channel)) { - doSend(channel, payload); - } - } - - public static void send(String channel, IOConsumer writer) { - if (canSend(channel)) { - doSend(channel, writer); - } - } - - public static void send(String channel, PacketByteBuf data) { - if (canSend(channel)) { - doSend(channel, data); - } - } - - public static void send(String channel, byte[] data) { - if (canSend(channel)) { - doSend(channel, data); - } - } - - public static void doSend(String channel, CustomPayload payload) { - sendPacket(makePacket(channel, payload)); - } - - public static void doSend(String channel, IOConsumer writer) { - sendPacket(makePacket(channel, writer)); - } - - public static void doSend(String channel, PacketByteBuf data) { - sendPacket(makePacket(channel, data)); - } - - public static void doSend(String channel, byte[] data) { - sendPacket(makePacket(channel, data)); - } - - private static Packet makePacket(String channel, CustomPayload payload) { - return makePacket(channel, payload::write); - } - - private static Packet makePacket(String channel, IOConsumer writer) { - try { - return new CustomPayloadC2SPacket(channel, PacketByteBufs.make(writer)); - } catch (IOException e) { - LOGGER.warn("error writing custom payload to channel \'" + channel + "\'", e); - return null; - } - } - - private static Packet makePacket(String channel, PacketByteBuf data) { - return new CustomPayloadC2SPacket(channel, data); - } - - private static Packet makePacket(String channel, byte[] data) { - return new CustomPayloadC2SPacket(channel, data); - } - - private static void sendPacket(Packet packet) { - if (packet != null) { - minecraft.getNetworkHandler().sendPacket(packet); - } - } - - private interface Listener { - - boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, byte[] data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/ICustomPayloadPacket.java b/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/ICustomPayloadPacket.java deleted file mode 100644 index 76ae7ad0..00000000 --- a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/ICustomPayloadPacket.java +++ /dev/null @@ -1,12 +0,0 @@ -package net.ornithemc.osl.networking.impl.interfaces.mixin; - -public interface ICustomPayloadPacket { - - // channel/data getters do exist in the Vanilla classes, - // but only in 13w41b and above, not in 13w41a - - String osl$networking$getChannel(); - - byte[] osl$networking$getData(); - -} diff --git a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java b/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java deleted file mode 100644 index a5519db4..00000000 --- a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java +++ /dev/null @@ -1,13 +0,0 @@ -package net.ornithemc.osl.networking.impl.interfaces.mixin; - -import java.util.Set; - -public interface INetworkHandler { - - boolean osl$networking$isPlayReady(); - - void osl$networking$registerChannels(Set channels); - - boolean osl$networking$isRegisteredChannel(String channel); - -} diff --git a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/CustomPayloadS2CPacketMixin.java b/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/CustomPayloadS2CPacketMixin.java deleted file mode 100644 index 2dcda1c8..00000000 --- a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/CustomPayloadS2CPacketMixin.java +++ /dev/null @@ -1,24 +0,0 @@ -package net.ornithemc.osl.networking.impl.mixin.client; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; - -import net.ornithemc.osl.networking.impl.interfaces.mixin.ICustomPayloadPacket; - -@Mixin(CustomPayloadS2CPacket.class) -public class CustomPayloadS2CPacketMixin implements ICustomPayloadPacket { - - @Shadow private String channel; - @Shadow private byte[] data; - - @Override - public String osl$networking$getChannel() { - return channel; - } - @Override - public byte[] osl$networking$getData() { - return data; - } -} diff --git a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java b/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java deleted file mode 100644 index e2311dd7..00000000 --- a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java +++ /dev/null @@ -1,24 +0,0 @@ -package net.ornithemc.osl.networking.impl.mixin.common; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; - -import net.ornithemc.osl.networking.impl.interfaces.mixin.ICustomPayloadPacket; - -@Mixin(CustomPayloadC2SPacket.class) -public class CustomPayloadC2SPacketMixin implements ICustomPayloadPacket { - - @Shadow private String channel; - @Shadow private byte[] data; - - @Override - public String osl$networking$getChannel() { - return channel; - } - @Override - public byte[] osl$networking$getData() { - return data; - } -} diff --git a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java b/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java deleted file mode 100644 index 150bf476..00000000 --- a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java +++ /dev/null @@ -1,309 +0,0 @@ -package net.ornithemc.osl.networking.impl.server; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.function.Supplier; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import net.minecraft.network.PacketByteBuf; -import net.minecraft.network.packet.Packet; -import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; -import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.entity.living.player.ServerPlayerEntity; -import net.minecraft.server.network.handler.ServerPlayNetworkHandler; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.Channels; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.api.PacketByteBufs; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.ByteArrayListener; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.ByteBufListener; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.PayloadListener; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; - -public final class ServerPlayNetworkingImpl { - - private static final Logger LOGGER = LogManager.getLogger("OSL|Server Play Networking"); - - private static MinecraftServer server; - - public static void setUp(MinecraftServer server) { - if (ServerPlayNetworkingImpl.server == server) { - throw new IllegalStateException("tried to set up server networking when it was already set up!"); - } - - ServerPlayNetworkingImpl.server = server; - } - - public static void destroy(MinecraftServer server) { - if (ServerPlayNetworkingImpl.server != server) { - throw new IllegalStateException("tried to destroy server networking when it was not set up!"); - } - - ServerPlayNetworkingImpl.server = null; - } - - public static final Map LISTENERS = new LinkedHashMap<>(); - - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - registerListenerImpl(channel, (server, handler, player, data) -> { - T payload = initializer.get(); - payload.read(PacketByteBufs.make(data)); - - return listener.handle(server, handler, player, payload); - }); - } - - public static void registerListener(String channel, ByteBufListener listener) { - registerListenerImpl(channel, (server, handler, player, data) -> { - return listener.handle(server, handler, player, PacketByteBufs.make(data)); - }); - } - - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - registerListenerImpl(channel, listener::handle); - } - - private static void registerListenerImpl(String channel, Listener listener) { - LISTENERS.compute(channel, (key, value) -> { - Channels.validate(channel); - - if (value != null) { - throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); - } - - return listener; - }); - } - - public static void unregisterListener(String channel) { - LISTENERS.remove(channel); - } - - public static boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, CustomPayloadC2SPacket packet) { - String channel = packet.getChannel(); - Listener listener = LISTENERS.get(channel); - - if (listener != null) { - try { - return listener.handle(server, handler, player, packet.getData()); - } catch (IOException e) { - LOGGER.warn("error handling custom payload on channel \'" + channel + "\'", e); - return true; - } - } - - return false; - } - - public static boolean isPlayReady(ServerPlayerEntity player) { - INetworkHandler handler = (INetworkHandler)player.networkHandler; - return handler != null && handler.osl$networking$isPlayReady(); - } - - public static boolean canSend(ServerPlayerEntity player, String channel) { - INetworkHandler handler = (INetworkHandler)player.networkHandler; - return handler != null && handler.osl$networking$isRegisteredChannel(channel); - } - - public static void send(ServerPlayerEntity player, String channel, CustomPayload payload) { - if (canSend(player, channel)) { - doSend(player, channel, payload); - } - } - - public static void send(ServerPlayerEntity player, String channel, IOConsumer writer) { - if (canSend(player, channel)) { - doSend(player, channel, writer); - } - } - - public static void send(ServerPlayerEntity player, String channel, PacketByteBuf data) { - if (canSend(player, channel)) { - doSend(player, channel, data); - } - } - - public static void send(ServerPlayerEntity player, String channel, byte[] data) { - if (canSend(player, channel)) { - doSend(player, channel, data); - } - } - - public static void send(Iterable players, String channel, CustomPayload payload) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, payload)); - } - - public static void send(Iterable players, String channel, IOConsumer writer) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, writer)); - } - - public static void send(Iterable players, String channel, PacketByteBuf data) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, data)); - } - - public static void send(Iterable players, String channel, byte[] data) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, data)); - } - - public static void send(int dimension, String channel, CustomPayload payload) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)), channel, payload); - } - - public static void send(int dimension, String channel, IOConsumer writer) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)), channel, writer); - } - - public static void send(int dimension, String channel, PacketByteBuf data) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)),channel, data); - } - - public static void send(int dimension, String channel, byte[] data) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)),channel, data); - } - - public static void send(String channel, CustomPayload payload) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, payload); - } - - public static void send(String channel, IOConsumer writer) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, writer); - } - - public static void send(String channel, PacketByteBuf data) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, data); - } - - public static void send(String channel, byte[] data) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, data); - } - - public static void doSend(ServerPlayerEntity player, String channel, CustomPayload payload) { - sendPacket(player, makePacket(channel, payload)); - } - - public static void doSend(ServerPlayerEntity player, String channel, IOConsumer writer) { - sendPacket(player, makePacket(channel, writer)); - } - - public static void doSend(ServerPlayerEntity player, String channel, PacketByteBuf data) { - sendPacket(player, makePacket(channel, data)); - } - - public static void doSend(ServerPlayerEntity player, String channel, byte[] data) { - sendPacket(player, makePacket(channel, data)); - } - - public static void doSend(Iterable players, String channel, CustomPayload payload) { - sendPacket(players, makePacket(channel, payload)); - } - - public static void doSend(Iterable players, String channel, IOConsumer writer) { - sendPacket(players, makePacket(channel, writer)); - } - - public static void doSend(Iterable players, String channel, PacketByteBuf data) { - sendPacket(players, makePacket(channel, data)); - } - - public static void doSend(Iterable players, String channel, byte[] data) { - sendPacket(players, makePacket(channel, data)); - } - - public static void doSend(int dimension, String channel, CustomPayload payload) { - doSend(collectPlayers(p -> p.dimension == dimension), channel, payload); - } - - public static void doSend(int dimension, String channel, IOConsumer writer) { - doSend(collectPlayers(p -> p.dimension == dimension), channel, writer); - } - - public static void doSend(int dimension, String channel, PacketByteBuf data) { - doSend(collectPlayers(p -> p.dimension == dimension),channel, data); - } - - public static void doSend(int dimension, String channel, byte[] data) { - doSend(collectPlayers(p -> p.dimension == dimension),channel, data); - } - - public static void doSend(String channel, CustomPayload payload) { - doSend(collectPlayers(p -> true), channel, payload); - } - - public static void doSend(String channel, IOConsumer writer) { - doSend(collectPlayers(p -> true), channel, writer); - } - - public static void doSend(String channel, PacketByteBuf data) { - doSend(collectPlayers(p -> true), channel, data); - } - - public static void doSend(String channel, byte[] data) { - doSend(collectPlayers(p -> true), channel, data); - } - - @SuppressWarnings("unchecked") // thanks proguard - private static Iterable collectPlayers(Predicate filter) { - return collectPlayers(server.getPlayerManager().players, filter); - } - - private static Iterable collectPlayers(Iterable src, Predicate filter) { - List players = new ArrayList<>(); - - for (ServerPlayerEntity player : src) { - if (filter.test(player)) { - players.add(player); - } - } - - return players; - } - - private static Packet makePacket(String channel, CustomPayload payload) { - return makePacket(channel, payload::write); - } - - private static Packet makePacket(String channel, IOConsumer writer) { - try { - return new CustomPayloadS2CPacket(channel, PacketByteBufs.make(writer)); - } catch (IOException e) { - LOGGER.warn("error writing custom payload to channel \'" + channel + "\'", e); - return null; - } - } - - private static Packet makePacket(String channel, PacketByteBuf data) { - return new CustomPayloadS2CPacket(channel, data); - } - - private static Packet makePacket(String channel, byte[] data) { - return new CustomPayloadS2CPacket(channel, data); - } - - private static void sendPacket(ServerPlayerEntity player, Packet packet) { - if (packet != null) { - player.networkHandler.sendPacket(packet); - } - } - - private static void sendPacket(Iterable players, Packet packet) { - if (packet != null) { - for (ServerPlayerEntity player : players) { - sendPacket(player, packet); - } - } - } - - private interface Listener { - - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mc13w41a-mc14w20b/build.gradle b/libraries/networking/networking-mc13w41a-mc18w30b/build.gradle similarity index 100% rename from libraries/networking/networking-mc13w41a-mc14w20b/build.gradle rename to libraries/networking/networking-mc13w41a-mc18w30b/build.gradle diff --git a/libraries/networking/networking-mc13w41a-mc18w30b/gradle.properties b/libraries/networking/networking-mc13w41a-mc18w30b/gradle.properties new file mode 100644 index 00000000..f397496b --- /dev/null +++ b/libraries/networking/networking-mc13w41a-mc18w30b/gradle.properties @@ -0,0 +1,7 @@ +environment = * +min_mc_version = 13w41a +max_mc_version = 18w30b +mc_version_range = >=1.7-alpha.13.41.a <=1.13.1-alpha.18.30.b + +minecraft_version = 18w30b +feather_build = 2 diff --git a/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/IdentifierChannelIdentifierParser.java b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/IdentifierChannelIdentifierParser.java new file mode 100644 index 00000000..e3de1820 --- /dev/null +++ b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/IdentifierChannelIdentifierParser.java @@ -0,0 +1,49 @@ +package net.ornithemc.osl.networking.api; + +import net.minecraft.resource.Identifier; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.impl.util.NamespacedIdentifierImpl; +import net.ornithemc.osl.networking.impl.ChannelIdentifierException; +import net.ornithemc.osl.networking.impl.ChannelIdentifierParseException; + +/** + * Utility methods for converting {@link NamespacedIdentifier}s from and to {@link Identifier}s. + */ +public final class IdentifierChannelIdentifierParser { + + /** + * Convert the given {@code Identifier} to a {@link NamespacedIdentifier}. + * The returned channel identifier may be invalid. + * + * @return the {@code NamespacedIdentifier} represented by the {@code Identifier}. + */ + public static NamespacedIdentifier fromIdentifier(Identifier id) { + return new NamespacedIdentifierImpl(id.getNamespace(), id.getPath()); + } + + /** + * Convert the given {@code Identifier} to a {@code NamespacedIdentifier}. + * The returned channel identifier is always valid. If no valid channel + * identifier can be parsed from the given identifier, an exception is + * thrown. + * + * @return the {@code NamespacedIdentifier} represented by the {@code Identifier}. + * @throws ChannelIdentifierParseException + * if no valid {@code NamespacedIdentifier} can be parsed from the given {@code Identifier}. + */ + public static NamespacedIdentifier fromIdentifierOrThrow(Identifier id) { + try { + return ChannelIdentifiers.from(id.getNamespace(), id.getPath()); + } catch (ChannelIdentifierException e) { + throw ChannelIdentifierParseException.invalid(id.toString(), e); + } + } + + /** + * Convert the given {@code NamespacedIdentifier} to its {@code Identifier} representation. + */ + public static Identifier toIdentifier(NamespacedIdentifier id) { + return new Identifier(id.namespace(), id.identifier()); + } +} diff --git a/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/PacketBuffer.java b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/PacketBuffer.java new file mode 100644 index 00000000..ebf33fb7 --- /dev/null +++ b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/PacketBuffer.java @@ -0,0 +1,1227 @@ +package net.ornithemc.osl.networking.api; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.channels.FileChannel; +import java.nio.channels.GatheringByteChannel; +import java.nio.channels.ScatteringByteChannel; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.UUID; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.util.ByteProcessor; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.resource.Identifier; +import net.minecraft.text.Text; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3i; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.NamespacedIdentifiers; + +public class PacketBuffer extends ByteBuf { + + private static final int VAR_VALUE_BITS = 7; + private static final int VAR_VALUE_MASK = 1 << VAR_VALUE_BITS - 1; + private static final int VAR_PARITY_VALUE = 1 << VAR_VALUE_BITS; + private static final int VAR_INT_MAX_BYTES = 5; + private static final int VAR_LONG_MAX_BYTES = 10; + + private static final int TEXT_JSON_MAX_LENGTH = 0x40000; + + // this module spans 13w41a-18w30b but BlockPos to long packing was added in 14w03a + private static final boolean SUPPORT_BLOCKPOS_PACKING = (BlockPos.class.getSuperclass() == Vec3i.class); + + final PacketByteBuf delegate; + + public PacketBuffer(ByteBuf delegate) { + this(new PacketByteBuf(delegate)); + } + + public PacketBuffer(PacketByteBuf delegate) { + this.delegate = delegate; + } + + public int readVarInt() { + return this.delegate.readVarInt(); + } + + public long readVarLong() { + long value = 0; + + byte bytes = 0; + byte nextByte = 0; + + do { + nextByte = this.readByte(); + value |= (nextByte & VAR_VALUE_MASK) << bytes++ * VAR_VALUE_BITS; + + if (bytes > VAR_LONG_MAX_BYTES) { + throw new RuntimeException("VarLong too big"); + } + } while ((nextByte & VAR_PARITY_VALUE) == VAR_PARITY_VALUE); + + return value; + } + + public byte[] readByteArray() { + return this.readByteArray(this.readableBytes()); + } + + public byte[] readByteArray(int maxLength) { + int length = this.readVarInt(); + + if (length > maxLength) { + throw new RuntimeException("ByteArray with size " + length + " is bigger than allowed " + maxLength); + } + + byte[] values = new byte[length]; + + for (int i = 0; i < length; i++) { + values[i] = this.readByte(); + } + + return values; + } + + public int[] readIntArray() { + return this.readIntArray(this.readableBytes()); + } + + public int[] readIntArray(int maxLength) { + int length = this.readVarInt(); + + if (length > maxLength) { + throw new RuntimeException("IntArray with size " + length + " is bigger than allowed " + maxLength); + } + + int[] values = new int[length]; + + for (int i = 0; i < length; i++) { + values[i] = this.readVarInt(); + } + + return values; + } + + public long[] readLongArray() { + return this.readLongArray(this.readableBytes() / 8); + } + + public long[] readLongArray(int maxLength) { + int length = this.readVarInt(); + + if (length > maxLength) { + throw new IllegalStateException("LongArray with size " + length + " is bigger than allowed " + maxLength); + } + + long[] values = new long[length]; + + for (int i = 0; i < length; i++) { + values[i] = this.readVarLong(); + } + + return values; + } + + public String readString() { + return this.readString(Short.MAX_VALUE); + } + + public String readString(int maxLength) { + int length = this.readVarInt(); + + if (length > maxLength * 4) { + throw new RuntimeException("The received encoded string buffer length is longer than maximum allowed (" + length + " > " + maxLength * 4 + ")"); + } + if (length < 0) { + throw new RuntimeException("The received encoded string buffer length is less than zero! Weird string!"); + } + + String s = this.toString(this.readerIndex(), length, StandardCharsets.UTF_8); + this.readerIndex(this.readerIndex() + length); + + if (s.length() > maxLength) { + throw new RuntimeException("The received string length is longer than maximum allowed (" + length + " > " + maxLength + ")"); + } + + return s; + } + + public > T readEnum(Class type) { + return type.getEnumConstants()[this.readVarInt()]; + } + + public Date readDate() { + return new Date(this.readLong()); + } + + public UUID readUuid() { + return new UUID( + this.readLong(), + this.readLong() + ); + } + + public BlockPos readBlockPos() { + if (SUPPORT_BLOCKPOS_PACKING) { + return BlockPos.fromLong(this.readLong()); + } else { + throw new UnsupportedOperationException("BlockPos packing is not supported in this Minecraft version!"); + } + } + + public Identifier readIdentifier() { + return new Identifier(this.readString()); + } + + public NamespacedIdentifier readNamespacedIdentifier() { + return NamespacedIdentifiers.parse(this.readString()); + } + + public Text readText() { + return Text.Serializer.fromJson(this.readString(TEXT_JSON_MAX_LENGTH)); + } + + public NbtCompound readNbtCompound() { + return this.delegate.readNbtCompound(); + } + + public ItemStack readItem() { + return this.delegate.readItem(); + } + + public ByteBuf writeVarInt(int value) { + return this.delegate.writeVarInt(value); + } + + public ByteBuf writeVarLong(long value) { + while ((value & -128) != 0) { + this.writeByte((int) (value & VAR_VALUE_MASK) | VAR_PARITY_VALUE); + value >>>= VAR_VALUE_BITS; + } + + this.writeByte((int) value); + + return this; + } + + public ByteBuf writeByteArray(byte[] values) { + this.writeVarInt(values.length); + + for (byte value : values) { + this.writeByte(value); + } + + return this; + } + + public ByteBuf writeIntArray(int[] values) { + this.writeVarInt(values.length); + + for (int value : values) { + this.writeVarInt(value); + } + + return this; + } + + public ByteBuf writeLongArray(long[] values) { + this.writeVarInt(values.length); + + for (long value : values) { + this.writeVarLong(value); + } + + return this; + } + + public ByteBuf writeString(String s) { + return this.writeString(s, Short.MAX_VALUE); + } + + public ByteBuf writeString(String s, int maxLength) { + byte[] bytes = s.getBytes(StandardCharsets.UTF_8); + + if (bytes.length > maxLength) { + throw new RuntimeException("String too big (was " + bytes.length + " bytes encoded, max " + maxLength + ")"); + } + + this.writeByteArray(bytes); + + return this; + } + + public ByteBuf writeEnum(Enum value) { + this.writeVarInt(value.ordinal()); + + return this; + } + + public ByteBuf writeDate(Date date) { + this.writeLong(date.getTime()); + + return this; + } + + public ByteBuf writeUuid(UUID uuid) { + this.writeLong(uuid.getMostSignificantBits()); + this.writeLong(uuid.getLeastSignificantBits()); + + return this; + } + + public ByteBuf writeBlockPos(BlockPos pos) { + if (SUPPORT_BLOCKPOS_PACKING) { + this.writeLong(pos.toLong()); + } else { + throw new UnsupportedOperationException("BlockPos packing is not supported in this Minecraft version!"); + } + + return this; + } + + public ByteBuf writeIdentifier(Identifier id) { + return this.writeString(id.toString()); + } + + public ByteBuf writeNamespacedIdentifier(NamespacedIdentifier id) { + return this.writeString(id.toString()); + } + + public ByteBuf writeText(Text text) { + return this.writeString(Text.Serializer.toJson(text), TEXT_JSON_MAX_LENGTH); + } + + public ByteBuf writeNbtCompound(NbtCompound nbt) { + return this.delegate.writeNbtCompound(nbt); + } + + public ByteBuf writeItem(ItemStack item) { + return this.delegate.writeItem(item); + } + + @Override + public int capacity() { + return this.delegate.capacity(); + } + + @Override + public ByteBuf capacity(int newCapacity) { + return this.delegate.capacity(newCapacity); + } + + @Override + public int maxCapacity() { + return this.delegate.maxCapacity(); + } + + @Override + public ByteBufAllocator alloc() { + return this.delegate.alloc(); + } + + @Override + public ByteOrder order() { + return this.delegate.order(); + } + + @Override + public ByteBuf order(ByteOrder order) { + return this.delegate.order(order); + } + + @Override + public ByteBuf unwrap() { + return this.delegate.unwrap(); + } + + @Override + public boolean isDirect() { + return this.delegate.isDirect(); + } + + @Override + public boolean isReadOnly() { + return this.delegate.isReadOnly(); + } + + @Override + public ByteBuf asReadOnly() { + return this.delegate.asReadOnly(); + } + + @Override + public int readerIndex() { + return this.delegate.readerIndex(); + } + + @Override + public ByteBuf readerIndex(int readerIndex) { + return this.delegate.readerIndex(readerIndex); + } + + @Override + public int writerIndex() { + return this.delegate.writerIndex(); + } + + @Override + public ByteBuf writerIndex(int writerIndex) { + return this.delegate.writerIndex(writerIndex); + } + + @Override + public ByteBuf setIndex(int readerIndex, int writerIndex) { + return this.delegate.setIndex(readerIndex, writerIndex); + } + + @Override + public int readableBytes() { + return this.delegate.readableBytes(); + } + + @Override + public int writableBytes() { + return this.delegate.writableBytes(); + } + + @Override + public int maxWritableBytes() { + return this.delegate.maxWritableBytes(); + } + + @Override + public boolean isReadable() { + return this.delegate.isReadable(); + } + + @Override + public boolean isReadable(int size) { + return this.delegate.isReadable(size); + } + + @Override + public boolean isWritable() { + return this.delegate.isWritable(); + } + + @Override + public boolean isWritable(int size) { + return this.delegate.isWritable(size); + } + + @Override + public ByteBuf clear() { + return this.delegate.clear(); + } + + @Override + public ByteBuf markReaderIndex() { + return this.delegate.markReaderIndex(); + } + + @Override + public ByteBuf resetReaderIndex() { + return this.delegate.resetReaderIndex(); + } + + @Override + public ByteBuf markWriterIndex() { + return this.delegate.markWriterIndex(); + } + + @Override + public ByteBuf resetWriterIndex() { + return this.delegate.resetWriterIndex(); + } + + @Override + public ByteBuf discardReadBytes() { + return this.delegate.discardReadBytes(); + } + + @Override + public ByteBuf discardSomeReadBytes() { + return this.delegate.discardSomeReadBytes(); + } + + @Override + public ByteBuf ensureWritable(int minWritableBytes) { + return this.delegate.ensureWritable(minWritableBytes); + } + + @Override + public int ensureWritable(int minWritableBytes, boolean force) { + return this.delegate.ensureWritable(minWritableBytes, force); + } + + @Override + public boolean getBoolean(int index) { + return this.delegate.getBoolean(index); + } + + @Override + public byte getByte(int index) { + return this.delegate.getByte(index); + } + + @Override + public short getUnsignedByte(int index) { + return this.delegate.getUnsignedByte(index); + } + + @Override + public short getShort(int index) { + return this.delegate.getShort(index); + } + + @Override + public short getShortLE(int index) { + return this.delegate.getShortLE(index); + } + + @Override + public int getUnsignedShort(int index) { + return this.delegate.getUnsignedShort(index); + } + + @Override + public int getUnsignedShortLE(int index) { + return this.delegate.getUnsignedShortLE(index); + } + + @Override + public int getMedium(int index) { + return this.delegate.getMedium(index); + } + + @Override + public int getMediumLE(int index) { + return this.delegate.getMediumLE(index); + } + + @Override + public int getUnsignedMedium(int index) { + return this.delegate.getUnsignedMedium(index); + } + + @Override + public int getUnsignedMediumLE(int index) { + return this.delegate.getUnsignedMediumLE(index); + } + + @Override + public int getInt(int index) { + return this.delegate.getInt(index); + } + + @Override + public int getIntLE(int index) { + return this.delegate.getIntLE(index); + } + + @Override + public long getUnsignedInt(int index) { + return this.delegate.getUnsignedInt(index); + } + + @Override + public long getUnsignedIntLE(int index) { + return this.delegate.getUnsignedIntLE(index); + } + + @Override + public long getLong(int index) { + return this.delegate.getLong(index); + } + + @Override + public long getLongLE(int index) { + return this.delegate.getLongLE(index); + } + + @Override + public char getChar(int index) { + return this.delegate.getChar(index); + } + + @Override + public float getFloat(int index) { + return this.delegate.getFloat(index); + } + + @Override + public double getDouble(int index) { + return this.delegate.getDouble(index); + } + + @Override + public ByteBuf getBytes(int index, ByteBuf dst) { + return this.delegate.getBytes(index, dst); + } + + @Override + public ByteBuf getBytes(int index, ByteBuf dst, int length) { + return this.delegate.getBytes(index, dst, length); + } + + @Override + public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) { + return this.delegate.getBytes(index, dst, dstIndex, length); + } + + @Override + public ByteBuf getBytes(int index, byte[] dst) { + return this.delegate.getBytes(index, dst); + } + + @Override + public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) { + return this.delegate.getBytes(index, dst, dstIndex, length); + } + + @Override + public ByteBuf getBytes(int index, ByteBuffer dst) { + return this.delegate.getBytes(index, dst); + } + + @Override + public ByteBuf getBytes(int index, OutputStream out, int length) throws IOException { + return this.delegate.getBytes(index, out, length); + } + + @Override + public int getBytes(int index, GatheringByteChannel out, int length) throws IOException { + return this.delegate.getBytes(index, out, length); + } + + @Override + public int getBytes(int index, FileChannel out, long position, int length) throws IOException { + return this.delegate.getBytes(index, out, position, length); + } + + @Override + public CharSequence getCharSequence(int index, int length, Charset charset) { + return this.delegate.getCharSequence(index, length, charset); + } + + @Override + public ByteBuf setBoolean(int index, boolean value) { + return this.delegate.setBoolean(index, value); + } + + @Override + public ByteBuf setByte(int index, int value) { + return this.delegate.setByte(index, value); + } + + @Override + public ByteBuf setShort(int index, int value) { + return this.delegate.setShort(index, value); + } + + @Override + public ByteBuf setShortLE(int index, int value) { + return this.delegate.setShortLE(index, value); + } + + @Override + public ByteBuf setMedium(int index, int value) { + return this.delegate.setMedium(index, value); + } + + @Override + public ByteBuf setMediumLE(int index, int value) { + return this.delegate.setMediumLE(index, value); + } + + @Override + public ByteBuf setInt(int index, int value) { + return this.delegate.setInt(index, value); + } + + @Override + public ByteBuf setIntLE(int index, int value) { + return this.delegate.setIntLE(index, value); + } + + @Override + public ByteBuf setLong(int index, long value) { + return this.delegate.setLong(index, value); + } + + @Override + public ByteBuf setLongLE(int index, long value) { + return this.delegate.setLongLE(index, value); + } + + @Override + public ByteBuf setChar(int index, int value) { + return this.delegate.setChar(index, value); + } + + @Override + public ByteBuf setFloat(int index, float value) { + return this.delegate.setFloat(index, value); + } + + @Override + public ByteBuf setDouble(int index, double value) { + return this.delegate.setDouble(index, value); + } + + @Override + public ByteBuf setBytes(int index, ByteBuf src) { + return this.delegate.setBytes(index, src); + } + + @Override + public ByteBuf setBytes(int index, ByteBuf src, int length) { + return this.delegate.setBytes(index, src, length); + } + + @Override + public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) { + return this.delegate.setBytes(index, src, srcIndex, length); + } + + @Override + public ByteBuf setBytes(int index, byte[] src) { + return this.delegate.setBytes(index, src); + } + + @Override + public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) { + return this.delegate.setBytes(index, src, srcIndex, length); + } + + @Override + public ByteBuf setBytes(int index, ByteBuffer src) { + return this.delegate.setBytes(index, src); + } + + @Override + public int setBytes(int index, InputStream in, int length) throws IOException { + return this.delegate.setBytes(index, in, length); + } + + @Override + public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException { + return this.delegate.setBytes(index, in, length); + } + + @Override + public int setBytes(int index, FileChannel in, long position, int length) throws IOException { + return this.delegate.setBytes(index, in, position, length); + } + + @Override + public ByteBuf setZero(int index, int length) { + return this.delegate.setZero(index, length); + } + + @Override + public int setCharSequence(int index, CharSequence sequence, Charset charset) { + return this.delegate.setCharSequence(index, sequence, charset); + } + + @Override + public boolean readBoolean() { + return this.delegate.readBoolean(); + } + + @Override + public byte readByte() { + return this.delegate.readByte(); + } + + @Override + public short readUnsignedByte() { + return this.delegate.readUnsignedByte(); + } + + @Override + public short readShort() { + return this.delegate.readShort(); + } + + @Override + public short readShortLE() { + return this.delegate.readShortLE(); + } + + @Override + public int readUnsignedShort() { + return this.delegate.readUnsignedShort(); + } + + @Override + public int readUnsignedShortLE() { + return this.delegate.readUnsignedShortLE(); + } + + @Override + public int readMedium() { + return this.delegate.readMedium(); + } + + @Override + public int readMediumLE() { + return this.delegate.readMediumLE(); + } + + @Override + public int readUnsignedMedium() { + return this.delegate.readUnsignedMedium(); + } + + @Override + public int readUnsignedMediumLE() { + return this.delegate.readUnsignedMediumLE(); + } + + @Override + public int readInt() { + return this.delegate.readInt(); + } + + @Override + public int readIntLE() { + return this.delegate.readIntLE(); + } + + @Override + public long readUnsignedInt() { + return this.delegate.readUnsignedInt(); + } + + @Override + public long readUnsignedIntLE() { + return this.delegate.readUnsignedIntLE(); + } + + @Override + public long readLong() { + return this.delegate.readLong(); + } + + @Override + public long readLongLE() { + return this.delegate.readLongLE(); + } + + @Override + public char readChar() { + return this.delegate.readChar(); + } + + @Override + public float readFloat() { + return this.delegate.readFloat(); + } + + @Override + public double readDouble() { + return this.delegate.readDouble(); + } + + @Override + public ByteBuf readBytes(int length) { + return this.delegate.readBytes(length); + } + + @Override + public ByteBuf readSlice(int length) { + return this.delegate.readSlice(length); + } + + @Override + public ByteBuf readRetainedSlice(int length) { + return this.delegate.readRetainedSlice(length); + } + + @Override + public ByteBuf readBytes(ByteBuf dst) { + return this.delegate.readBytes(dst); + } + + @Override + public ByteBuf readBytes(ByteBuf dst, int length) { + return this.delegate.readBytes(dst, length); + } + + @Override + public ByteBuf readBytes(ByteBuf dst, int dstIndex, int length) { + return this.delegate.readBytes(dst, dstIndex, length); + } + + @Override + public ByteBuf readBytes(byte[] dst) { + return this.delegate.readBytes(dst); + } + + @Override + public ByteBuf readBytes(byte[] dst, int dstIndex, int length) { + return this.delegate.readBytes(dst, dstIndex, length); + } + + @Override + public ByteBuf readBytes(ByteBuffer dst) { + return this.delegate.readBytes(dst); + } + + @Override + public ByteBuf readBytes(OutputStream out, int length) throws IOException { + return this.delegate.readBytes(out, length); + } + + @Override + public int readBytes(GatheringByteChannel out, int length) throws IOException { + return this.delegate.readBytes(out, length); + } + + @Override + public CharSequence readCharSequence(int length, Charset charset) { + return this.delegate.readCharSequence(length, charset); + } + + @Override + public int readBytes(FileChannel out, long position, int length) throws IOException { + return this.delegate.readBytes(out, position, length); + } + + @Override + public ByteBuf skipBytes(int length) { + return this.delegate.skipBytes(length); + } + + @Override + public ByteBuf writeBoolean(boolean value) { + return this.delegate.writeBoolean(value); + } + + @Override + public ByteBuf writeByte(int value) { + return this.delegate.writeByte(value); + } + + @Override + public ByteBuf writeShort(int value) { + return this.delegate.writeShort(value); + } + + @Override + public ByteBuf writeShortLE(int value) { + return this.delegate.writeShortLE(value); + } + + @Override + public ByteBuf writeMedium(int value) { + return this.delegate.writeMedium(value); + } + + @Override + public ByteBuf writeMediumLE(int value) { + return this.delegate.writeMediumLE(value); + } + + @Override + public ByteBuf writeInt(int value) { + return this.delegate.writeInt(value); + } + + @Override + public ByteBuf writeIntLE(int value) { + return this.delegate.writeIntLE(value); + } + + @Override + public ByteBuf writeLong(long value) { + return this.delegate.writeLong(value); + } + + @Override + public ByteBuf writeLongLE(long value) { + return this.delegate.writeLongLE(value); + } + + @Override + public ByteBuf writeChar(int value) { + return this.delegate.writeChar(value); + } + + @Override + public ByteBuf writeFloat(float value) { + return this.delegate.writeFloat(value); + } + + @Override + public ByteBuf writeDouble(double value) { + return this.delegate.writeDouble(value); + } + + @Override + public ByteBuf writeBytes(ByteBuf src) { + return this.delegate.writeBytes(src); + } + + @Override + public ByteBuf writeBytes(ByteBuf src, int length) { + return this.delegate.writeBytes(src, length); + } + + @Override + public ByteBuf writeBytes(ByteBuf src, int srcIndex, int length) { + return this.delegate.writeBytes(src, srcIndex, length); + } + + @Override + public ByteBuf writeBytes(byte[] src) { + return this.delegate.writeBytes(src); + } + + @Override + public ByteBuf writeBytes(byte[] src, int srcIndex, int length) { + return this.delegate.writeBytes(src, srcIndex, length); + } + + @Override + public ByteBuf writeBytes(ByteBuffer src) { + return this.delegate.writeBytes(src); + } + + @Override + public int writeBytes(InputStream in, int length) throws IOException { + return this.delegate.writeBytes(in, length); + } + + @Override + public int writeBytes(ScatteringByteChannel in, int length) throws IOException { + return this.delegate.writeBytes(in, length); + } + + @Override + public int writeBytes(FileChannel in, long position, int length) throws IOException { + return this.delegate.writeBytes(in, position, length); + } + + @Override + public ByteBuf writeZero(int length) { + return this.delegate.writeZero(length); + } + + @Override + public int writeCharSequence(CharSequence sequence, Charset charset) { + return this.delegate.writeCharSequence(sequence, charset); + } + + @Override + public int indexOf(int fromIndex, int toIndex, byte value) { + return this.delegate.indexOf(fromIndex, toIndex, value); + } + + @Override + public int bytesBefore(byte value) { + return this.delegate.bytesBefore(value); + } + + @Override + public int bytesBefore(int length, byte value) { + return this.delegate.bytesBefore(length, value); + } + + @Override + public int bytesBefore(int index, int length, byte value) { + return this.delegate.bytesBefore(index, length, value); + } + + @Override + public int forEachByte(ByteProcessor processor) { + return this.delegate.forEachByte(processor); + } + + @Override + public int forEachByte(int index, int length, ByteProcessor processor) { + return this.delegate.forEachByte(index, length, processor); + } + + @Override + public int forEachByteDesc(ByteProcessor processor) { + return this.delegate.forEachByteDesc(processor); + } + + @Override + public int forEachByteDesc(int index, int length, ByteProcessor processor) { + return this.delegate.forEachByteDesc(index, length, processor); + } + + @Override + public ByteBuf copy() { + return this.delegate.copy(); + } + + @Override + public ByteBuf copy(int index, int length) { + return this.delegate.copy(index, length); + } + + @Override + public ByteBuf slice() { + return this.delegate.slice(); + } + + @Override + public ByteBuf retainedSlice() { + return this.delegate.retainedSlice(); + } + + @Override + public ByteBuf slice(int index, int length) { + return this.delegate.slice(index, length); + } + + @Override + public ByteBuf retainedSlice(int index, int length) { + return this.delegate.retainedSlice(index, length); + } + + @Override + public ByteBuf duplicate() { + return this.delegate.duplicate(); + } + + @Override + public ByteBuf retainedDuplicate() { + return this.delegate.retainedDuplicate(); + } + + @Override + public int nioBufferCount() { + return this.delegate.nioBufferCount(); + } + + @Override + public ByteBuffer nioBuffer() { + return this.delegate.nioBuffer(); + } + + @Override + public ByteBuffer nioBuffer(int index, int length) { + return this.delegate.nioBuffer(index, length); + } + + @Override + public ByteBuffer internalNioBuffer(int index, int length) { + return this.delegate.internalNioBuffer(index, length); + } + + @Override + public ByteBuffer[] nioBuffers() { + return this.delegate.nioBuffers(); + } + + @Override + public ByteBuffer[] nioBuffers(int index, int length) { + return this.delegate.nioBuffers(index, length); + } + + @Override + public boolean hasArray() { + return this.delegate.hasArray(); + } + + @Override + public byte[] array() { + return this.delegate.array(); + } + + @Override + public int arrayOffset() { + return this.delegate.arrayOffset(); + } + + @Override + public boolean hasMemoryAddress() { + return this.delegate.hasMemoryAddress(); + } + + @Override + public long memoryAddress() { + return this.delegate.memoryAddress(); + } + + @Override + public String toString(Charset charset) { + return this.delegate.toString(charset); + } + + @Override + public String toString(int index, int length, Charset charset) { + return this.delegate.toString(index, length, charset); + } + + @Override + public int hashCode() { + return this.delegate.hashCode(); + } + + @Override + public boolean equals(Object o) { + return this.delegate.equals(o); + } + + @Override + public int compareTo(ByteBuf o) { + return this.delegate.compareTo(o); + } + + @Override + public String toString() { + return this.delegate.toString(); + } + + @Override + public ByteBuf retain(int increment) { + return this.delegate.retain(increment); + } + + @Override + public ByteBuf retain() { + return this.delegate.retain(); + } + + @Override + public ByteBuf touch() { + return this.delegate.touch(); + } + + @Override + public ByteBuf touch(Object hint) { + return this.delegate.touch(hint); + } + + @Override + public int refCnt() { + return this.delegate.refCnt(); + } + + @Override + public boolean release() { + return this.delegate.release(); + } + + @Override + public boolean release(int decrement) { + return this.delegate.release(decrement); + } +} diff --git a/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/PacketBuffers.java b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/PacketBuffers.java new file mode 100644 index 00000000..516f6420 --- /dev/null +++ b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/PacketBuffers.java @@ -0,0 +1,41 @@ +package net.ornithemc.osl.networking.api; + +import java.io.IOException; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; + +import net.minecraft.network.PacketByteBuf; + +import net.ornithemc.osl.core.api.util.function.IOConsumer; + +public final class PacketBuffers { + + public static PacketBuffer make() { + return wrapped(Unpooled.buffer()); + } + + public static PacketBuffer make(IOConsumer writer) throws IOException { + PacketBuffer buffer = make(); + writer.accept(buffer); + return buffer; + } + + public static PacketBuffer wrap(byte[] bytes) { + return wrapped(Unpooled.wrappedBuffer(bytes)); + } + + public static byte[] unwrap(PacketBuffer buffer) { + byte[] bytes = new byte[buffer.writerIndex()]; + buffer.getBytes(0, bytes); + return bytes; + } + + public static PacketBuffer wrapped(ByteBuf buffer) { + return new PacketBuffer(buffer); + } + + public static PacketByteBuf unwrapped(PacketBuffer buffer) { + return buffer.delegate; + } +} diff --git a/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/PacketPayload.java b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/PacketPayload.java new file mode 100644 index 00000000..7f7835e7 --- /dev/null +++ b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/PacketPayload.java @@ -0,0 +1,11 @@ +package net.ornithemc.osl.networking.api; + +import java.io.IOException; + +public interface PacketPayload { + + void read(PacketBuffer buffer) throws IOException; + + void write(PacketBuffer buffer) throws IOException; + +} diff --git a/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java similarity index 100% rename from libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java rename to libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java diff --git a/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPacketListener.java b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPacketListener.java new file mode 100644 index 00000000..1e24b0e4 --- /dev/null +++ b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPacketListener.java @@ -0,0 +1,31 @@ +package net.ornithemc.osl.networking.api.client; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.network.handler.ClientPlayNetworkHandler; + +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketPayload; + +public interface ClientPacketListener { + + /** + * Receive incoming data from the server. + * + * @return + * Whether the data is consumed. Should only return {@code false} if the + * data is completely ignored. + */ + boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, T data); + + @FunctionalInterface + public interface Payload extends ClientPacketListener { + } + + @FunctionalInterface + public interface Buffer extends ClientPacketListener { + } + + @FunctionalInterface + public interface Bytes extends ClientPacketListener { + } +} diff --git a/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java new file mode 100644 index 00000000..06d6ff52 --- /dev/null +++ b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java @@ -0,0 +1,153 @@ +package net.ornithemc.osl.networking.api.client; + +import java.util.function.Supplier; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.function.IOConsumer; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketPayload; +import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; + +public final class ClientPlayNetworking { + + /** + * Register a listener to receive data from the server through the given channel. + * This listener will only be called from the main thread. + */ + public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { + ClientPlayNetworkingImpl.registerListener(channel, initializer, listener); + } + + /** + * Register a listener to receive data from the server through the given channel. + * This listener may be called off the main thread. + */ + public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { + ClientPlayNetworkingImpl.registerListenerAsync(channel, initializer, listener); + } + + /** + * Register a listener to receive data from the server through the given channel. + * This listener will only be called from the main thread. + */ + public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { + ClientPlayNetworkingImpl.registerListener(channel, listener); + } + + /** + * Register a listener to receive data from the server through the given channel. + * This listener may be called off the main thread. + */ + public static void registerListenerAsync(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { + ClientPlayNetworkingImpl.registerListenerAsync(channel, listener); + } + + /** + * Register a listener to receive data from the server through the given channel. + * This listener will only be called from the main thread. + */ + public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { + ClientPlayNetworkingImpl.registerListener(channel, listener); + } + + /** + * Register a listener to receive data from the server through the given channel. + * This listener may be called off the main thread. + */ + public static void registerListenerAsync(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { + ClientPlayNetworkingImpl.registerListenerAsync(channel, listener); + } + + /** + * Remove the listener registered to the given channel. + */ + public static void unregisterListener(NamespacedIdentifier channel) { + ClientPlayNetworkingImpl.unregisterListener(channel); + } + + /** + * Check whether the connection is ready for data to be sent to the server. + */ + public static boolean isPlayReady() { + return ClientPlayNetworkingImpl.isPlayReady(); + } + + /** + * Check whether the given channel is open for data to be sent through it. + * This method will return {@code false} if the client is not connected to a + * server, or if the server has no listeners for the given channel. + */ + public static boolean isPlayReady(NamespacedIdentifier channel) { + return ClientPlayNetworkingImpl.isPlayReady(channel); + } + + /** + * Send a packet to the server through the given channel. The payload will + * only be written if the channel is open. + */ + public static void send(NamespacedIdentifier channel, PacketPayload payload) { + ClientPlayNetworkingImpl.send(channel, payload); + } + + /** + * Send a packet to the server through the given channel. The writer will + * only be called if the channel is open. + */ + public static void send(NamespacedIdentifier channel, IOConsumer writer) { + ClientPlayNetworkingImpl.send(channel, writer); + } + + /** + * Send a packet to the server through the given channel. + */ + public static void send(NamespacedIdentifier channel, PacketBuffer buffer) { + ClientPlayNetworkingImpl.send(channel, buffer); + } + + /** + * Send a packet to the server through the given channel. + */ + public static void send(NamespacedIdentifier channel, byte[] bytes) { + ClientPlayNetworkingImpl.send(channel, bytes); + } + + /** + * Send a packet to the server through the given channel, without checking + * whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the server. + */ + public static void sendNoCheck(NamespacedIdentifier channel, PacketPayload payload) { + ClientPlayNetworkingImpl.sendNoCheck(channel, payload); + } + + /** + * Send a packet to the server through the given channel, without checking + * whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the server. + */ + public static void sendNoCheck(NamespacedIdentifier channel, IOConsumer writer) { + ClientPlayNetworkingImpl.sendNoCheck(channel, writer); + } + + /** + * Send a packet to the server through the given channel, without checking + * whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the server. + */ + public static void sendNoCheck(NamespacedIdentifier channel, PacketBuffer buffer) { + ClientPlayNetworkingImpl.sendNoCheck(channel, buffer); + } + + /** + * Send a packet to the server through the given channel, without checking + * whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the server. + */ + public static void sendNoCheck(NamespacedIdentifier channel, byte[] bytes) { + ClientPlayNetworkingImpl.sendNoCheck(channel, bytes); + } +} diff --git a/libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java similarity index 100% rename from libraries/networking/networking-mc1.13-pre4-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java rename to libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java diff --git a/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java new file mode 100644 index 00000000..fc0a43a7 --- /dev/null +++ b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java @@ -0,0 +1,32 @@ +package net.ornithemc.osl.networking.api.server; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.entity.living.player.ServerPlayerEntity; +import net.minecraft.server.network.handler.ServerPlayNetworkHandler; + +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketPayload; + +public interface ServerPacketListener { + + /** + * Receive incoming data from the client. + * + * @return + * Whether the data is consumed. Should only return {@code false} if the + * data is completely ignored. + */ + boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, T data); + + @FunctionalInterface + public interface Payload extends ServerPacketListener { + } + + @FunctionalInterface + public interface Buffer extends ServerPacketListener { + } + + @FunctionalInterface + public interface Bytes extends ServerPacketListener { + } +} diff --git a/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java similarity index 52% rename from libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java rename to libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java index f8ebbf6a..3df6fc42 100644 --- a/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java +++ b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java @@ -1,15 +1,13 @@ package net.ornithemc.osl.networking.api.server; -import java.io.IOException; import java.util.function.Supplier; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.server.MinecraftServer; import net.minecraft.server.entity.living.player.ServerPlayerEntity; -import net.minecraft.server.network.handler.ServerPlayNetworkHandler; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.CustomPayload; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketPayload; import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; public final class ServerPlayNetworking { @@ -17,61 +15,55 @@ public final class ServerPlayNetworking { /** * Register a listener to receive data from the server through the given channel. * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. */ - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { + public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { ServerPlayNetworkingImpl.registerListener(channel, initializer, listener); } /** * Register a listener to receive data from the server through the given channel. * This listener may be called off the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. */ - public static void registerListenerAsync(String channel, Supplier initializer, PayloadListener listener) { + public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { ServerPlayNetworkingImpl.registerListenerAsync(channel, initializer, listener); } /** * Register a listener to receive data from the server through the given channel. * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. */ - public static void registerListener(String channel, ByteBufListener listener) { + public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { ServerPlayNetworkingImpl.registerListener(channel, listener); } /** * Register a listener to receive data from the server through the given channel. * This listener may be called off the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. */ - public static void registerListenerAsync(String channel, ByteBufListener listener) { + public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { ServerPlayNetworkingImpl.registerListenerAsync(channel, listener); } /** * Register a listener to receive data from the server through the given channel. * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. */ - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - ServerPlayNetworkingImpl.registerListenerRaw(channel, listener); + public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { + ServerPlayNetworkingImpl.registerListener(channel, listener); } /** * Register a listener to receive data from the server through the given channel. * This listener may be called off the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. */ - public static void registerListenerRawAsync(String channel, ByteArrayListener listener) { - ServerPlayNetworkingImpl.registerListenerRawAsync(channel, listener); + public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { + ServerPlayNetworkingImpl.registerListenerAsync(channel, listener); } /** * Remove the listener registered to the given channel. */ - public static void unregisterListener(String channel) { + public static void unregisterListener(NamespacedIdentifier channel) { ServerPlayNetworkingImpl.unregisterListener(channel); } @@ -83,19 +75,19 @@ public static boolean isPlayReady(ServerPlayerEntity player) { } /** - * Check whether the given channel is open for data to be sent through it. + * Check whether the given channel is ready for data to be sent through it. * This method will return {@code false} if the client has no listeners for * the given channel. */ - public static boolean canSend(ServerPlayerEntity player, String channel) { - return ServerPlayNetworkingImpl.canSend(player, channel); + public static boolean isPlayReady(ServerPlayerEntity player, NamespacedIdentifier channel) { + return ServerPlayNetworkingImpl.isPlayReady(player, channel); } /** * Send a packet to the given player through the given channel. The payload * will only be written if the channel is open. */ - public static void send(ServerPlayerEntity player, String channel, CustomPayload payload) { + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, PacketPayload payload) { ServerPlayNetworkingImpl.send(player, channel, payload); } @@ -103,29 +95,29 @@ public static void send(ServerPlayerEntity player, String channel, CustomPayload * Send a packet to the given player through the given channel. The writer * will only be called if the channel is open. */ - public static void send(ServerPlayerEntity player, String channel, IOConsumer writer) { + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, IOConsumer writer) { ServerPlayNetworkingImpl.send(player, channel, writer); } /** * Send a packet to the given player through the given channel. */ - public static void send(ServerPlayerEntity player, String channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.send(player, channel, data); + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, PacketBuffer buffer) { + ServerPlayNetworkingImpl.send(player, channel, buffer); } /** * Send a packet to the given player through the given channel. */ - public static void send(ServerPlayerEntity player, String channel, byte[] data) { - ServerPlayNetworkingImpl.send(player, channel, data); + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, byte[] bytes) { + ServerPlayNetworkingImpl.send(player, channel, bytes); } /** * Send a packet to the given players through the given channel. The payload * will only be written if the channel is open for at least one player. */ - public static void send(Iterable players, String channel, CustomPayload payload) { + public static void send(Iterable players, NamespacedIdentifier channel, PacketPayload payload) { ServerPlayNetworkingImpl.send(players, channel, payload); } @@ -133,22 +125,22 @@ public static void send(Iterable players, String channel, Cu * Send a packet to the given players through the given channel. The writer * will only be called if the channel is open for at least one player. */ - public static void send(Iterable players, String channel, IOConsumer writer) { + public static void send(Iterable players, NamespacedIdentifier channel, IOConsumer writer) { ServerPlayNetworkingImpl.send(players, channel, writer); } /** * Send a packet to the given players through the given channel. */ - public static void send(Iterable players, String channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.send(players, channel, data); + public static void send(Iterable players, NamespacedIdentifier channel, PacketBuffer buffer) { + ServerPlayNetworkingImpl.send(players, channel, buffer); } /** * Send a packet to the given players through the given channel. */ - public static void send(Iterable players, String channel, byte[] data) { - ServerPlayNetworkingImpl.send(players, channel, data); + public static void send(Iterable players, NamespacedIdentifier channel, byte[] bytes) { + ServerPlayNetworkingImpl.send(players, channel, bytes); } /** @@ -156,7 +148,7 @@ public static void send(Iterable players, String channel, by * channel. The payload will only be written if the channel is open for at * least one player. */ - public static void send(int dimension, String channel, CustomPayload payload) { + public static void send(int dimension, NamespacedIdentifier channel, PacketPayload payload) { ServerPlayNetworkingImpl.send(dimension, channel, payload); } @@ -165,7 +157,7 @@ public static void send(int dimension, String channel, CustomPayload payload) { * channel. The writer will only be called if the channel is open for at * least one player. */ - public static void send(int dimension, String channel, IOConsumer writer) { + public static void send(int dimension, NamespacedIdentifier channel, IOConsumer writer) { ServerPlayNetworkingImpl.send(dimension, channel, writer); } @@ -173,23 +165,23 @@ public static void send(int dimension, String channel, IOConsumer * Send a packet to the players in the given dimension through the given * channel. */ - public static void send(int dimension, String channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.send(dimension, channel, data); + public static void send(int dimension, NamespacedIdentifier channel, PacketBuffer buffer) { + ServerPlayNetworkingImpl.send(dimension, channel, buffer); } /** * Send a packet to the players in the given dimension through the given * channel. */ - public static void send(int dimension, String channel, byte[] data) { - ServerPlayNetworkingImpl.send(dimension, channel, data); + public static void send(int dimension, NamespacedIdentifier channel, byte[] bytes) { + ServerPlayNetworkingImpl.send(dimension, channel, bytes); } /** * Send a packet to all players through the given channel. The payload will * only be written if the channel is open for at least one player. */ - public static void send(String channel, CustomPayload payload) { + public static void send(NamespacedIdentifier channel, PacketPayload payload) { ServerPlayNetworkingImpl.send(channel, payload); } @@ -197,22 +189,22 @@ public static void send(String channel, CustomPayload payload) { * Send a packet to all players through the given channel. The writer will * only be called if the channel is open for at least one player. */ - public static void send(String channel, IOConsumer writer) { + public static void send(NamespacedIdentifier channel, IOConsumer writer) { ServerPlayNetworkingImpl.send(channel, writer); } /** * Send a packet to all players through the given channel. */ - public static void send(String channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.send(channel, data); + public static void send(NamespacedIdentifier channel, PacketBuffer buffer) { + ServerPlayNetworkingImpl.send(channel, buffer); } /** * Send a packet to all players through the given channel. */ - public static void send(String channel, byte[] data) { - ServerPlayNetworkingImpl.send(channel, data); + public static void send(NamespacedIdentifier channel, byte[] bytes) { + ServerPlayNetworkingImpl.send(channel, bytes); } /** @@ -221,8 +213,8 @@ public static void send(String channel, byte[] data) { * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(ServerPlayerEntity player, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(player, channel, payload); + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, PacketPayload payload) { + ServerPlayNetworkingImpl.sendNoCheck(player, channel, payload); } /** @@ -231,8 +223,8 @@ public static void doSend(ServerPlayerEntity player, String channel, CustomPaylo * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(ServerPlayerEntity player, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(player, channel, writer); + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, IOConsumer writer) { + ServerPlayNetworkingImpl.sendNoCheck(player, channel, writer); } /** @@ -241,8 +233,8 @@ public static void doSend(ServerPlayerEntity player, String channel, IOConsumer< * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(ServerPlayerEntity player, String channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.doSend(player, channel, data); + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, PacketBuffer buffer) { + ServerPlayNetworkingImpl.sendNoCheck(player, channel, buffer); } /** @@ -251,8 +243,8 @@ public static void doSend(ServerPlayerEntity player, String channel, PacketByteB * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(ServerPlayerEntity player, String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(player, channel, data); + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, byte[] bytes) { + ServerPlayNetworkingImpl.sendNoCheck(player, channel, bytes); } /** @@ -261,8 +253,8 @@ public static void doSend(ServerPlayerEntity player, String channel, byte[] data * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(Iterable players, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(players, channel, payload); + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, PacketPayload payload) { + ServerPlayNetworkingImpl.sendNoCheck(players, channel, payload); } /** @@ -271,8 +263,8 @@ public static void doSend(Iterable players, String channel, * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(Iterable players, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(players, channel, writer); + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, IOConsumer writer) { + ServerPlayNetworkingImpl.sendNoCheck(players, channel, writer); } /** @@ -281,8 +273,8 @@ public static void doSend(Iterable players, String channel, * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(Iterable players, String channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.doSend(players, channel, data); + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, PacketBuffer buffer) { + ServerPlayNetworkingImpl.sendNoCheck(players, channel, buffer); } /** @@ -291,8 +283,8 @@ public static void doSend(Iterable players, String channel, * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(Iterable players, String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(players, channel, data); + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, byte[] bytes) { + ServerPlayNetworkingImpl.sendNoCheck(players, channel, bytes); } /** @@ -301,8 +293,8 @@ public static void doSend(Iterable players, String channel, * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(int dimension, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(dimension, channel, payload); + public static void sendNoCheck(int dimension, NamespacedIdentifier channel, PacketPayload payload) { + ServerPlayNetworkingImpl.sendNoCheck(dimension, channel, payload); } /** @@ -311,8 +303,8 @@ public static void doSend(int dimension, String channel, CustomPayload payload) * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(int dimension, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(dimension, channel, writer); + public static void sendNoCheck(int dimension, NamespacedIdentifier channel, IOConsumer writer) { + ServerPlayNetworkingImpl.sendNoCheck(dimension, channel, writer); } /** @@ -321,8 +313,8 @@ public static void doSend(int dimension, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(channel, writer); + public static void sendNoCheck(NamespacedIdentifier channel, IOConsumer writer) { + ServerPlayNetworkingImpl.sendNoCheck(channel, writer); } /** @@ -361,8 +353,8 @@ public static void doSend(String channel, IOConsumer writer) { * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(String channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.doSend(channel, data); + public static void sendNoCheck(NamespacedIdentifier channel, PacketBuffer buffer) { + ServerPlayNetworkingImpl.sendNoCheck(channel, buffer); } /** @@ -371,46 +363,7 @@ public static void doSend(String channel, PacketByteBuf data) { * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(channel, data); - } - - public interface PayloadListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, T payload) throws IOException; - - } - - public interface ByteBufListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, PacketByteBuf data) throws IOException; - - } - - public interface ByteArrayListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] data) throws IOException; - + public static void sendNoCheck(NamespacedIdentifier channel, byte[] bytes) { + ServerPlayNetworkingImpl.sendNoCheck(channel, bytes); } } diff --git a/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java new file mode 100644 index 00000000..27d46bc9 --- /dev/null +++ b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java @@ -0,0 +1,61 @@ +package net.ornithemc.osl.networking.impl; + +import java.io.IOException; +import java.util.LinkedHashSet; +import java.util.Set; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.api.ChannelIdentifiers; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketPayload; +import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; +import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; + +public class HandshakePayload implements PacketPayload { + + public static final NamespacedIdentifier CHANNEL = Constants.OSL_HANDSHAKE_CHANNEL; + + public byte protocol; + public Set channels; + + public HandshakePayload() { + } + + public HandshakePayload(Set channels) { + this.protocol = Constants.OSL_HANDSHAKE_PROTOCOL; + // we allow registering listeners on channels that do not conform to OSL spec + // but payloads sent over these channels aren't sent via OSL so we can ignore + // them for the OSL handshake. + this.channels = ChannelIdentifiers.dropInvalid(channels); + } + + public static HandshakePayload client() { + return new HandshakePayload(ClientPlayNetworkingImpl.CHANNEL_LISTENERS.keySet()); + } + + public static HandshakePayload server() { + return new HandshakePayload(ServerPlayNetworkingImpl.CHANNEL_LISTENERS.keySet()); + } + + @Override + public void read(PacketBuffer buffer) throws IOException { + protocol = buffer.readByte(); + channels = new LinkedHashSet<>(); + + int channelCount = buffer.readInt(); + + for (int i = 0; i < channelCount; i++) { + channels.add(buffer.readNamespacedIdentifier()); + } + } + + @Override + public void write(PacketBuffer buffer) throws IOException { + buffer.writeByte(protocol); + buffer.writeInt(channels.size()); + + for (NamespacedIdentifier channel : channels) { + buffer.writeNamespacedIdentifier(channel); + } + } +} diff --git a/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/PacketFactory.java b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/PacketFactory.java new file mode 100644 index 00000000..d2d5f3d6 --- /dev/null +++ b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/PacketFactory.java @@ -0,0 +1,15 @@ +package net.ornithemc.osl.networking.impl; + +import net.minecraft.network.packet.Packet; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.api.PacketBuffer; + +@FunctionalInterface +public interface PacketFactory { + + // Packet is not generic prior to 14w31a + @SuppressWarnings("rawtypes") + Packet create(NamespacedIdentifier channel, PacketBuffer data); + +} diff --git a/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/access/CustomPayloadPacketAccess.java b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/access/CustomPayloadPacketAccess.java new file mode 100644 index 00000000..3241aa75 --- /dev/null +++ b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/access/CustomPayloadPacketAccess.java @@ -0,0 +1,12 @@ +package net.ornithemc.osl.networking.impl.access; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.api.PacketBuffer; + +public interface CustomPayloadPacketAccess { + + NamespacedIdentifier osl$networking$getChannel(); + + PacketBuffer osl$networking$getData(); + +} diff --git a/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/access/NetworkHandlerAccess.java b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/access/NetworkHandlerAccess.java new file mode 100644 index 00000000..d3e3c4e0 --- /dev/null +++ b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/access/NetworkHandlerAccess.java @@ -0,0 +1,15 @@ +package net.ornithemc.osl.networking.impl.access; + +import java.util.Set; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; + +public interface NetworkHandlerAccess { + + boolean osl$networking$isPlayReady(); + + boolean osl$networking$isPlayReady(NamespacedIdentifier channel); + + void osl$networking$registerChannels(Set channels); + +} diff --git a/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/access/PlayerManagerAccess.java b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/access/PlayerManagerAccess.java new file mode 100644 index 00000000..6fc92ae4 --- /dev/null +++ b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/access/PlayerManagerAccess.java @@ -0,0 +1,11 @@ +package net.ornithemc.osl.networking.impl.access; + +import java.util.List; + +import net.minecraft.server.entity.living.player.ServerPlayerEntity; + +public interface PlayerManagerAccess { + + List osl$networking$getAll(); + +} diff --git a/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/access/TaskRunnerAccess.java b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/access/TaskRunnerAccess.java new file mode 100644 index 00000000..bff1ba39 --- /dev/null +++ b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/access/TaskRunnerAccess.java @@ -0,0 +1,7 @@ +package net.ornithemc.osl.networking.impl.access; + +public interface TaskRunnerAccess { + + boolean osl$networking$submit(Runnable task); + +} diff --git a/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java new file mode 100644 index 00000000..32dd8d57 --- /dev/null +++ b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java @@ -0,0 +1,267 @@ +package net.ornithemc.osl.networking.impl.client; + +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.function.Supplier; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.network.handler.ClientPlayNetworkHandler; +import net.minecraft.network.packet.Packet; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.function.IOConsumer; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketBuffers; +import net.ornithemc.osl.networking.api.PacketPayload; +import net.ornithemc.osl.networking.api.client.ClientPacketListener; +import net.ornithemc.osl.networking.impl.PacketFactory; +import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; +import net.ornithemc.osl.networking.impl.access.TaskRunnerAccess; + +public final class ClientPlayNetworkingImpl { + + private static final Logger LOGGER = LogManager.getLogger("OSL|Client Play Networking"); + + private static PacketFactory packetFactory; + private static Minecraft minecraft; + private static Thread thread; + + public static void setUpPacketFactory(PacketFactory factory) { + if (ClientPlayNetworkingImpl.packetFactory != null) { + throw new IllegalStateException("tried to set up client custom payload packet factory when it was already set up!"); + } + + ClientPlayNetworkingImpl.packetFactory = factory; + } + + public static void setUp(Minecraft minecraft) { + if (ClientPlayNetworkingImpl.minecraft == minecraft) { + throw new IllegalStateException("tried to set up client play networking when it was already set up!"); + } + if (ClientPlayNetworkingImpl.packetFactory == null) { + throw new IllegalStateException("tried to set up client play networking when no custom payload packet factory was set up!"); + } + + ClientPlayNetworkingImpl.minecraft = minecraft; + ClientPlayNetworkingImpl.thread = Thread.currentThread(); + } + + public static void destroy(Minecraft minecraft) { + if (ClientPlayNetworkingImpl.minecraft != minecraft) { + throw new IllegalStateException("tried to destroy client play networking when it was not set up!"); + } + + ClientPlayNetworkingImpl.minecraft = null; + ClientPlayNetworkingImpl.thread = null; + } + + public static final Map CHANNEL_LISTENERS = new LinkedHashMap<>(); + + public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { + registerListener(channel, initializer, listener, false); + } + + public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { + registerListener(channel, initializer, listener, true); + } + + private static void registerListener(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener, boolean async) { + registerListenerImpl(channel, new ChannelListener() { + + @Override + public boolean isAsync() { + return async; + } + + @Override + public boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, PacketBuffer buffer) throws IOException { + T payload = initializer.get(); + payload.read(buffer); + + return listener.handle(minecraft, handler, payload); + } + }); + } + + public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { + registerListener(channel, listener, false); + } + + public static void registerListenerAsync(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { + registerListener(channel, listener, true); + } + + private static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Buffer listener, boolean async) { + registerListenerImpl(channel, new ChannelListener() { + + @Override + public boolean isAsync() { + return async; + } + + @Override + public boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, PacketBuffer buffer) throws IOException { + return listener.handle(minecraft, handler, buffer); + } + }); + } + + public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { + registerListener(channel, listener, false); + } + + public static void registerListenerAsync(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { + registerListener(channel, listener, true); + } + + private static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Bytes listener, boolean async) { + registerListenerImpl(channel, new ChannelListener() { + + @Override + public boolean isAsync() { + return async; + } + + @Override + public boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, PacketBuffer buffer) throws IOException { + return listener.handle(minecraft, handler, buffer.readByteArray()); + } + }); + } + + private static void registerListenerImpl(NamespacedIdentifier channel, ChannelListener listener) { + CHANNEL_LISTENERS.compute(channel, (key, value) -> { + if (value != null) { + throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); + } + + return listener; + }); + } + + public static void unregisterListener(NamespacedIdentifier channel) { + CHANNEL_LISTENERS.remove(channel); + } + + // Packet is not generic prior to 14w31a + @SuppressWarnings("rawtypes") + public static boolean handlePacket(Minecraft minecraft, ClientPlayNetworkHandler handler, Packet packet) { + CustomPayloadPacketAccess p = (CustomPayloadPacketAccess)packet; + + NamespacedIdentifier channel = p.osl$networking$getChannel(); + ChannelListener listener = CHANNEL_LISTENERS.get(channel); + + if (listener != null) { + PacketBuffer data = p.osl$networking$getData(); + + if (Thread.currentThread() == thread || listener.isAsync()) { + return handlePayload(minecraft, handler, listener, channel, data); + } else { + return ((TaskRunnerAccess) minecraft).osl$networking$submit(() -> handlePayload(minecraft, handler, listener, channel, data)); + } + } + + return false; + } + + private static boolean handlePayload(Minecraft minecraft, ClientPlayNetworkHandler handler, ChannelListener listener, NamespacedIdentifier channel, PacketBuffer data) { + try { + return listener.handle(minecraft, handler, data); + } catch (IOException e) { + LOGGER.warn("error handling custom payload on channel \'" + channel + "\'", e); + } + + return true; + } + + public static boolean isPlayReady() { + NetworkHandlerAccess handler = (NetworkHandlerAccess)minecraft.getNetworkHandler(); + return handler != null && handler.osl$networking$isPlayReady(); + } + + public static boolean isPlayReady(NamespacedIdentifier channel) { + NetworkHandlerAccess handler = (NetworkHandlerAccess)minecraft.getNetworkHandler(); + return handler != null && handler.osl$networking$isPlayReady(channel); + } + + public static void send(NamespacedIdentifier channel, PacketPayload payload) { + if (isPlayReady(channel)) { + sendInternal(channel, payload); + } + } + + public static void send(NamespacedIdentifier channel, IOConsumer writer) { + if (isPlayReady(channel)) { + sendInternal(channel, writer); + } + } + + public static void send(NamespacedIdentifier channel, PacketBuffer buffer) { + if (isPlayReady(channel)) { + sendInternal(channel, buffer); + } + } + + public static void send(NamespacedIdentifier channel, byte[] bytes) { + if (isPlayReady(channel)) { + sendInternal(channel, bytes); + } + } + + public static void sendNoCheck(NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(channel, payload); + } + + public static void sendNoCheck(NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(channel, writer); + } + + public static void sendNoCheck(NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(channel, buffer); + } + + public static void sendNoCheck(NamespacedIdentifier channel, byte[] bytes) { + sendInternal(channel, bytes); + } + + private static void sendInternal(NamespacedIdentifier channel, PacketPayload payload) { + try { + sendPacket(channel, PacketBuffers.make(payload::write)); + } catch (IOException e) { + LOGGER.warn("error writing packet payload to channel \'" + channel + "\'", e); + } + } + + private static void sendInternal(NamespacedIdentifier channel, IOConsumer writer) { + try { + sendPacket(channel, PacketBuffers.make(writer)); + } catch (IOException e) { + LOGGER.warn("error writing buffer to channel \'" + channel + "\'", e); + } + } + + private static void sendInternal(NamespacedIdentifier channel, PacketBuffer buffer) { + sendPacket(channel, buffer); + } + + private static void sendInternal(NamespacedIdentifier channel, byte[] bytes) { + sendPacket(channel, PacketBuffers.wrap(bytes)); + } + + private static void sendPacket(NamespacedIdentifier channel, PacketBuffer data) { + minecraft.getNetworkHandler().sendPacket(packetFactory.create(channel, data)); + } + + private interface ChannelListener { + + boolean isAsync(); + + boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, PacketBuffer buffer) throws IOException; + + } +} diff --git a/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java new file mode 100644 index 00000000..175a9d06 --- /dev/null +++ b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java @@ -0,0 +1,420 @@ +package net.ornithemc.osl.networking.impl.server; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.function.Supplier; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import net.minecraft.network.packet.Packet; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.entity.living.player.ServerPlayerEntity; +import net.minecraft.server.network.handler.ServerPlayNetworkHandler; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.function.IOConsumer; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketBuffers; +import net.ornithemc.osl.networking.api.PacketPayload; +import net.ornithemc.osl.networking.api.server.ServerPacketListener; +import net.ornithemc.osl.networking.impl.PacketFactory; +import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; +import net.ornithemc.osl.networking.impl.access.PlayerManagerAccess; +import net.ornithemc.osl.networking.impl.access.TaskRunnerAccess; + +public final class ServerPlayNetworkingImpl { + + private static final Logger LOGGER = LogManager.getLogger("OSL|Server Play Networking"); + + private static PacketFactory packetFactory; + private static MinecraftServer server; + private static Thread thread; + + public static void setUpPacketFactory(PacketFactory factory) { + if (ServerPlayNetworkingImpl.packetFactory != null) { + throw new IllegalStateException("tried to set up server custom payload packet factory when it was already set up!"); + } + + ServerPlayNetworkingImpl.packetFactory = factory; + } + + public static void setUp(MinecraftServer server) { + if (ServerPlayNetworkingImpl.server == server) { + throw new IllegalStateException("tried to set up server play networking when it was already set up!"); + } + if (ServerPlayNetworkingImpl.packetFactory == null) { + throw new IllegalStateException("tried to set up server play networking when no custom payload packet factory was set up!"); + } + + ServerPlayNetworkingImpl.server = server; + ServerPlayNetworkingImpl.thread = Thread.currentThread(); + } + + public static void destroy(MinecraftServer server) { + if (ServerPlayNetworkingImpl.server != server) { + throw new IllegalStateException("tried to destroy server play networking when it was not set up!"); + } + + ServerPlayNetworkingImpl.server = null; + ServerPlayNetworkingImpl.thread = null; + } + + public static final Map CHANNEL_LISTENERS = new LinkedHashMap<>(); + + public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { + ServerPlayNetworkingImpl.registerListener(channel, initializer, listener, false); + } + + public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { + ServerPlayNetworkingImpl.registerListener(channel, initializer, listener, true); + } + + private static void registerListener(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener, boolean async) { + registerListenerImpl(channel, new ChannelListener() { + + @Override + public boolean isAsync() { + return async; + } + + @Override + public boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, PacketBuffer buffer) throws IOException { + T payload = initializer.get(); + payload.read(buffer); + + return listener.handle(server, handler, player, payload); + } + }); + } + + public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { + ServerPlayNetworkingImpl.registerListener(channel, listener, false); + } + + public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { + ServerPlayNetworkingImpl.registerListener(channel, listener, true); + } + + private static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Buffer listener, boolean async) { + registerListenerImpl(channel, new ChannelListener() { + + @Override + public boolean isAsync() { + return async; + } + + @Override + public boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, PacketBuffer buffer) throws IOException { + return listener.handle(server, handler, player, buffer); + } + }); + } + + public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { + ServerPlayNetworkingImpl.registerListener(channel, listener, false); + } + + public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { + ServerPlayNetworkingImpl.registerListener(channel, listener, true); + } + + private static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener, boolean async) { + registerListenerImpl(channel, new ChannelListener() { + + @Override + public boolean isAsync() { + return async; + } + + @Override + public boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, PacketBuffer buffer) throws IOException { + return listener.handle(server, handler, player, buffer.readByteArray()); + } + }); + } + + private static void registerListenerImpl(NamespacedIdentifier channel, ChannelListener listener) { + CHANNEL_LISTENERS.compute(channel, (key, value) -> { + if (value != null) { + throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); + } + + return listener; + }); + } + + public static void unregisterListener(NamespacedIdentifier channel) { + CHANNEL_LISTENERS.remove(channel); + } + + // Packet is not generic prior to 14w31a + @SuppressWarnings("rawtypes") + public static boolean handlePacket(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, Packet packet) { + CustomPayloadPacketAccess p = (CustomPayloadPacketAccess)packet; + + NamespacedIdentifier channel = p.osl$networking$getChannel(); + ChannelListener listener = CHANNEL_LISTENERS.get(channel); + + if (listener != null) { + PacketBuffer data = p.osl$networking$getData(); + + if (Thread.currentThread() == thread || listener.isAsync()) { + return handlePayload(server, handler, player, listener, channel, data); + } else { + return ((TaskRunnerAccess) server).osl$networking$submit(() -> handlePayload(server, handler, player, listener, channel, data)); + } + } + + return false; + } + + private static boolean handlePayload(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, ChannelListener listener, NamespacedIdentifier channel, PacketBuffer data) { + try { + return listener.handle(server, handler, player, data); + } catch (IOException e) { + LOGGER.warn("error handling custom payload on channel \'" + channel + "\'", e); + } + + return true; + } + + public static boolean isPlayReady(ServerPlayerEntity player) { + NetworkHandlerAccess handler = (NetworkHandlerAccess)player.networkHandler; + return handler != null && handler.osl$networking$isPlayReady(); + } + + public static boolean isPlayReady(ServerPlayerEntity player, NamespacedIdentifier channel) { + NetworkHandlerAccess handler = (NetworkHandlerAccess)player.networkHandler; + return handler != null && handler.osl$networking$isPlayReady(channel); + } + + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, PacketPayload payload) { + if (isPlayReady(player, channel)) { + sendInternal(player, channel, payload); + } + } + + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, IOConsumer writer) { + if (isPlayReady(player, channel)) { + sendInternal(player, channel, writer); + } + } + + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, PacketBuffer buffer) { + if (isPlayReady(player, channel)) { + sendInternal(player, channel, buffer); + } + } + + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, byte[] bytes) { + if (isPlayReady(player, channel)) { + sendInternal(player, channel, bytes); + } + } + + public static void send(Iterable players, NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(collectPlayers(players, p -> isPlayReady(p, channel)), channel, payload); + } + + public static void send(Iterable players, NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(collectPlayers(players, p -> isPlayReady(p, channel)), channel, writer); + } + + public static void send(Iterable players, NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(collectPlayers(players, p -> isPlayReady(p, channel)), channel, buffer); + } + + public static void send(Iterable players, NamespacedIdentifier channel, byte[] bytes) { + sendInternal(collectPlayers(players, p -> isPlayReady(p, channel)), channel, bytes); + } + + public static void send(int dimension, NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(collectPlayers(p -> p.dimension == dimension && isPlayReady(p, channel)), channel, payload); + } + + public static void send(int dimension, NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(collectPlayers(p -> p.dimension == dimension && isPlayReady(p, channel)), channel, writer); + } + + public static void send(int dimension, NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(collectPlayers(p -> p.dimension == dimension && isPlayReady(p, channel)),channel, buffer); + } + + public static void send(int dimension, NamespacedIdentifier channel, byte[] bytes) { + sendInternal(collectPlayers(p -> p.dimension == dimension && isPlayReady(p, channel)),channel, bytes); + } + + public static void send(NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(collectPlayers(p -> isPlayReady(p, channel)), channel, payload); + } + + public static void send(NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(collectPlayers(p -> isPlayReady(p, channel)), channel, writer); + } + + public static void send(NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(collectPlayers(p -> isPlayReady(p, channel)), channel, buffer); + } + + public static void send(NamespacedIdentifier channel, byte[] bytes) { + sendInternal(collectPlayers(p -> isPlayReady(p, channel)), channel, bytes); + } + + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(player, channel, payload); + } + + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(player, channel, writer); + } + + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(player, channel, buffer); + } + + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, byte[] bytes) { + sendInternal(player, channel, bytes); + } + + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(players, channel, payload); + } + + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(players, channel, writer); + } + + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(players, channel, buffer); + } + + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, byte[] bytes) { + sendInternal(players, channel, bytes); + } + + public static void sendNoCheck(int dimension, NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(collectPlayers(p -> p.dimension == dimension), channel, payload); + } + + public static void sendNoCheck(int dimension, NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(collectPlayers(p -> p.dimension == dimension), channel, writer); + } + + public static void sendNoCheck(int dimension, NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(collectPlayers(p -> p.dimension == dimension),channel, buffer); + } + + public static void sendNoCheck(int dimension, NamespacedIdentifier channel, byte[] bytes) { + sendInternal(collectPlayers(p -> p.dimension == dimension),channel, bytes); + } + + public static void sendNoCheck(NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(allPlayers(), channel, payload); + } + + public static void sendNoCheck(NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(allPlayers(), channel, writer); + } + + public static void sendNoCheck(NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(allPlayers(), channel, buffer); + } + + public static void sendNoCheck(NamespacedIdentifier channel, byte[] bytes) { + sendInternal(allPlayers(), channel, bytes); + } + + private static void sendInternal(ServerPlayerEntity player, NamespacedIdentifier channel, PacketPayload payload) { + try { + sendPacket(player, channel, PacketBuffers.make(payload::write)); + } catch (IOException e) { + LOGGER.warn("error writing packet payload to channel \'" + channel + "\'", e); + } + } + + private static void sendInternal(ServerPlayerEntity player, NamespacedIdentifier channel, IOConsumer writer) { + try { + sendPacket(player, channel, PacketBuffers.make(writer)); + } catch (IOException e) { + LOGGER.warn("error writing buffer to channel \'" + channel + "\'", e); + } + } + + private static void sendInternal(ServerPlayerEntity player, NamespacedIdentifier channel, PacketBuffer buffer) { + sendPacket(player, channel, buffer); + } + + private static void sendInternal(ServerPlayerEntity player, NamespacedIdentifier channel, byte[] bytes) { + sendPacket(player, channel, PacketBuffers.wrap(bytes)); + } + + private static void sendInternal(Iterable players, NamespacedIdentifier channel, PacketPayload payload) { + try { + sendPacket(players, channel, PacketBuffers.make(payload::write)); + } catch (IOException e) { + LOGGER.warn("error writing packet payload to channel \'" + channel + "\'", e); + } + } + + private static void sendInternal(Iterable players, NamespacedIdentifier channel, IOConsumer writer) { + try { + sendPacket(players, channel, PacketBuffers.make(writer)); + } catch (IOException e) { + LOGGER.warn("error writing buffer to channel \'" + channel + "\'", e); + } + } + + private static void sendInternal(Iterable players, NamespacedIdentifier channel, PacketBuffer buffer) { + sendPacket(players, channel, buffer); + } + + private static void sendInternal(Iterable players, NamespacedIdentifier channel, byte[] bytes) { + sendPacket(players, channel, PacketBuffers.wrap(bytes)); + } + + private static Iterable allPlayers() { + return ((PlayerManagerAccess) server.getPlayerManager()).osl$networking$getAll(); + } + + private static Iterable collectPlayers(Predicate filter) { + return collectPlayers(allPlayers(), filter); + } + + private static Iterable collectPlayers(Iterable src, Predicate filter) { + List players = new ArrayList<>(); + + for (ServerPlayerEntity player : src) { + if (filter.test(player)) { + players.add(player); + } + } + + return players; + } + + private static void sendPacket(ServerPlayerEntity player, NamespacedIdentifier channel, PacketBuffer data) { + player.networkHandler.sendPacket(packetFactory.create(channel, data)); + } + + private static void sendPacket(Iterable players, NamespacedIdentifier channel, PacketBuffer data) { + Packet packet = packetFactory.create(channel, data); + + for (ServerPlayerEntity player : players) { + player.networkHandler.sendPacket(packet); + } + } + + private interface ChannelListener { + + boolean isAsync(); + + boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, PacketBuffer buffer) throws IOException; + + } +} diff --git a/libraries/networking/networking-mc14w21a-mc14w30c/build.gradle b/libraries/networking/networking-mc14w21a-mc14w30c/build.gradle deleted file mode 100644 index 2f186572..00000000 --- a/libraries/networking/networking-mc14w21a-mc14w30c/build.gradle +++ /dev/null @@ -1,4 +0,0 @@ -setUpModule(project, - 'entrypoints-mc13w16a-04192037-mc1.14.4', - 'lifecycle-events-mc13w36a-09051446-mc1.13' -) diff --git a/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java b/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java deleted file mode 100644 index aee6a1cd..00000000 --- a/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java +++ /dev/null @@ -1,13 +0,0 @@ -package net.ornithemc.osl.networking.api; - -import java.io.IOException; - -import net.minecraft.network.PacketByteBuf; - -public interface CustomPayload { - - void read(PacketByteBuf buffer) throws IOException; - - void write(PacketByteBuf buffer) throws IOException; - -} diff --git a/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/api/PacketByteBufs.java b/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/api/PacketByteBufs.java deleted file mode 100644 index e1944e62..00000000 --- a/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/api/PacketByteBufs.java +++ /dev/null @@ -1,31 +0,0 @@ -package net.ornithemc.osl.networking.api; - -import java.io.IOException; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; - -import net.minecraft.network.PacketByteBuf; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; - -public final class PacketByteBufs { - - public static PacketByteBuf make() { - return make(Unpooled.buffer()); - } - - public static PacketByteBuf make(byte[] bytes) { - return make(Unpooled.wrappedBuffer(bytes)); - } - - public static PacketByteBuf make(ByteBuf buf) { - return new PacketByteBuf(buf); - } - - public static PacketByteBuf make(IOConsumer writer) throws IOException { - PacketByteBuf buffer = make(); - writer.accept(buffer); - return buffer; - } -} diff --git a/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java b/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java deleted file mode 100644 index d5adcfb8..00000000 --- a/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java +++ /dev/null @@ -1,82 +0,0 @@ -package net.ornithemc.osl.networking.api.client; - -import java.util.function.Consumer; - -import net.minecraft.client.Minecraft; - -import net.ornithemc.osl.core.api.events.Event; - -/** - * Events related to the client side of a client-server connection. - */ -public class ClientConnectionEvents { - - /** - * This event is fired after a successful login occurs. - * - *

- * Note that channel registration happens after login, - * and until then data cannot safely be sent to the server. - * - *

- * This applies to connections to dedicated servers as - * well as connections to integrated servers. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ClientConnectionEvents.LOGIN.register(minecraft -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> LOGIN = Event.consumer(); - /** - * This event is fired after login, once channel registration is complete. - * - *

- * This marks the moment data can safely be sent to the server. - * - *

- * This applies to connections to dedicated servers as - * well as connections to integrated servers. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ClientConnectionEvents.PLAY_READY.register(minecraft -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> PLAY_READY = Event.consumer(); - /** - * This event is fired when the client disconnects from the server. - * - *

- * This applies to connections to dedicated servers as - * well as connections to integrated servers. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ClientConnectionEvents.DISCONNECT.register(minecraft -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> DISCONNECT = Event.consumer(); - -} diff --git a/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java b/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java deleted file mode 100644 index dd12e8f0..00000000 --- a/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java +++ /dev/null @@ -1,201 +0,0 @@ -package net.ornithemc.osl.networking.api.client; - -import java.io.IOException; -import java.util.function.Supplier; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.network.handler.ClientPlayNetworkHandler; -import net.minecraft.network.PacketByteBuf; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; - -public final class ClientPlayNetworking { - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - ClientPlayNetworkingImpl.registerListener(channel, initializer, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListenerAsync(String channel, Supplier initializer, PayloadListener listener) { - ClientPlayNetworkingImpl.registerListenerAsync(channel, initializer, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListener(String channel, ByteBufListener listener) { - ClientPlayNetworkingImpl.registerListener(channel, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListenerAsync(String channel, ByteBufListener listener) { - ClientPlayNetworkingImpl.registerListenerAsync(channel, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - ClientPlayNetworkingImpl.registerListenerRaw(channel, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListenerRawAsync(String channel, ByteArrayListener listener) { - ClientPlayNetworkingImpl.registerListenerRawAsync(channel, listener); - } - - /** - * Remove the listener registered to the given channel. - */ - public static void unregisterListener(String channel) { - ClientPlayNetworkingImpl.unregisterListener(channel); - } - - /** - * Check whether the connection is ready for data to be sent to the server. - */ - public static boolean isPlayReady() { - return ClientPlayNetworkingImpl.isPlayReady(); - } - - /** - * Check whether the given channel is open for data to be sent through it. - * This method will return {@code false} if the client is not connected to a - * server, or if the server has no listeners for the given channel. - */ - public static boolean canSend(String channel) { - return ClientPlayNetworkingImpl.canSend(channel); - } - - /** - * Send a packet to the server through the given channel. The payload will - * only be written if the channel is open. - */ - public static void send(String channel, CustomPayload payload) { - ClientPlayNetworkingImpl.send(channel, payload); - } - - /** - * Send a packet to the server through the given channel. The writer will - * only be called if the channel is open. - */ - public static void send(String channel, IOConsumer writer) { - ClientPlayNetworkingImpl.send(channel, writer); - } - - /** - * Send a packet to the server through the given channel. - */ - public static void send(String channel, PacketByteBuf data) { - ClientPlayNetworkingImpl.send(channel, data); - } - - /** - * Send a packet to the server through the given channel. - */ - public static void send(String channel, byte[] data) { - ClientPlayNetworkingImpl.send(channel, data); - } - - /** - * Send a packet to the server through the given channel, without checking - * whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the server. - */ - public static void doSend(String channel, CustomPayload payload) { - ClientPlayNetworkingImpl.doSend(channel, payload); - } - - /** - * Send a packet to the server through the given channel, without checking - * whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the server. - */ - public static void doSend(String channel, IOConsumer writer) { - ClientPlayNetworkingImpl.doSend(channel, writer); - } - - /** - * Send a packet to the server through the given channel, without checking - * whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the server. - */ - public static void doSend(String channel, PacketByteBuf data) { - ClientPlayNetworkingImpl.doSend(channel, data); - } - - /** - * Send a packet to the server through the given channel, without checking - * whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the server. - */ - public static void doSend(String channel, byte[] data) { - ClientPlayNetworkingImpl.doSend(channel, data); - } - - public interface PayloadListener { - - /** - * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, T payload) throws IOException; - - } - - public interface ByteBufListener { - - /** - * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, PacketByteBuf data) throws IOException; - - } - - public interface ByteArrayListener { - - /** - * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, byte[] data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java b/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java deleted file mode 100644 index e248c524..00000000 --- a/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java +++ /dev/null @@ -1,83 +0,0 @@ -package net.ornithemc.osl.networking.api.server; - -import java.util.function.BiConsumer; - -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.entity.living.player.ServerPlayerEntity; - -import net.ornithemc.osl.core.api.events.Event; - -/** - * Events related to the server side of a client-server connection. - */ -public class ServerConnectionEvents { - - /** - * This event is fired after a successful login occurs. - * - *

- * Note that channel registration happens after login, - * and until then data cannot safely be sent to the client. - * - *

- * This applies to connections to dedicated servers as - * well as connections to integrated servers. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ServerConnectionEvents.LOGIN.register((server, player) -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> LOGIN = Event.biConsumer(); - /** - * This event is fired after login, once channel registration is complete. - * - *

- * This marks the moment data can safely be sent to the client. - * - *

- * This applies to connections to dedicated servers as - * well as connections to integrated servers. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ServerConnectionEvents.PLAY_READY.register((server, player) -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> PLAY_READY = Event.biConsumer(); - /** - * This event is fired when a client disconnects from the server. - * - *

- * This applies to connections to dedicated servers as - * well as connections to integrated servers. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ServerConnectionEvents.DISCONNECT.register((server, player) -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> DISCONNECT = Event.biConsumer(); - -} diff --git a/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java b/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java deleted file mode 100644 index 5ad5c022..00000000 --- a/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java +++ /dev/null @@ -1,55 +0,0 @@ -package net.ornithemc.osl.networking.impl; - -import java.io.IOException; -import java.util.LinkedHashSet; -import java.util.Set; - -import net.minecraft.network.PacketByteBuf; - -import net.ornithemc.osl.networking.api.Channels; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -public class HandshakePayload implements CustomPayload { - - public static final String CHANNEL = "OSL|Handshake"; - - public Set channels; - - public HandshakePayload() { - } - - public HandshakePayload(Set channels) { - this.channels = channels; - } - - public static HandshakePayload client() { - return new HandshakePayload(ClientPlayNetworkingImpl.LISTENERS.keySet()); - } - - public static HandshakePayload server() { - return new HandshakePayload(ServerPlayNetworkingImpl.LISTENERS.keySet()); - } - - @Override - public void read(PacketByteBuf buffer) throws IOException { - channels = new LinkedHashSet<>(); - int channelCount = buffer.readInt(); - - if (channelCount > 0) { - for (int i = 0; i < channelCount; i++) { - channels.add(buffer.readString(Channels.MAX_LENGTH)); - } - } - } - - @Override - public void write(PacketByteBuf buffer) throws IOException { - buffer.writeInt(channels.size()); - - for (String channel : channels) { - buffer.writeString(channel); - } - } -} diff --git a/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/NetworkListener.java b/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/NetworkListener.java deleted file mode 100644 index 7e34822c..00000000 --- a/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/NetworkListener.java +++ /dev/null @@ -1,20 +0,0 @@ -package net.ornithemc.osl.networking.impl; - -public class NetworkListener { - - private final T listener; - private final boolean async; - - public NetworkListener(T listener, boolean async) { - this.listener = listener; - this.async = async; - } - - public T get() { - return listener; - } - - public boolean isAsync() { - return async; - } -} diff --git a/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/Networking.java deleted file mode 100644 index 601d2f5d..00000000 --- a/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/Networking.java +++ /dev/null @@ -1,57 +0,0 @@ -package net.ornithemc.osl.networking.impl; - -import net.ornithemc.osl.entrypoints.api.ModInitializer; -import net.ornithemc.osl.entrypoints.api.client.ClientModInitializer; -import net.ornithemc.osl.entrypoints.api.server.ServerModInitializer; -import net.ornithemc.osl.lifecycle.api.client.MinecraftClientEvents; -import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; -import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking; -import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking; -import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -public class Networking implements ModInitializer, ClientModInitializer, ServerModInitializer { - - @Override - public void init() { - MinecraftServerEvents.START.register(server -> { - ServerPlayNetworkingImpl.setUp(server); - }); - MinecraftServerEvents.STOP.register(server -> { - ServerPlayNetworkingImpl.destroy(server); - }); - ServerPlayNetworking.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { - // send channel registration data as a response to receiving client channel registration data - ServerPlayNetworkingImpl.doSend(player, HandshakePayload.CHANNEL, HandshakePayload.server()); - - ((INetworkHandler)handler).osl$networking$registerChannels(payload.channels); - ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); - - return true; - }); - } - - @Override - public void initClient() { - MinecraftClientEvents.START.register(minecraft -> { - ClientPlayNetworkingImpl.setUp(minecraft); - }); - MinecraftClientEvents.STOP.register(minecraft -> { - ClientPlayNetworkingImpl.destroy(minecraft); - }); - ClientPlayNetworking.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { - ((INetworkHandler)handler).osl$networking$registerChannels(payload.channels); - ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); - - return true; - }); - } - - @Override - public void initServer() { - // empty impl - } -} diff --git a/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java b/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java deleted file mode 100644 index 830dc28d..00000000 --- a/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java +++ /dev/null @@ -1,214 +0,0 @@ -package net.ornithemc.osl.networking.impl.client; - -import java.io.IOException; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.function.Supplier; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.network.handler.ClientPlayNetworkHandler; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.network.PacketUtils; -import net.minecraft.network.packet.Packet; -import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; -import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.Channels; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.api.PacketByteBufs; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.ByteArrayListener; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.ByteBufListener; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.PayloadListener; -import net.ornithemc.osl.networking.impl.NetworkListener; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; - -public final class ClientPlayNetworkingImpl { - - private static final Logger LOGGER = LogManager.getLogger("OSL|Client Play Networking"); - - private static Minecraft minecraft; - - public static void setUp(Minecraft minecraft) { - if (ClientPlayNetworkingImpl.minecraft == minecraft) { - throw new IllegalStateException("tried to set up client networking when it was already set up!"); - } - - ClientPlayNetworkingImpl.minecraft = minecraft; - } - - public static void destroy(Minecraft minecraft) { - if (ClientPlayNetworkingImpl.minecraft != minecraft) { - throw new IllegalStateException("tried to destroy client networking when it was not set up!"); - } - - ClientPlayNetworkingImpl.minecraft = null; - } - - public static final Map> LISTENERS = new LinkedHashMap<>(); - - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - registerListener(channel, initializer, listener, false); - } - - public static void registerListenerAsync(String channel, Supplier initializer, PayloadListener listener) { - registerListener(channel, initializer, listener, true); - } - - private static void registerListener(String channel, Supplier initializer, PayloadListener listener, boolean async) { - registerListenerImpl(channel, (minecraft, handler, data) -> { - T payload = initializer.get(); - payload.read(PacketByteBufs.make(data)); - - return listener.handle(minecraft, handler, payload); - }, async); - } - - public static void registerListener(String channel, ByteBufListener listener) { - registerListener(channel, listener, false); - } - - public static void registerListenerAsync(String channel, ByteBufListener listener) { - registerListener(channel, listener, true); - } - - private static void registerListener(String channel, ByteBufListener listener, boolean async) { - registerListenerImpl(channel, (minecraft, handler, data) -> { - return listener.handle(minecraft, handler, PacketByteBufs.make(data)); - }, async); - } - - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - registerListenerRaw(channel, listener, false); - } - - public static void registerListenerRawAsync(String channel, ByteArrayListener listener) { - registerListenerRaw(channel, listener, true); - } - - private static void registerListenerRaw(String channel, ByteArrayListener listener, boolean async) { - registerListenerImpl(channel, listener::handle, async); - } - - private static void registerListenerImpl(String channel, Listener listener, boolean async) { - LISTENERS.compute(channel, (key, value) -> { - Channels.validate(channel); - - if (value != null) { - throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); - } - - return new NetworkListener<>(listener, async); - }); - } - - public static void unregisterListener(String channel) { - LISTENERS.remove(channel); - } - - public static boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, CustomPayloadS2CPacket packet) { - String channel = packet.getChannel(); - NetworkListener listener = LISTENERS.get(channel); - - if (listener != null) { - if (!listener.isAsync()) { - PacketUtils.ensureOnSameThread(packet, handler, minecraft); - } - - try { - return listener.get().handle(minecraft, handler, packet.getData()); - } catch (IOException e) { - LOGGER.warn("error handling custom payload on channel \'" + channel + "\'", e); - return true; - } - } - - return false; - } - - public static boolean isPlayReady() { - INetworkHandler handler = (INetworkHandler)minecraft.getNetworkHandler(); - return handler != null && handler.osl$networking$isPlayReady(); - } - - public static boolean canSend(String channel) { - INetworkHandler handler = (INetworkHandler)minecraft.getNetworkHandler(); - return handler != null && handler.osl$networking$isRegisteredChannel(channel); - } - - public static void send(String channel, CustomPayload payload) { - if (canSend(channel)) { - doSend(channel, payload); - } - } - - public static void send(String channel, IOConsumer writer) { - if (canSend(channel)) { - doSend(channel, writer); - } - } - - public static void send(String channel, PacketByteBuf data) { - if (canSend(channel)) { - doSend(channel, data); - } - } - - public static void send(String channel, byte[] data) { - if (canSend(channel)) { - doSend(channel, data); - } - } - - public static void doSend(String channel, CustomPayload payload) { - sendPacket(makePacket(channel, payload)); - } - - public static void doSend(String channel, IOConsumer writer) { - sendPacket(makePacket(channel, writer)); - } - - public static void doSend(String channel, PacketByteBuf data) { - sendPacket(makePacket(channel, data)); - } - - public static void doSend(String channel, byte[] data) { - sendPacket(makePacket(channel, data)); - } - - private static Packet makePacket(String channel, CustomPayload payload) { - return makePacket(channel, payload::write); - } - - private static Packet makePacket(String channel, IOConsumer writer) { - try { - return new CustomPayloadC2SPacket(channel, PacketByteBufs.make(writer)); - } catch (IOException e) { - LOGGER.warn("error writing custom payload to channel \'" + channel + "\'", e); - return null; - } - } - - private static Packet makePacket(String channel, PacketByteBuf data) { - return new CustomPayloadC2SPacket(channel, data); - } - - private static Packet makePacket(String channel, byte[] data) { - return new CustomPayloadC2SPacket(channel, data); - } - - private static void sendPacket(Packet packet) { - if (packet != null) { - minecraft.getNetworkHandler().sendPacket(packet); - } - } - - private interface Listener { - - boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, byte[] data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java b/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java deleted file mode 100644 index a5519db4..00000000 --- a/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java +++ /dev/null @@ -1,13 +0,0 @@ -package net.ornithemc.osl.networking.impl.interfaces.mixin; - -import java.util.Set; - -public interface INetworkHandler { - - boolean osl$networking$isPlayReady(); - - void osl$networking$registerChannels(Set channels); - - boolean osl$networking$isRegisteredChannel(String channel); - -} diff --git a/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/IPlayerManager.java b/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/IPlayerManager.java deleted file mode 100644 index 71925ecd..00000000 --- a/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/IPlayerManager.java +++ /dev/null @@ -1,13 +0,0 @@ -package net.ornithemc.osl.networking.impl.interfaces.mixin; - -import java.util.List; - -import net.minecraft.server.entity.living.player.ServerPlayerEntity; - -public interface IPlayerManager { - - // a getAll method does exist but only in 1.8.1-pre3 and above - - List osl$networking$getAll(); - -} diff --git a/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java b/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java deleted file mode 100644 index 0c5372fa..00000000 --- a/libraries/networking/networking-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java +++ /dev/null @@ -1,339 +0,0 @@ -package net.ornithemc.osl.networking.impl.server; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.function.Supplier; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import net.minecraft.network.PacketByteBuf; -import net.minecraft.network.PacketUtils; -import net.minecraft.network.packet.Packet; -import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; -import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.entity.living.player.ServerPlayerEntity; -import net.minecraft.server.network.handler.ServerPlayNetworkHandler; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.Channels; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.api.PacketByteBufs; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.ByteArrayListener; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.ByteBufListener; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.PayloadListener; -import net.ornithemc.osl.networking.impl.NetworkListener; -import net.ornithemc.osl.networking.impl.interfaces.mixin.IPlayerManager; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; - -public final class ServerPlayNetworkingImpl { - - private static final Logger LOGGER = LogManager.getLogger("OSL|Server Play Networking"); - - private static MinecraftServer server; - - public static void setUp(MinecraftServer server) { - if (ServerPlayNetworkingImpl.server == server) { - throw new IllegalStateException("tried to set up server networking when it was already set up!"); - } - - ServerPlayNetworkingImpl.server = server; - } - - public static void destroy(MinecraftServer server) { - if (ServerPlayNetworkingImpl.server != server) { - throw new IllegalStateException("tried to destroy server networking when it was not set up!"); - } - - ServerPlayNetworkingImpl.server = null; - } - - public static final Map> LISTENERS = new LinkedHashMap<>(); - - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - registerListener(channel, initializer, listener, false); - } - - public static void registerListenerAsync(String channel, Supplier initializer, PayloadListener listener) { - registerListener(channel, initializer, listener, true); - } - - private static void registerListener(String channel, Supplier initializer, PayloadListener listener, boolean async) { - registerListenerImpl(channel, (server, handler, player, data) -> { - T payload = initializer.get(); - payload.read(PacketByteBufs.make(data)); - - return listener.handle(server, handler, player, payload); - }, async); - } - - public static void registerListener(String channel, ByteBufListener listener) { - registerListener(channel, listener, false); - } - - public static void registerListenerAsync(String channel, ByteBufListener listener) { - registerListener(channel, listener, true); - } - - private static void registerListener(String channel, ByteBufListener listener, boolean async) { - registerListenerImpl(channel, (server, handler, player, data) -> { - return listener.handle(server, handler, player, PacketByteBufs.make(data)); - }, async); - } - - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - registerListenerRaw(channel, listener, false); - } - - public static void registerListenerRawAsync(String channel, ByteArrayListener listener) { - registerListenerRaw(channel, listener, true); - } - - private static void registerListenerRaw(String channel, ByteArrayListener listener, boolean async) { - registerListenerImpl(channel, listener::handle, async); - } - - private static void registerListenerImpl(String channel, Listener listener, boolean async) { - LISTENERS.compute(channel, (key, value) -> { - Channels.validate(channel); - - if (value != null) { - throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); - } - - return new NetworkListener<>(listener, async); - }); - } - - public static void unregisterListener(String channel) { - LISTENERS.remove(channel); - } - - public static boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, CustomPayloadC2SPacket packet) { - String channel = packet.getChannel(); - NetworkListener listener = LISTENERS.get(channel); - - if (listener != null) { - if (!listener.isAsync()) { - PacketUtils.ensureOnSameThread(packet, handler, server); - } - - try { - return listener.get().handle(server, handler, player, packet.getData()); - } catch (IOException e) { - LOGGER.warn("error handling custom payload on channel \'" + channel + "\'", e); - return true; - } - } - - return false; - } - - public static boolean isPlayReady(ServerPlayerEntity player) { - INetworkHandler handler = (INetworkHandler)player.networkHandler; - return handler != null && handler.osl$networking$isPlayReady(); - } - - public static boolean canSend(ServerPlayerEntity player, String channel) { - INetworkHandler handler = (INetworkHandler)player.networkHandler; - return handler != null && handler.osl$networking$isRegisteredChannel(channel); - } - - public static void send(ServerPlayerEntity player, String channel, CustomPayload payload) { - if (canSend(player, channel)) { - doSend(player, channel, payload); - } - } - - public static void send(ServerPlayerEntity player, String channel, IOConsumer writer) { - if (canSend(player, channel)) { - doSend(player, channel, writer); - } - } - - public static void send(ServerPlayerEntity player, String channel, PacketByteBuf data) { - if (canSend(player, channel)) { - doSend(player, channel, data); - } - } - - public static void send(ServerPlayerEntity player, String channel, byte[] data) { - if (canSend(player, channel)) { - doSend(player, channel, data); - } - } - - public static void send(Iterable players, String channel, CustomPayload payload) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, payload)); - } - - public static void send(Iterable players, String channel, IOConsumer writer) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, writer)); - } - - public static void send(Iterable players, String channel, PacketByteBuf data) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, data)); - } - - public static void send(Iterable players, String channel, byte[] data) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, data)); - } - - public static void send(int dimension, String channel, CustomPayload payload) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)), channel, payload); - } - - public static void send(int dimension, String channel, IOConsumer writer) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)), channel, writer); - } - - public static void send(int dimension, String channel, PacketByteBuf data) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)),channel, data); - } - - public static void send(int dimension, String channel, byte[] data) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)),channel, data); - } - - public static void send(String channel, CustomPayload payload) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, payload); - } - - public static void send(String channel, IOConsumer writer) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, writer); - } - - public static void send(String channel, PacketByteBuf data) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, data); - } - - public static void send(String channel, byte[] data) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, data); - } - - public static void doSend(ServerPlayerEntity player, String channel, CustomPayload payload) { - sendPacket(player, makePacket(channel, payload)); - } - - public static void doSend(ServerPlayerEntity player, String channel, IOConsumer writer) { - sendPacket(player, makePacket(channel, writer)); - } - - public static void doSend(ServerPlayerEntity player, String channel, PacketByteBuf data) { - sendPacket(player, makePacket(channel, data)); - } - - public static void doSend(ServerPlayerEntity player, String channel, byte[] data) { - sendPacket(player, makePacket(channel, data)); - } - - public static void doSend(Iterable players, String channel, CustomPayload payload) { - sendPacket(players, makePacket(channel, payload)); - } - - public static void doSend(Iterable players, String channel, IOConsumer writer) { - sendPacket(players, makePacket(channel, writer)); - } - - public static void doSend(Iterable players, String channel, PacketByteBuf data) { - sendPacket(players, makePacket(channel, data)); - } - - public static void doSend(Iterable players, String channel, byte[] data) { - sendPacket(players, makePacket(channel, data)); - } - - public static void doSend(int dimension, String channel, CustomPayload payload) { - doSend(collectPlayers(p -> p.dimension == dimension), channel, payload); - } - - public static void doSend(int dimension, String channel, IOConsumer writer) { - doSend(collectPlayers(p -> p.dimension == dimension), channel, writer); - } - - public static void doSend(int dimension, String channel, PacketByteBuf data) { - doSend(collectPlayers(p -> p.dimension == dimension),channel, data); - } - - public static void doSend(int dimension, String channel, byte[] data) { - doSend(collectPlayers(p -> p.dimension == dimension),channel, data); - } - - public static void doSend(String channel, CustomPayload payload) { - doSend(collectPlayers(p -> true), channel, payload); - } - - public static void doSend(String channel, IOConsumer writer) { - doSend(collectPlayers(p -> true), channel, writer); - } - - public static void doSend(String channel, PacketByteBuf data) { - doSend(collectPlayers(p -> true), channel, data); - } - - public static void doSend(String channel, byte[] data) { - doSend(collectPlayers(p -> true), channel, data); - } - - private static Iterable collectPlayers(Predicate filter) { - return collectPlayers(((IPlayerManager)server.getPlayerManager()).osl$networking$getAll(), filter); - } - - private static Iterable collectPlayers(Iterable src, Predicate filter) { - List players = new ArrayList<>(); - - for (ServerPlayerEntity player : src) { - if (filter.test(player)) { - players.add(player); - } - } - - return players; - } - - private static Packet makePacket(String channel, CustomPayload payload) { - return makePacket(channel, payload::write); - } - - private static Packet makePacket(String channel, IOConsumer writer) { - try { - return new CustomPayloadS2CPacket(channel, PacketByteBufs.make(writer)); - } catch (IOException e) { - LOGGER.warn("error writing custom payload to channel \'" + channel + "\'", e); - return null; - } - } - - private static Packet makePacket(String channel, PacketByteBuf data) { - return new CustomPayloadS2CPacket(channel, data); - } - - private static Packet makePacket(String channel, byte[] data) { - return new CustomPayloadS2CPacket(channel, data); - } - - private static void sendPacket(ServerPlayerEntity player, Packet packet) { - if (packet != null) { - player.networkHandler.sendPacket(packet); - } - } - - private static void sendPacket(Iterable players, Packet packet) { - if (packet != null) { - for (ServerPlayerEntity player : players) { - sendPacket(player, packet); - } - } - } - - private interface Listener { - - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mc14w21a-mc14w30c/src/main/resources/osl.networking.mixins.json b/libraries/networking/networking-mc14w21a-mc14w30c/src/main/resources/osl.networking.mixins.json deleted file mode 100644 index b9030aa9..00000000 --- a/libraries/networking/networking-mc14w21a-mc14w30c/src/main/resources/osl.networking.mixins.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "required": true, - "minVersion": "0.8", - "package": "net.ornithemc.osl.networking.impl.mixin", - "compatibilityLevel": "JAVA_8", - "mixins": [ - "common.PlayerManagerMixin", - "common.ServerPlayNetworkHandlerMixin" - ], - "client": [ - "client.ClientPlayNetworkHandlerMixin" - ], - "server": [ - ], - "injectors": { - "defaultRequire": 1 - } -} diff --git a/libraries/networking/networking-mc14w31a-mc1.13-pre2/build.gradle b/libraries/networking/networking-mc14w31a-mc1.13-pre2/build.gradle deleted file mode 100644 index 2f186572..00000000 --- a/libraries/networking/networking-mc14w31a-mc1.13-pre2/build.gradle +++ /dev/null @@ -1,4 +0,0 @@ -setUpModule(project, - 'entrypoints-mc13w16a-04192037-mc1.14.4', - 'lifecycle-events-mc13w36a-09051446-mc1.13' -) diff --git a/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java b/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java deleted file mode 100644 index aee6a1cd..00000000 --- a/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java +++ /dev/null @@ -1,13 +0,0 @@ -package net.ornithemc.osl.networking.api; - -import java.io.IOException; - -import net.minecraft.network.PacketByteBuf; - -public interface CustomPayload { - - void read(PacketByteBuf buffer) throws IOException; - - void write(PacketByteBuf buffer) throws IOException; - -} diff --git a/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/api/PacketByteBufs.java b/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/api/PacketByteBufs.java deleted file mode 100644 index e1944e62..00000000 --- a/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/api/PacketByteBufs.java +++ /dev/null @@ -1,31 +0,0 @@ -package net.ornithemc.osl.networking.api; - -import java.io.IOException; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; - -import net.minecraft.network.PacketByteBuf; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; - -public final class PacketByteBufs { - - public static PacketByteBuf make() { - return make(Unpooled.buffer()); - } - - public static PacketByteBuf make(byte[] bytes) { - return make(Unpooled.wrappedBuffer(bytes)); - } - - public static PacketByteBuf make(ByteBuf buf) { - return new PacketByteBuf(buf); - } - - public static PacketByteBuf make(IOConsumer writer) throws IOException { - PacketByteBuf buffer = make(); - writer.accept(buffer); - return buffer; - } -} diff --git a/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java b/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java deleted file mode 100644 index d5adcfb8..00000000 --- a/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java +++ /dev/null @@ -1,82 +0,0 @@ -package net.ornithemc.osl.networking.api.client; - -import java.util.function.Consumer; - -import net.minecraft.client.Minecraft; - -import net.ornithemc.osl.core.api.events.Event; - -/** - * Events related to the client side of a client-server connection. - */ -public class ClientConnectionEvents { - - /** - * This event is fired after a successful login occurs. - * - *

- * Note that channel registration happens after login, - * and until then data cannot safely be sent to the server. - * - *

- * This applies to connections to dedicated servers as - * well as connections to integrated servers. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ClientConnectionEvents.LOGIN.register(minecraft -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> LOGIN = Event.consumer(); - /** - * This event is fired after login, once channel registration is complete. - * - *

- * This marks the moment data can safely be sent to the server. - * - *

- * This applies to connections to dedicated servers as - * well as connections to integrated servers. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ClientConnectionEvents.PLAY_READY.register(minecraft -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> PLAY_READY = Event.consumer(); - /** - * This event is fired when the client disconnects from the server. - * - *

- * This applies to connections to dedicated servers as - * well as connections to integrated servers. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ClientConnectionEvents.DISCONNECT.register(minecraft -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> DISCONNECT = Event.consumer(); - -} diff --git a/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java b/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java deleted file mode 100644 index 8bde7c31..00000000 --- a/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java +++ /dev/null @@ -1,153 +0,0 @@ -package net.ornithemc.osl.networking.api.client; - -import java.io.IOException; -import java.util.function.Supplier; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.network.handler.ClientPlayNetworkHandler; -import net.minecraft.network.PacketByteBuf; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; - -public final class ClientPlayNetworking { - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - ClientPlayNetworkingImpl.registerListener(channel, initializer, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListenerAsync(String channel, Supplier initializer, PayloadListener listener) { - ClientPlayNetworkingImpl.registerListenerAsync(channel, initializer, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListener(String channel, ByteBufListener listener) { - ClientPlayNetworkingImpl.registerListener(channel, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListenerAsync(String channel, ByteBufListener listener) { - ClientPlayNetworkingImpl.registerListenerAsync(channel, listener); - } - - /** - * Remove the listener registered to the given channel. - */ - public static void unregisterListener(String channel) { - ClientPlayNetworkingImpl.unregisterListener(channel); - } - - /** - * Check whether the connection is ready for data to be sent to the server. - */ - public static boolean isPlayReady() { - return ClientPlayNetworkingImpl.isPlayReady(); - } - - /** - * Check whether the given channel is open for data to be sent through it. - * This method will return {@code false} if the client is not connected to a - * server, or if the server has no listeners for the given channel. - */ - public static boolean canSend(String channel) { - return ClientPlayNetworkingImpl.canSend(channel); - } - - /** - * Send a packet to the server through the given channel. The payload will - * only be written if the channel is open. - */ - public static void send(String channel, CustomPayload payload) { - ClientPlayNetworkingImpl.send(channel, payload); - } - - /** - * Send a packet to the server through the given channel. The writer will - * only be called if the channel is open. - */ - public static void send(String channel, IOConsumer writer) { - ClientPlayNetworkingImpl.send(channel, writer); - } - - /** - * Send a packet to the server through the given channel. - */ - public static void send(String channel, PacketByteBuf data) { - ClientPlayNetworkingImpl.send(channel, data); - } - - /** - * Send a packet to the server through the given channel, without checking - * whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the server. - */ - public static void doSend(String channel, CustomPayload payload) { - ClientPlayNetworkingImpl.doSend(channel, payload); - } - - /** - * Send a packet to the server through the given channel, without checking - * whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the server. - */ - public static void doSend(String channel, IOConsumer writer) { - ClientPlayNetworkingImpl.doSend(channel, writer); - } - - /** - * Send a packet to the server through the given channel, without checking - * whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the server. - */ - public static void doSend(String channel, PacketByteBuf data) { - ClientPlayNetworkingImpl.doSend(channel, data); - } - - public interface PayloadListener { - - /** - * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, T payload) throws IOException; - - } - - public interface ByteBufListener { - - /** - * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, PacketByteBuf data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java b/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java deleted file mode 100644 index e248c524..00000000 --- a/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java +++ /dev/null @@ -1,83 +0,0 @@ -package net.ornithemc.osl.networking.api.server; - -import java.util.function.BiConsumer; - -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.entity.living.player.ServerPlayerEntity; - -import net.ornithemc.osl.core.api.events.Event; - -/** - * Events related to the server side of a client-server connection. - */ -public class ServerConnectionEvents { - - /** - * This event is fired after a successful login occurs. - * - *

- * Note that channel registration happens after login, - * and until then data cannot safely be sent to the client. - * - *

- * This applies to connections to dedicated servers as - * well as connections to integrated servers. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ServerConnectionEvents.LOGIN.register((server, player) -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> LOGIN = Event.biConsumer(); - /** - * This event is fired after login, once channel registration is complete. - * - *

- * This marks the moment data can safely be sent to the client. - * - *

- * This applies to connections to dedicated servers as - * well as connections to integrated servers. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ServerConnectionEvents.PLAY_READY.register((server, player) -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> PLAY_READY = Event.biConsumer(); - /** - * This event is fired when a client disconnects from the server. - * - *

- * This applies to connections to dedicated servers as - * well as connections to integrated servers. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ServerConnectionEvents.DISCONNECT.register((server, player) -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> DISCONNECT = Event.biConsumer(); - -} diff --git a/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java b/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java deleted file mode 100644 index 2a904225..00000000 --- a/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java +++ /dev/null @@ -1,316 +0,0 @@ -package net.ornithemc.osl.networking.api.server; - -import java.io.IOException; -import java.util.function.Supplier; - -import net.minecraft.network.PacketByteBuf; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.entity.living.player.ServerPlayerEntity; -import net.minecraft.server.network.handler.ServerPlayNetworkHandler; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -public final class ServerPlayNetworking { - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - ServerPlayNetworkingImpl.registerListener(channel, initializer, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListenerAsync(String channel, Supplier initializer, PayloadListener listener) { - ServerPlayNetworkingImpl.registerListenerAsync(channel, initializer, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListener(String channel, ByteBufListener listener) { - ServerPlayNetworkingImpl.registerListener(channel, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListenerAsync(String channel, ByteBufListener listener) { - ServerPlayNetworkingImpl.registerListenerAsync(channel, listener); - } - - /** - * Remove the listener registered to the given channel. - */ - public static void unregisterListener(String channel) { - ServerPlayNetworkingImpl.unregisterListener(channel); - } - - /** - * Check whether the connection is ready for data to be sent to the client. - */ - public static boolean isPlayReady(ServerPlayerEntity player) { - return ServerPlayNetworkingImpl.isPlayReady(player); - } - - /** - * Check whether the given channel is open for data to be sent through it. - * This method will return {@code false} if the client has no listeners for - * the given channel. - */ - public static boolean canSend(ServerPlayerEntity player, String channel) { - return ServerPlayNetworkingImpl.canSend(player, channel); - } - - /** - * Send a packet to the given player through the given channel. The payload - * will only be written if the channel is open. - */ - public static void send(ServerPlayerEntity player, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.send(player, channel, payload); - } - - /** - * Send a packet to the given player through the given channel. The writer - * will only be called if the channel is open. - */ - public static void send(ServerPlayerEntity player, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.send(player, channel, writer); - } - - /** - * Send a packet to the given player through the given channel. - */ - public static void send(ServerPlayerEntity player, String channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.send(player, channel, data); - } - - /** - * Send a packet to the given players through the given channel. The payload - * will only be written if the channel is open for at least one player. - */ - public static void send(Iterable players, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.send(players, channel, payload); - } - - /** - * Send a packet to the given players through the given channel. The writer - * will only be called if the channel is open for at least one player. - */ - public static void send(Iterable players, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.send(players, channel, writer); - } - - /** - * Send a packet to the given players through the given channel. - */ - public static void send(Iterable players, String channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.send(players, channel, data); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel. The payload will only be written if the channel is open for at - * least one player. - */ - public static void send(int dimension, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.send(dimension, channel, payload); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel. The writer will only be called if the channel is open for at - * least one player. - */ - public static void send(int dimension, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.send(dimension, channel, writer); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel. - */ - public static void send(int dimension, String channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.send(dimension, channel, data); - } - - /** - * Send a packet to all players through the given channel. The payload will - * only be written if the channel is open for at least one player. - */ - public static void send(String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.send(channel, payload); - } - - /** - * Send a packet to all players through the given channel. The writer will - * only be called if the channel is open for at least one player. - */ - public static void send(String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.send(channel, writer); - } - - /** - * Send a packet to all players through the given channel. - */ - public static void send(String channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.send(channel, data); - } - - /** - * Send a packet to the given player through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(ServerPlayerEntity player, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(player, channel, payload); - } - - /** - * Send a packet to the given player through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(ServerPlayerEntity player, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(player, channel, writer); - } - - /** - * Send a packet to the given player through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(ServerPlayerEntity player, String channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.doSend(player, channel, data); - } - - /** - * Send a packet to the given players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(Iterable players, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(players, channel, payload); - } - - /** - * Send a packet to the given players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(Iterable players, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(players, channel, writer); - } - - /** - * Send a packet to the given players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(Iterable players, String channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.doSend(players, channel, data); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel, without checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(int dimension, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(dimension, channel, payload); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel, without checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(int dimension, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(dimension, channel, writer); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel, without checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(int dimension, String channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.doSend(dimension, channel, data); - } - - /** - * Send a packet to all players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(channel, payload); - } - - /** - * Send a packet to all players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(channel, writer); - } - - /** - * Send a packet to all players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(String channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.doSend(channel, data); - } - - public interface PayloadListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, T payload) throws IOException; - - } - - public interface ByteBufListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, PacketByteBuf data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java b/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java deleted file mode 100644 index 5ad5c022..00000000 --- a/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java +++ /dev/null @@ -1,55 +0,0 @@ -package net.ornithemc.osl.networking.impl; - -import java.io.IOException; -import java.util.LinkedHashSet; -import java.util.Set; - -import net.minecraft.network.PacketByteBuf; - -import net.ornithemc.osl.networking.api.Channels; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -public class HandshakePayload implements CustomPayload { - - public static final String CHANNEL = "OSL|Handshake"; - - public Set channels; - - public HandshakePayload() { - } - - public HandshakePayload(Set channels) { - this.channels = channels; - } - - public static HandshakePayload client() { - return new HandshakePayload(ClientPlayNetworkingImpl.LISTENERS.keySet()); - } - - public static HandshakePayload server() { - return new HandshakePayload(ServerPlayNetworkingImpl.LISTENERS.keySet()); - } - - @Override - public void read(PacketByteBuf buffer) throws IOException { - channels = new LinkedHashSet<>(); - int channelCount = buffer.readInt(); - - if (channelCount > 0) { - for (int i = 0; i < channelCount; i++) { - channels.add(buffer.readString(Channels.MAX_LENGTH)); - } - } - } - - @Override - public void write(PacketByteBuf buffer) throws IOException { - buffer.writeInt(channels.size()); - - for (String channel : channels) { - buffer.writeString(channel); - } - } -} diff --git a/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/NetworkListener.java b/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/NetworkListener.java deleted file mode 100644 index 7e34822c..00000000 --- a/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/NetworkListener.java +++ /dev/null @@ -1,20 +0,0 @@ -package net.ornithemc.osl.networking.impl; - -public class NetworkListener { - - private final T listener; - private final boolean async; - - public NetworkListener(T listener, boolean async) { - this.listener = listener; - this.async = async; - } - - public T get() { - return listener; - } - - public boolean isAsync() { - return async; - } -} diff --git a/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/Networking.java deleted file mode 100644 index 601d2f5d..00000000 --- a/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/Networking.java +++ /dev/null @@ -1,57 +0,0 @@ -package net.ornithemc.osl.networking.impl; - -import net.ornithemc.osl.entrypoints.api.ModInitializer; -import net.ornithemc.osl.entrypoints.api.client.ClientModInitializer; -import net.ornithemc.osl.entrypoints.api.server.ServerModInitializer; -import net.ornithemc.osl.lifecycle.api.client.MinecraftClientEvents; -import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; -import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking; -import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking; -import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -public class Networking implements ModInitializer, ClientModInitializer, ServerModInitializer { - - @Override - public void init() { - MinecraftServerEvents.START.register(server -> { - ServerPlayNetworkingImpl.setUp(server); - }); - MinecraftServerEvents.STOP.register(server -> { - ServerPlayNetworkingImpl.destroy(server); - }); - ServerPlayNetworking.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { - // send channel registration data as a response to receiving client channel registration data - ServerPlayNetworkingImpl.doSend(player, HandshakePayload.CHANNEL, HandshakePayload.server()); - - ((INetworkHandler)handler).osl$networking$registerChannels(payload.channels); - ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); - - return true; - }); - } - - @Override - public void initClient() { - MinecraftClientEvents.START.register(minecraft -> { - ClientPlayNetworkingImpl.setUp(minecraft); - }); - MinecraftClientEvents.STOP.register(minecraft -> { - ClientPlayNetworkingImpl.destroy(minecraft); - }); - ClientPlayNetworking.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { - ((INetworkHandler)handler).osl$networking$registerChannels(payload.channels); - ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); - - return true; - }); - } - - @Override - public void initServer() { - // empty impl - } -} diff --git a/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java b/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java deleted file mode 100644 index f9078808..00000000 --- a/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java +++ /dev/null @@ -1,185 +0,0 @@ -package net.ornithemc.osl.networking.impl.client; - -import java.io.IOException; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.function.Supplier; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.network.handler.ClientPlayNetworkHandler; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.network.PacketUtils; -import net.minecraft.network.packet.Packet; -import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; -import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.Channels; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.api.PacketByteBufs; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.ByteBufListener; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.PayloadListener; -import net.ornithemc.osl.networking.impl.NetworkListener; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; - -public final class ClientPlayNetworkingImpl { - - private static final Logger LOGGER = LogManager.getLogger("OSL|Client Play Networking"); - - private static Minecraft minecraft; - - public static void setUp(Minecraft minecraft) { - if (ClientPlayNetworkingImpl.minecraft == minecraft) { - throw new IllegalStateException("tried to set up client networking when it was already set up!"); - } - - ClientPlayNetworkingImpl.minecraft = minecraft; - } - - public static void destroy(Minecraft minecraft) { - if (ClientPlayNetworkingImpl.minecraft != minecraft) { - throw new IllegalStateException("tried to destroy client networking when it was not set up!"); - } - - ClientPlayNetworkingImpl.minecraft = null; - } - - public static final Map> LISTENERS = new LinkedHashMap<>(); - - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - registerListener(channel, initializer, listener, false); - } - - public static void registerListenerAsync(String channel, Supplier initializer, PayloadListener listener) { - registerListener(channel, initializer, listener, true); - } - - private static void registerListener(String channel, Supplier initializer, PayloadListener listener, boolean async) { - registerListenerImpl(channel, (minecraft, handler, data) -> { - T payload = initializer.get(); - payload.read(data); - - return listener.handle(minecraft, handler, payload); - }, async); - } - - public static void registerListener(String channel, ByteBufListener listener) { - registerListener(channel, listener, false); - } - - public static void registerListenerAsync(String channel, ByteBufListener listener) { - registerListener(channel, listener, true); - } - - private static void registerListener(String channel, ByteBufListener listener, boolean async) { - registerListenerImpl(channel, listener::handle, async); - } - - private static void registerListenerImpl(String channel, Listener listener, boolean async) { - LISTENERS.compute(channel, (key, value) -> { - Channels.validate(channel); - - if (value != null) { - throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); - } - - return new NetworkListener<>(listener, async); - }); - } - - public static void unregisterListener(String channel) { - LISTENERS.remove(channel); - } - - public static boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, CustomPayloadS2CPacket packet) { - String channel = packet.getChannel(); - NetworkListener listener = LISTENERS.get(channel); - - if (listener != null) { - if (!listener.isAsync()) { - PacketUtils.ensureOnSameThread(packet, handler, minecraft); - } - - try { - return listener.get().handle(minecraft, handler, packet.getData()); - } catch (IOException e) { - LOGGER.warn("error handling custom payload on channel \'" + channel + "\'", e); - return true; - } - } - - return false; - } - - public static boolean isPlayReady() { - INetworkHandler handler = (INetworkHandler)minecraft.getNetworkHandler(); - return handler != null && handler.osl$networking$isPlayReady(); - } - - public static boolean canSend(String channel) { - INetworkHandler handler = (INetworkHandler)minecraft.getNetworkHandler(); - return handler != null && handler.osl$networking$isRegisteredChannel(channel); - } - - public static void send(String channel, CustomPayload payload) { - if (canSend(channel)) { - doSend(channel, payload); - } - } - - public static void send(String channel, IOConsumer writer) { - if (canSend(channel)) { - doSend(channel, writer); - } - } - - public static void send(String channel, PacketByteBuf data) { - if (canSend(channel)) { - doSend(channel, data); - } - } - - public static void doSend(String channel, CustomPayload payload) { - sendPacket(makePacket(channel, payload)); - } - - public static void doSend(String channel, IOConsumer writer) { - sendPacket(makePacket(channel, writer)); - } - - public static void doSend(String channel, PacketByteBuf data) { - sendPacket(makePacket(channel, data)); - } - - private static Packet makePacket(String channel, CustomPayload payload) { - return makePacket(channel, payload::write); - } - - private static Packet makePacket(String channel, IOConsumer writer) { - try { - return new CustomPayloadC2SPacket(channel, PacketByteBufs.make(writer)); - } catch (IOException e) { - LOGGER.warn("error writing custom payload to channel \'" + channel + "\'", e); - return null; - } - } - - private static Packet makePacket(String channel, PacketByteBuf data) { - return new CustomPayloadC2SPacket(channel, data); - } - - private static void sendPacket(Packet packet) { - if (packet != null) { - minecraft.getNetworkHandler().sendPacket(packet); - } - } - - private interface Listener { - - boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, PacketByteBuf data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java b/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java deleted file mode 100644 index a5519db4..00000000 --- a/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java +++ /dev/null @@ -1,13 +0,0 @@ -package net.ornithemc.osl.networking.impl.interfaces.mixin; - -import java.util.Set; - -public interface INetworkHandler { - - boolean osl$networking$isPlayReady(); - - void osl$networking$registerChannels(Set channels); - - boolean osl$networking$isRegisteredChannel(String channel); - -} diff --git a/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/IPlayerManager.java b/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/IPlayerManager.java deleted file mode 100644 index 71925ecd..00000000 --- a/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/IPlayerManager.java +++ /dev/null @@ -1,13 +0,0 @@ -package net.ornithemc.osl.networking.impl.interfaces.mixin; - -import java.util.List; - -import net.minecraft.server.entity.living.player.ServerPlayerEntity; - -public interface IPlayerManager { - - // a getAll method does exist but only in 1.8.1-pre3 and above - - List osl$networking$getAll(); - -} diff --git a/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java b/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java deleted file mode 100644 index 4921990c..00000000 --- a/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java +++ /dev/null @@ -1,286 +0,0 @@ -package net.ornithemc.osl.networking.impl.server; - -import java.io.IOException; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.function.Supplier; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import net.minecraft.network.PacketByteBuf; -import net.minecraft.network.PacketUtils; -import net.minecraft.network.packet.Packet; -import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; -import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.entity.living.player.ServerPlayerEntity; -import net.minecraft.server.network.handler.ServerPlayNetworkHandler; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.Channels; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.api.PacketByteBufs; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.ByteBufListener; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.PayloadListener; -import net.ornithemc.osl.networking.impl.NetworkListener; -import net.ornithemc.osl.networking.impl.interfaces.mixin.IPlayerManager; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; - -public final class ServerPlayNetworkingImpl { - - private static final Logger LOGGER = LogManager.getLogger("OSL|Server Play Networking"); - - private static MinecraftServer server; - - public static void setUp(MinecraftServer server) { - if (ServerPlayNetworkingImpl.server == server) { - throw new IllegalStateException("tried to set up server networking when it was already set up!"); - } - - ServerPlayNetworkingImpl.server = server; - } - - public static void destroy(MinecraftServer server) { - if (ServerPlayNetworkingImpl.server != server) { - throw new IllegalStateException("tried to destroy server networking when it was not set up!"); - } - - ServerPlayNetworkingImpl.server = null; - } - - public static final Map> LISTENERS = new LinkedHashMap<>(); - - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - registerListener(channel, initializer, listener, false); - } - - public static void registerListenerAsync(String channel, Supplier initializer, PayloadListener listener) { - registerListener(channel, initializer, listener, true); - } - - private static void registerListener(String channel, Supplier initializer, PayloadListener listener, boolean async) { - registerListenerImpl(channel, (server, handler, player, data) -> { - T payload = initializer.get(); - payload.read(data); - - return listener.handle(server, handler, player, payload); - }, async); - } - - public static void registerListener(String channel, ByteBufListener listener) { - registerListener(channel, listener, false); - } - - public static void registerListenerAsync(String channel, ByteBufListener listener) { - registerListener(channel, listener, true); - } - - private static void registerListener(String channel, ByteBufListener listener, boolean async) { - registerListenerImpl(channel, listener::handle, async); - } - - private static void registerListenerImpl(String channel, Listener listener, boolean async) { - LISTENERS.compute(channel, (key, value) -> { - Channels.validate(channel); - - if (value != null) { - throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); - } - - return new NetworkListener<>(listener, async); - }); - } - - public static void unregisterListener(String channel) { - LISTENERS.remove(channel); - } - - public static boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, CustomPayloadC2SPacket packet) { - String channel = packet.getChannel(); - NetworkListener listener = LISTENERS.get(channel); - - if (listener != null) { - if (!listener.isAsync()) { - PacketUtils.ensureOnSameThread(packet, handler, server); - } - - try { - return listener.get().handle(server, handler, player, packet.getData()); - } catch (IOException e) { - LOGGER.warn("error handling custom payload on channel \'" + channel + "\'", e); - return true; - } - } - - return false; - } - - public static boolean isPlayReady(ServerPlayerEntity player) { - INetworkHandler handler = (INetworkHandler)player.networkHandler; - return handler != null && handler.osl$networking$isPlayReady(); - } - - public static boolean canSend(ServerPlayerEntity player, String channel) { - INetworkHandler handler = (INetworkHandler)player.networkHandler; - return handler != null && handler.osl$networking$isRegisteredChannel(channel); - } - - public static void send(ServerPlayerEntity player, String channel, CustomPayload payload) { - if (canSend(player, channel)) { - doSend(player, channel, payload); - } - } - - public static void send(ServerPlayerEntity player, String channel, IOConsumer writer) { - if (canSend(player, channel)) { - doSend(player, channel, writer); - } - } - - public static void send(ServerPlayerEntity player, String channel, PacketByteBuf data) { - if (canSend(player, channel)) { - doSend(player, channel, data); - } - } - - public static void send(Iterable players, String channel, CustomPayload payload) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, payload)); - } - - public static void send(Iterable players, String channel, IOConsumer writer) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, writer)); - } - - public static void send(Iterable players, String channel, PacketByteBuf data) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, data)); - } - - public static void send(int dimension, String channel, CustomPayload payload) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)), channel, payload); - } - - public static void send(int dimension, String channel, IOConsumer writer) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)), channel, writer); - } - - public static void send(int dimension, String channel, PacketByteBuf data) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)),channel, data); - } - - public static void send(String channel, CustomPayload payload) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, payload); - } - - public static void send(String channel, IOConsumer writer) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, writer); - } - - public static void send(String channel, PacketByteBuf data) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, data); - } - - public static void doSend(ServerPlayerEntity player, String channel, CustomPayload payload) { - sendPacket(player, makePacket(channel, payload)); - } - - public static void doSend(ServerPlayerEntity player, String channel, IOConsumer writer) { - sendPacket(player, makePacket(channel, writer)); - } - - public static void doSend(ServerPlayerEntity player, String channel, PacketByteBuf data) { - sendPacket(player, makePacket(channel, data)); - } - - public static void doSend(Iterable players, String channel, CustomPayload payload) { - sendPacket(players, makePacket(channel, payload)); - } - - public static void doSend(Iterable players, String channel, IOConsumer writer) { - sendPacket(players, makePacket(channel, writer)); - } - - public static void doSend(Iterable players, String channel, PacketByteBuf data) { - sendPacket(players, makePacket(channel, data)); - } - - public static void doSend(int dimension, String channel, CustomPayload payload) { - doSend(collectPlayers(p -> p.dimension == dimension), channel, payload); - } - - public static void doSend(int dimension, String channel, IOConsumer writer) { - doSend(collectPlayers(p -> p.dimension == dimension), channel, writer); - } - - public static void doSend(int dimension, String channel, PacketByteBuf data) { - doSend(collectPlayers(p -> p.dimension == dimension),channel, data); - } - - public static void doSend(String channel, CustomPayload payload) { - doSend(collectPlayers(p -> true), channel, payload); - } - - public static void doSend(String channel, IOConsumer writer) { - doSend(collectPlayers(p -> true), channel, writer); - } - - public static void doSend(String channel, PacketByteBuf data) { - doSend(collectPlayers(p -> true), channel, data); - } - - private static Iterable collectPlayers(Predicate filter) { - return collectPlayers(((IPlayerManager)server.getPlayerManager()).osl$networking$getAll(), filter); - } - - private static Iterable collectPlayers(Iterable src, Predicate filter) { - List players = new ArrayList<>(); - - for (ServerPlayerEntity player : src) { - if (filter.test(player)) { - players.add(player); - } - } - - return players; - } - - private static Packet makePacket(String channel, CustomPayload payload) { - return makePacket(channel, payload::write); - } - - private static Packet makePacket(String channel, IOConsumer writer) { - try { - return new CustomPayloadS2CPacket(channel, PacketByteBufs.make(writer)); - } catch (IOException e) { - LOGGER.warn("error writing custom payload to channel \'" + channel + "\'", e); - return null; - } - } - - private static Packet makePacket(String channel, PacketByteBuf data) { - return new CustomPayloadS2CPacket(channel, data); - } - - private static void sendPacket(ServerPlayerEntity player, Packet packet) { - if (packet != null) { - player.networkHandler.sendPacket(packet); - } - } - - private static void sendPacket(Iterable players, Packet packet) { - if (packet != null) { - for (ServerPlayerEntity player : players) { - sendPacket(player, packet); - } - } - } - - private interface Listener { - - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, PacketByteBuf data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/resources/osl.networking.mixins.json b/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/resources/osl.networking.mixins.json deleted file mode 100644 index b9030aa9..00000000 --- a/libraries/networking/networking-mc14w31a-mc1.13-pre2/src/main/resources/osl.networking.mixins.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "required": true, - "minVersion": "0.8", - "package": "net.ornithemc.osl.networking.impl.mixin", - "compatibilityLevel": "JAVA_8", - "mixins": [ - "common.PlayerManagerMixin", - "common.ServerPlayNetworkHandlerMixin" - ], - "client": [ - "client.ClientPlayNetworkHandlerMixin" - ], - "server": [ - ], - "injectors": { - "defaultRequire": 1 - } -} diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/gradle.properties b/libraries/networking/networking-mc18w31a-mc1.14.4/gradle.properties index 2f28bcb7..bd3aa07b 100644 --- a/libraries/networking/networking-mc18w31a-mc1.14.4/gradle.properties +++ b/libraries/networking/networking-mc18w31a-mc1.14.4/gradle.properties @@ -4,4 +4,4 @@ max_mc_version = 1.14.4 mc_version_range = >=1.13.1-alpha.18.31.a <=1.14.4 minecraft_version = 1.14.4 -feather_build = 1 +feather_build = 2 diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java deleted file mode 100644 index aee6a1cd..00000000 --- a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java +++ /dev/null @@ -1,13 +0,0 @@ -package net.ornithemc.osl.networking.api; - -import java.io.IOException; - -import net.minecraft.network.PacketByteBuf; - -public interface CustomPayload { - - void read(PacketByteBuf buffer) throws IOException; - - void write(PacketByteBuf buffer) throws IOException; - -} diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/IdentifierChannelIdentifierParser.java b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/IdentifierChannelIdentifierParser.java new file mode 100644 index 00000000..e3de1820 --- /dev/null +++ b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/IdentifierChannelIdentifierParser.java @@ -0,0 +1,49 @@ +package net.ornithemc.osl.networking.api; + +import net.minecraft.resource.Identifier; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.impl.util.NamespacedIdentifierImpl; +import net.ornithemc.osl.networking.impl.ChannelIdentifierException; +import net.ornithemc.osl.networking.impl.ChannelIdentifierParseException; + +/** + * Utility methods for converting {@link NamespacedIdentifier}s from and to {@link Identifier}s. + */ +public final class IdentifierChannelIdentifierParser { + + /** + * Convert the given {@code Identifier} to a {@link NamespacedIdentifier}. + * The returned channel identifier may be invalid. + * + * @return the {@code NamespacedIdentifier} represented by the {@code Identifier}. + */ + public static NamespacedIdentifier fromIdentifier(Identifier id) { + return new NamespacedIdentifierImpl(id.getNamespace(), id.getPath()); + } + + /** + * Convert the given {@code Identifier} to a {@code NamespacedIdentifier}. + * The returned channel identifier is always valid. If no valid channel + * identifier can be parsed from the given identifier, an exception is + * thrown. + * + * @return the {@code NamespacedIdentifier} represented by the {@code Identifier}. + * @throws ChannelIdentifierParseException + * if no valid {@code NamespacedIdentifier} can be parsed from the given {@code Identifier}. + */ + public static NamespacedIdentifier fromIdentifierOrThrow(Identifier id) { + try { + return ChannelIdentifiers.from(id.getNamespace(), id.getPath()); + } catch (ChannelIdentifierException e) { + throw ChannelIdentifierParseException.invalid(id.toString(), e); + } + } + + /** + * Convert the given {@code NamespacedIdentifier} to its {@code Identifier} representation. + */ + public static Identifier toIdentifier(NamespacedIdentifier id) { + return new Identifier(id.namespace(), id.identifier()); + } +} diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/PacketBuffer.java b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/PacketBuffer.java new file mode 100644 index 00000000..368bf2b5 --- /dev/null +++ b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/PacketBuffer.java @@ -0,0 +1,1113 @@ +package net.ornithemc.osl.networking.api; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.channels.FileChannel; +import java.nio.channels.GatheringByteChannel; +import java.nio.channels.ScatteringByteChannel; +import java.nio.charset.Charset; +import java.util.Date; +import java.util.UUID; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.util.ByteProcessor; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.resource.Identifier; +import net.minecraft.text.Text; +import net.minecraft.util.math.BlockPos; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.NamespacedIdentifiers; + +public class PacketBuffer extends ByteBuf { + + final PacketByteBuf delegate; + + public PacketBuffer(ByteBuf delegate) { + this(new PacketByteBuf(delegate)); + } + + public PacketBuffer(PacketByteBuf delegate) { + this.delegate = delegate; + } + + public int readVarInt() { + return this.delegate.readVarInt(); + } + + public long readVarLong() { + return this.delegate.readVarLong(); + } + + public byte[] readByteArray() { + return this.delegate.readByteArray(); + } + + public byte[] readByteArray(int maxLength) { + return this.delegate.readByteArray(maxLength); + } + + public int[] readIntArray() { + return this.delegate.readIntArray(); + } + + public int[] readIntArray(int maxLength) { + return this.delegate.readIntArray(maxLength); + } + + public long[] readLongArray() { + return this.readLongArray(this.readableBytes() / 8); + } + + public long[] readLongArray(int maxLength) { + int length = this.readVarInt(); + + if (length > maxLength) { + throw new IllegalStateException("LongArray with size " + length + " is bigger than allowed " + maxLength); + } + + long[] values = new long[length]; + + for (int i = 0; i < length; i++) { + values[i] = this.readVarLong(); + } + + return values; + } + + public String readString() { + return this.readString(Short.MAX_VALUE); + } + + public String readString(int maxLength) { + return this.delegate.readString(maxLength); + } + + public > T readEnum(Class type) { + return this.delegate.readEnum(type); + } + + public Date readDate() { + return this.delegate.readDate(); + } + + public UUID readUuid() { + return this.delegate.readUuid(); + } + + public BlockPos readBlockPos() { + return this.delegate.readBlockPos(); + } + + public Identifier readIdentifier() { + return this.delegate.readIdentifier(); + } + + public NamespacedIdentifier readNamespacedIdentifier() { + return NamespacedIdentifiers.parse(this.readString()); + } + + public Text readText() { + return this.delegate.readText(); + } + + public NbtCompound readNbtCompound() { + return this.delegate.readNbtCompound(); + } + + public ItemStack readItem() { + return this.delegate.readItem(); + } + + public ByteBuf writeVarInt(int value) { + return this.delegate.writeVarInt(value); + } + + public ByteBuf writeVarLong(long value) { + return this.delegate.writeVarLong(value); + } + + public ByteBuf writeByteArray(byte[] bytes) { + return this.delegate.writeByteArray(bytes); + } + + public ByteBuf writeIntArray(int[] values) { + return this.delegate.writeIntArray(values); + } + + public ByteBuf writeLongArray(long[] values) { + this.writeVarInt(values.length); + + for (long value : values) { + this.writeVarLong(value); + } + + return this; + } + + public ByteBuf writeString(String s) { + return this.writeString(s, Short.MAX_VALUE); + } + + public ByteBuf writeString(String s, int maxLength) { + return this.delegate.writeString(s, maxLength); + } + + public ByteBuf writeEnum(Enum value) { + return this.delegate.writeEnum(value); + } + + public ByteBuf writeDate(Date date) { + return this.delegate.writeDate(date); + } + + public ByteBuf writeUuid(UUID uuid) { + return this.delegate.writeUuid(uuid); + } + + public ByteBuf writeBlockPos(BlockPos pos) { + return this.delegate.writeBlockPos(pos); + } + + public ByteBuf writeIdentifier(Identifier id) { + return this.delegate.writeIdentifier(id); + } + + public ByteBuf writeNamespacedIdentifier(NamespacedIdentifier id) { + return this.writeString(id.toString()); + } + + public ByteBuf writeText(Text text) { + return this.delegate.writeText(text); + } + + public ByteBuf writeNbtCompound(NbtCompound nbt) { + return this.delegate.writeNbtCompound(nbt); + } + + public ByteBuf writeItem(ItemStack item) { + return this.delegate.writeItem(item); + } + + @Override + public int capacity() { + return this.delegate.capacity(); + } + + @Override + public ByteBuf capacity(int newCapacity) { + return this.delegate.capacity(newCapacity); + } + + @Override + public int maxCapacity() { + return this.delegate.maxCapacity(); + } + + @Override + public ByteBufAllocator alloc() { + return this.delegate.alloc(); + } + + @Override + public ByteOrder order() { + return this.delegate.order(); + } + + @Override + public ByteBuf order(ByteOrder order) { + return this.delegate.order(order); + } + + @Override + public ByteBuf unwrap() { + return this.delegate.unwrap(); + } + + @Override + public boolean isDirect() { + return this.delegate.isDirect(); + } + + @Override + public boolean isReadOnly() { + return this.delegate.isReadOnly(); + } + + @Override + public ByteBuf asReadOnly() { + return this.delegate.asReadOnly(); + } + + @Override + public int readerIndex() { + return this.delegate.readerIndex(); + } + + @Override + public ByteBuf readerIndex(int readerIndex) { + return this.delegate.readerIndex(readerIndex); + } + + @Override + public int writerIndex() { + return this.delegate.writerIndex(); + } + + @Override + public ByteBuf writerIndex(int writerIndex) { + return this.delegate.writerIndex(writerIndex); + } + + @Override + public ByteBuf setIndex(int readerIndex, int writerIndex) { + return this.delegate.setIndex(readerIndex, writerIndex); + } + + @Override + public int readableBytes() { + return this.delegate.readableBytes(); + } + + @Override + public int writableBytes() { + return this.delegate.writableBytes(); + } + + @Override + public int maxWritableBytes() { + return this.delegate.maxWritableBytes(); + } + + @Override + public boolean isReadable() { + return this.delegate.isReadable(); + } + + @Override + public boolean isReadable(int size) { + return this.delegate.isReadable(size); + } + + @Override + public boolean isWritable() { + return this.delegate.isWritable(); + } + + @Override + public boolean isWritable(int size) { + return this.delegate.isWritable(size); + } + + @Override + public ByteBuf clear() { + return this.delegate.clear(); + } + + @Override + public ByteBuf markReaderIndex() { + return this.delegate.markReaderIndex(); + } + + @Override + public ByteBuf resetReaderIndex() { + return this.delegate.resetReaderIndex(); + } + + @Override + public ByteBuf markWriterIndex() { + return this.delegate.markWriterIndex(); + } + + @Override + public ByteBuf resetWriterIndex() { + return this.delegate.resetWriterIndex(); + } + + @Override + public ByteBuf discardReadBytes() { + return this.delegate.discardReadBytes(); + } + + @Override + public ByteBuf discardSomeReadBytes() { + return this.delegate.discardSomeReadBytes(); + } + + @Override + public ByteBuf ensureWritable(int minWritableBytes) { + return this.delegate.ensureWritable(minWritableBytes); + } + + @Override + public int ensureWritable(int minWritableBytes, boolean force) { + return this.delegate.ensureWritable(minWritableBytes, force); + } + + @Override + public boolean getBoolean(int index) { + return this.delegate.getBoolean(index); + } + + @Override + public byte getByte(int index) { + return this.delegate.getByte(index); + } + + @Override + public short getUnsignedByte(int index) { + return this.delegate.getUnsignedByte(index); + } + + @Override + public short getShort(int index) { + return this.delegate.getShort(index); + } + + @Override + public short getShortLE(int index) { + return this.delegate.getShortLE(index); + } + + @Override + public int getUnsignedShort(int index) { + return this.delegate.getUnsignedShort(index); + } + + @Override + public int getUnsignedShortLE(int index) { + return this.delegate.getUnsignedShortLE(index); + } + + @Override + public int getMedium(int index) { + return this.delegate.getMedium(index); + } + + @Override + public int getMediumLE(int index) { + return this.delegate.getMediumLE(index); + } + + @Override + public int getUnsignedMedium(int index) { + return this.delegate.getUnsignedMedium(index); + } + + @Override + public int getUnsignedMediumLE(int index) { + return this.delegate.getUnsignedMediumLE(index); + } + + @Override + public int getInt(int index) { + return this.delegate.getInt(index); + } + + @Override + public int getIntLE(int index) { + return this.delegate.getIntLE(index); + } + + @Override + public long getUnsignedInt(int index) { + return this.delegate.getUnsignedInt(index); + } + + @Override + public long getUnsignedIntLE(int index) { + return this.delegate.getUnsignedIntLE(index); + } + + @Override + public long getLong(int index) { + return this.delegate.getLong(index); + } + + @Override + public long getLongLE(int index) { + return this.delegate.getLongLE(index); + } + + @Override + public char getChar(int index) { + return this.delegate.getChar(index); + } + + @Override + public float getFloat(int index) { + return this.delegate.getFloat(index); + } + + @Override + public double getDouble(int index) { + return this.delegate.getDouble(index); + } + + @Override + public ByteBuf getBytes(int index, ByteBuf dst) { + return this.delegate.getBytes(index, dst); + } + + @Override + public ByteBuf getBytes(int index, ByteBuf dst, int length) { + return this.delegate.getBytes(index, dst, length); + } + + @Override + public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) { + return this.delegate.getBytes(index, dst, dstIndex, length); + } + + @Override + public ByteBuf getBytes(int index, byte[] dst) { + return this.delegate.getBytes(index, dst); + } + + @Override + public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) { + return this.delegate.getBytes(index, dst, dstIndex, length); + } + + @Override + public ByteBuf getBytes(int index, ByteBuffer dst) { + return this.delegate.getBytes(index, dst); + } + + @Override + public ByteBuf getBytes(int index, OutputStream out, int length) throws IOException { + return this.delegate.getBytes(index, out, length); + } + + @Override + public int getBytes(int index, GatheringByteChannel out, int length) throws IOException { + return this.delegate.getBytes(index, out, length); + } + + @Override + public int getBytes(int index, FileChannel out, long position, int length) throws IOException { + return this.delegate.getBytes(index, out, position, length); + } + + @Override + public CharSequence getCharSequence(int index, int length, Charset charset) { + return this.delegate.getCharSequence(index, length, charset); + } + + @Override + public ByteBuf setBoolean(int index, boolean value) { + return this.delegate.setBoolean(index, value); + } + + @Override + public ByteBuf setByte(int index, int value) { + return this.delegate.setByte(index, value); + } + + @Override + public ByteBuf setShort(int index, int value) { + return this.delegate.setShort(index, value); + } + + @Override + public ByteBuf setShortLE(int index, int value) { + return this.delegate.setShortLE(index, value); + } + + @Override + public ByteBuf setMedium(int index, int value) { + return this.delegate.setMedium(index, value); + } + + @Override + public ByteBuf setMediumLE(int index, int value) { + return this.delegate.setMediumLE(index, value); + } + + @Override + public ByteBuf setInt(int index, int value) { + return this.delegate.setInt(index, value); + } + + @Override + public ByteBuf setIntLE(int index, int value) { + return this.delegate.setIntLE(index, value); + } + + @Override + public ByteBuf setLong(int index, long value) { + return this.delegate.setLong(index, value); + } + + @Override + public ByteBuf setLongLE(int index, long value) { + return this.delegate.setLongLE(index, value); + } + + @Override + public ByteBuf setChar(int index, int value) { + return this.delegate.setChar(index, value); + } + + @Override + public ByteBuf setFloat(int index, float value) { + return this.delegate.setFloat(index, value); + } + + @Override + public ByteBuf setDouble(int index, double value) { + return this.delegate.setDouble(index, value); + } + + @Override + public ByteBuf setBytes(int index, ByteBuf src) { + return this.delegate.setBytes(index, src); + } + + @Override + public ByteBuf setBytes(int index, ByteBuf src, int length) { + return this.delegate.setBytes(index, src, length); + } + + @Override + public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) { + return this.delegate.setBytes(index, src, srcIndex, length); + } + + @Override + public ByteBuf setBytes(int index, byte[] src) { + return this.delegate.setBytes(index, src); + } + + @Override + public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) { + return this.delegate.setBytes(index, src, srcIndex, length); + } + + @Override + public ByteBuf setBytes(int index, ByteBuffer src) { + return this.delegate.setBytes(index, src); + } + + @Override + public int setBytes(int index, InputStream in, int length) throws IOException { + return this.delegate.setBytes(index, in, length); + } + + @Override + public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException { + return this.delegate.setBytes(index, in, length); + } + + @Override + public int setBytes(int index, FileChannel in, long position, int length) throws IOException { + return this.delegate.setBytes(index, in, position, length); + } + + @Override + public ByteBuf setZero(int index, int length) { + return this.delegate.setZero(index, length); + } + + @Override + public int setCharSequence(int index, CharSequence sequence, Charset charset) { + return this.delegate.setCharSequence(index, sequence, charset); + } + + @Override + public boolean readBoolean() { + return this.delegate.readBoolean(); + } + + @Override + public byte readByte() { + return this.delegate.readByte(); + } + + @Override + public short readUnsignedByte() { + return this.delegate.readUnsignedByte(); + } + + @Override + public short readShort() { + return this.delegate.readShort(); + } + + @Override + public short readShortLE() { + return this.delegate.readShortLE(); + } + + @Override + public int readUnsignedShort() { + return this.delegate.readUnsignedShort(); + } + + @Override + public int readUnsignedShortLE() { + return this.delegate.readUnsignedShortLE(); + } + + @Override + public int readMedium() { + return this.delegate.readMedium(); + } + + @Override + public int readMediumLE() { + return this.delegate.readMediumLE(); + } + + @Override + public int readUnsignedMedium() { + return this.delegate.readUnsignedMedium(); + } + + @Override + public int readUnsignedMediumLE() { + return this.delegate.readUnsignedMediumLE(); + } + + @Override + public int readInt() { + return this.delegate.readInt(); + } + + @Override + public int readIntLE() { + return this.delegate.readIntLE(); + } + + @Override + public long readUnsignedInt() { + return this.delegate.readUnsignedInt(); + } + + @Override + public long readUnsignedIntLE() { + return this.delegate.readUnsignedIntLE(); + } + + @Override + public long readLong() { + return this.delegate.readLong(); + } + + @Override + public long readLongLE() { + return this.delegate.readLongLE(); + } + + @Override + public char readChar() { + return this.delegate.readChar(); + } + + @Override + public float readFloat() { + return this.delegate.readFloat(); + } + + @Override + public double readDouble() { + return this.delegate.readDouble(); + } + + @Override + public ByteBuf readBytes(int length) { + return this.delegate.readBytes(length); + } + + @Override + public ByteBuf readSlice(int length) { + return this.delegate.readSlice(length); + } + + @Override + public ByteBuf readRetainedSlice(int length) { + return this.delegate.readRetainedSlice(length); + } + + @Override + public ByteBuf readBytes(ByteBuf dst) { + return this.delegate.readBytes(dst); + } + + @Override + public ByteBuf readBytes(ByteBuf dst, int length) { + return this.delegate.readBytes(dst, length); + } + + @Override + public ByteBuf readBytes(ByteBuf dst, int dstIndex, int length) { + return this.delegate.readBytes(dst, dstIndex, length); + } + + @Override + public ByteBuf readBytes(byte[] dst) { + return this.delegate.readBytes(dst); + } + + @Override + public ByteBuf readBytes(byte[] dst, int dstIndex, int length) { + return this.delegate.readBytes(dst, dstIndex, length); + } + + @Override + public ByteBuf readBytes(ByteBuffer dst) { + return this.delegate.readBytes(dst); + } + + @Override + public ByteBuf readBytes(OutputStream out, int length) throws IOException { + return this.delegate.readBytes(out, length); + } + + @Override + public int readBytes(GatheringByteChannel out, int length) throws IOException { + return this.delegate.readBytes(out, length); + } + + @Override + public CharSequence readCharSequence(int length, Charset charset) { + return this.delegate.readCharSequence(length, charset); + } + + @Override + public int readBytes(FileChannel out, long position, int length) throws IOException { + return this.delegate.readBytes(out, position, length); + } + + @Override + public ByteBuf skipBytes(int length) { + return this.delegate.skipBytes(length); + } + + @Override + public ByteBuf writeBoolean(boolean value) { + return this.delegate.writeBoolean(value); + } + + @Override + public ByteBuf writeByte(int value) { + return this.delegate.writeByte(value); + } + + @Override + public ByteBuf writeShort(int value) { + return this.delegate.writeShort(value); + } + + @Override + public ByteBuf writeShortLE(int value) { + return this.delegate.writeShortLE(value); + } + + @Override + public ByteBuf writeMedium(int value) { + return this.delegate.writeMedium(value); + } + + @Override + public ByteBuf writeMediumLE(int value) { + return this.delegate.writeMediumLE(value); + } + + @Override + public ByteBuf writeInt(int value) { + return this.delegate.writeInt(value); + } + + @Override + public ByteBuf writeIntLE(int value) { + return this.delegate.writeIntLE(value); + } + + @Override + public ByteBuf writeLong(long value) { + return this.delegate.writeLong(value); + } + + @Override + public ByteBuf writeLongLE(long value) { + return this.delegate.writeLongLE(value); + } + + @Override + public ByteBuf writeChar(int value) { + return this.delegate.writeChar(value); + } + + @Override + public ByteBuf writeFloat(float value) { + return this.delegate.writeFloat(value); + } + + @Override + public ByteBuf writeDouble(double value) { + return this.delegate.writeDouble(value); + } + + @Override + public ByteBuf writeBytes(ByteBuf src) { + return this.delegate.writeBytes(src); + } + + @Override + public ByteBuf writeBytes(ByteBuf src, int length) { + return this.delegate.writeBytes(src, length); + } + + @Override + public ByteBuf writeBytes(ByteBuf src, int srcIndex, int length) { + return this.delegate.writeBytes(src, srcIndex, length); + } + + @Override + public ByteBuf writeBytes(byte[] src) { + return this.delegate.writeBytes(src); + } + + @Override + public ByteBuf writeBytes(byte[] src, int srcIndex, int length) { + return this.delegate.writeBytes(src, srcIndex, length); + } + + @Override + public ByteBuf writeBytes(ByteBuffer src) { + return this.delegate.writeBytes(src); + } + + @Override + public int writeBytes(InputStream in, int length) throws IOException { + return this.delegate.writeBytes(in, length); + } + + @Override + public int writeBytes(ScatteringByteChannel in, int length) throws IOException { + return this.delegate.writeBytes(in, length); + } + + @Override + public int writeBytes(FileChannel in, long position, int length) throws IOException { + return this.delegate.writeBytes(in, position, length); + } + + @Override + public ByteBuf writeZero(int length) { + return this.delegate.writeZero(length); + } + + @Override + public int writeCharSequence(CharSequence sequence, Charset charset) { + return this.delegate.writeCharSequence(sequence, charset); + } + + @Override + public int indexOf(int fromIndex, int toIndex, byte value) { + return this.delegate.indexOf(fromIndex, toIndex, value); + } + + @Override + public int bytesBefore(byte value) { + return this.delegate.bytesBefore(value); + } + + @Override + public int bytesBefore(int length, byte value) { + return this.delegate.bytesBefore(length, value); + } + + @Override + public int bytesBefore(int index, int length, byte value) { + return this.delegate.bytesBefore(index, length, value); + } + + @Override + public int forEachByte(ByteProcessor processor) { + return this.delegate.forEachByte(processor); + } + + @Override + public int forEachByte(int index, int length, ByteProcessor processor) { + return this.delegate.forEachByte(index, length, processor); + } + + @Override + public int forEachByteDesc(ByteProcessor processor) { + return this.delegate.forEachByteDesc(processor); + } + + @Override + public int forEachByteDesc(int index, int length, ByteProcessor processor) { + return this.delegate.forEachByteDesc(index, length, processor); + } + + @Override + public ByteBuf copy() { + return this.delegate.copy(); + } + + @Override + public ByteBuf copy(int index, int length) { + return this.delegate.copy(index, length); + } + + @Override + public ByteBuf slice() { + return this.delegate.slice(); + } + + @Override + public ByteBuf retainedSlice() { + return this.delegate.retainedSlice(); + } + + @Override + public ByteBuf slice(int index, int length) { + return this.delegate.slice(index, length); + } + + @Override + public ByteBuf retainedSlice(int index, int length) { + return this.delegate.retainedSlice(index, length); + } + + @Override + public ByteBuf duplicate() { + return this.delegate.duplicate(); + } + + @Override + public ByteBuf retainedDuplicate() { + return this.delegate.retainedDuplicate(); + } + + @Override + public int nioBufferCount() { + return this.delegate.nioBufferCount(); + } + + @Override + public ByteBuffer nioBuffer() { + return this.delegate.nioBuffer(); + } + + @Override + public ByteBuffer nioBuffer(int index, int length) { + return this.delegate.nioBuffer(index, length); + } + + @Override + public ByteBuffer internalNioBuffer(int index, int length) { + return this.delegate.internalNioBuffer(index, length); + } + + @Override + public ByteBuffer[] nioBuffers() { + return this.delegate.nioBuffers(); + } + + @Override + public ByteBuffer[] nioBuffers(int index, int length) { + return this.delegate.nioBuffers(index, length); + } + + @Override + public boolean hasArray() { + return this.delegate.hasArray(); + } + + @Override + public byte[] array() { + return this.delegate.array(); + } + + @Override + public int arrayOffset() { + return this.delegate.arrayOffset(); + } + + @Override + public boolean hasMemoryAddress() { + return this.delegate.hasMemoryAddress(); + } + + @Override + public long memoryAddress() { + return this.delegate.memoryAddress(); + } + + @Override + public String toString(Charset charset) { + return this.delegate.toString(charset); + } + + @Override + public String toString(int index, int length, Charset charset) { + return this.delegate.toString(index, length, charset); + } + + @Override + public int hashCode() { + return this.delegate.hashCode(); + } + + @Override + public boolean equals(Object o) { + return this.delegate.equals(o); + } + + @Override + public int compareTo(ByteBuf o) { + return this.delegate.compareTo(o); + } + + @Override + public String toString() { + return this.delegate.toString(); + } + + @Override + public ByteBuf retain(int increment) { + return this.delegate.retain(increment); + } + + @Override + public ByteBuf retain() { + return this.delegate.retain(); + } + + @Override + public ByteBuf touch() { + return this.delegate.touch(); + } + + @Override + public ByteBuf touch(Object hint) { + return this.delegate.touch(hint); + } + + @Override + public int refCnt() { + return this.delegate.refCnt(); + } + + @Override + public boolean release() { + return this.delegate.release(); + } + + @Override + public boolean release(int decrement) { + return this.delegate.release(decrement); + } +} diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/PacketBuffers.java b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/PacketBuffers.java new file mode 100644 index 00000000..516f6420 --- /dev/null +++ b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/PacketBuffers.java @@ -0,0 +1,41 @@ +package net.ornithemc.osl.networking.api; + +import java.io.IOException; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; + +import net.minecraft.network.PacketByteBuf; + +import net.ornithemc.osl.core.api.util.function.IOConsumer; + +public final class PacketBuffers { + + public static PacketBuffer make() { + return wrapped(Unpooled.buffer()); + } + + public static PacketBuffer make(IOConsumer writer) throws IOException { + PacketBuffer buffer = make(); + writer.accept(buffer); + return buffer; + } + + public static PacketBuffer wrap(byte[] bytes) { + return wrapped(Unpooled.wrappedBuffer(bytes)); + } + + public static byte[] unwrap(PacketBuffer buffer) { + byte[] bytes = new byte[buffer.writerIndex()]; + buffer.getBytes(0, bytes); + return bytes; + } + + public static PacketBuffer wrapped(ByteBuf buffer) { + return new PacketBuffer(buffer); + } + + public static PacketByteBuf unwrapped(PacketBuffer buffer) { + return buffer.delegate; + } +} diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/PacketByteBufs.java b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/PacketByteBufs.java deleted file mode 100644 index e1944e62..00000000 --- a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/PacketByteBufs.java +++ /dev/null @@ -1,31 +0,0 @@ -package net.ornithemc.osl.networking.api; - -import java.io.IOException; - -import io.netty.buffer.ByteBuf; -import io.netty.buffer.Unpooled; - -import net.minecraft.network.PacketByteBuf; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; - -public final class PacketByteBufs { - - public static PacketByteBuf make() { - return make(Unpooled.buffer()); - } - - public static PacketByteBuf make(byte[] bytes) { - return make(Unpooled.wrappedBuffer(bytes)); - } - - public static PacketByteBuf make(ByteBuf buf) { - return new PacketByteBuf(buf); - } - - public static PacketByteBuf make(IOConsumer writer) throws IOException { - PacketByteBuf buffer = make(); - writer.accept(buffer); - return buffer; - } -} diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/PacketPayload.java b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/PacketPayload.java new file mode 100644 index 00000000..7f7835e7 --- /dev/null +++ b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/PacketPayload.java @@ -0,0 +1,11 @@ +package net.ornithemc.osl.networking.api; + +import java.io.IOException; + +public interface PacketPayload { + + void read(PacketBuffer buffer) throws IOException; + + void write(PacketBuffer buffer) throws IOException; + +} diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/client/ClientPacketListener.java b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/client/ClientPacketListener.java new file mode 100644 index 00000000..1e24b0e4 --- /dev/null +++ b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/client/ClientPacketListener.java @@ -0,0 +1,31 @@ +package net.ornithemc.osl.networking.api.client; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.network.handler.ClientPlayNetworkHandler; + +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketPayload; + +public interface ClientPacketListener { + + /** + * Receive incoming data from the server. + * + * @return + * Whether the data is consumed. Should only return {@code false} if the + * data is completely ignored. + */ + boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, T data); + + @FunctionalInterface + public interface Payload extends ClientPacketListener { + } + + @FunctionalInterface + public interface Buffer extends ClientPacketListener { + } + + @FunctionalInterface + public interface Bytes extends ClientPacketListener { + } +} diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java index cfb3c548..06d6ff52 100644 --- a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java +++ b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java @@ -1,15 +1,11 @@ package net.ornithemc.osl.networking.api.client; -import java.io.IOException; import java.util.function.Supplier; -import net.minecraft.client.Minecraft; -import net.minecraft.client.network.handler.ClientPlayNetworkHandler; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.resource.Identifier; - +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.CustomPayload; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketPayload; import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; public final class ClientPlayNetworking { @@ -17,43 +13,55 @@ public final class ClientPlayNetworking { /** * Register a listener to receive data from the server through the given channel. * This listener will only be called from the main thread. - * A channel can be any valid {@linkplain net.minecraft.resource.Identifier Identifier}. */ - public static void registerListener(Identifier channel, Supplier initializer, PayloadListener listener) { + public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { ClientPlayNetworkingImpl.registerListener(channel, initializer, listener); } /** * Register a listener to receive data from the server through the given channel. * This listener may be called off the main thread. - * A channel can be any valid {@linkplain net.minecraft.resource.Identifier Identifier}. */ - public static void registerListenerAsync(Identifier channel, Supplier initializer, PayloadListener listener) { + public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { ClientPlayNetworkingImpl.registerListenerAsync(channel, initializer, listener); } /** * Register a listener to receive data from the server through the given channel. * This listener will only be called from the main thread. - * A channel can be any valid {@linkplain net.minecraft.resource.Identifier Identifier}. */ - public static void registerListener(Identifier channel, ByteBufListener listener) { + public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { + ClientPlayNetworkingImpl.registerListener(channel, listener); + } + + /** + * Register a listener to receive data from the server through the given channel. + * This listener may be called off the main thread. + */ + public static void registerListenerAsync(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { + ClientPlayNetworkingImpl.registerListenerAsync(channel, listener); + } + + /** + * Register a listener to receive data from the server through the given channel. + * This listener will only be called from the main thread. + */ + public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { ClientPlayNetworkingImpl.registerListener(channel, listener); } /** * Register a listener to receive data from the server through the given channel. * This listener may be called off the main thread. - * A channel can be any valid {@linkplain net.minecraft.resource.Identifier Identifier}. */ - public static void registerListenerAsync(Identifier channel, ByteBufListener listener) { + public static void registerListenerAsync(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { ClientPlayNetworkingImpl.registerListenerAsync(channel, listener); } /** * Remove the listener registered to the given channel. */ - public static void unregisterListener(Identifier channel) { + public static void unregisterListener(NamespacedIdentifier channel) { ClientPlayNetworkingImpl.unregisterListener(channel); } @@ -69,15 +77,15 @@ public static boolean isPlayReady() { * This method will return {@code false} if the client is not connected to a * server, or if the server has no listeners for the given channel. */ - public static boolean canSend(Identifier channel) { - return ClientPlayNetworkingImpl.canSend(channel); + public static boolean isPlayReady(NamespacedIdentifier channel) { + return ClientPlayNetworkingImpl.isPlayReady(channel); } /** * Send a packet to the server through the given channel. The payload will * only be written if the channel is open. */ - public static void send(Identifier channel, CustomPayload payload) { + public static void send(NamespacedIdentifier channel, PacketPayload payload) { ClientPlayNetworkingImpl.send(channel, payload); } @@ -85,15 +93,22 @@ public static void send(Identifier channel, CustomPayload payload) { * Send a packet to the server through the given channel. The writer will * only be called if the channel is open. */ - public static void send(Identifier channel, IOConsumer writer) { + public static void send(NamespacedIdentifier channel, IOConsumer writer) { ClientPlayNetworkingImpl.send(channel, writer); } /** * Send a packet to the server through the given channel. */ - public static void send(Identifier channel, PacketByteBuf data) { - ClientPlayNetworkingImpl.send(channel, data); + public static void send(NamespacedIdentifier channel, PacketBuffer buffer) { + ClientPlayNetworkingImpl.send(channel, buffer); + } + + /** + * Send a packet to the server through the given channel. + */ + public static void send(NamespacedIdentifier channel, byte[] bytes) { + ClientPlayNetworkingImpl.send(channel, bytes); } /** @@ -102,8 +117,8 @@ public static void send(Identifier channel, PacketByteBuf data) { * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the server. */ - public static void doSend(Identifier channel, CustomPayload payload) { - ClientPlayNetworkingImpl.doSend(channel, payload); + public static void sendNoCheck(NamespacedIdentifier channel, PacketPayload payload) { + ClientPlayNetworkingImpl.sendNoCheck(channel, payload); } /** @@ -112,8 +127,8 @@ public static void doSend(Identifier channel, CustomPayload payload) { * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the server. */ - public static void doSend(Identifier channel, IOConsumer writer) { - ClientPlayNetworkingImpl.doSend(channel, writer); + public static void sendNoCheck(NamespacedIdentifier channel, IOConsumer writer) { + ClientPlayNetworkingImpl.sendNoCheck(channel, writer); } /** @@ -122,33 +137,17 @@ public static void doSend(Identifier channel, IOConsumer writer) * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the server. */ - public static void doSend(Identifier channel, PacketByteBuf data) { - ClientPlayNetworkingImpl.doSend(channel, data); - } - - public interface PayloadListener { - - /** - * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, T payload) throws IOException; - + public static void sendNoCheck(NamespacedIdentifier channel, PacketBuffer buffer) { + ClientPlayNetworkingImpl.sendNoCheck(channel, buffer); } - public interface ByteBufListener { - - /** - * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, PacketByteBuf data) throws IOException; - + /** + * Send a packet to the server through the given channel, without checking + * whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the server. + */ + public static void sendNoCheck(NamespacedIdentifier channel, byte[] bytes) { + ClientPlayNetworkingImpl.sendNoCheck(channel, bytes); } } diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java new file mode 100644 index 00000000..fc0a43a7 --- /dev/null +++ b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java @@ -0,0 +1,32 @@ +package net.ornithemc.osl.networking.api.server; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.entity.living.player.ServerPlayerEntity; +import net.minecraft.server.network.handler.ServerPlayNetworkHandler; + +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketPayload; + +public interface ServerPacketListener { + + /** + * Receive incoming data from the client. + * + * @return + * Whether the data is consumed. Should only return {@code false} if the + * data is completely ignored. + */ + boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, T data); + + @FunctionalInterface + public interface Payload extends ServerPacketListener { + } + + @FunctionalInterface + public interface Buffer extends ServerPacketListener { + } + + @FunctionalInterface + public interface Bytes extends ServerPacketListener { + } +} diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java index 4f9a8053..34a7821d 100644 --- a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java +++ b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java @@ -1,17 +1,14 @@ package net.ornithemc.osl.networking.api.server; -import java.io.IOException; import java.util.function.Supplier; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.resource.Identifier; -import net.minecraft.server.MinecraftServer; import net.minecraft.server.entity.living.player.ServerPlayerEntity; -import net.minecraft.server.network.handler.ServerPlayNetworkHandler; import net.minecraft.world.dimension.DimensionType; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.CustomPayload; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketPayload; import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; public final class ServerPlayNetworking { @@ -19,43 +16,55 @@ public final class ServerPlayNetworking { /** * Register a listener to receive data from the server through the given channel. * This listener will only be called from the main thread. - * A channel can be any valid {@linkplain net.minecraft.resource.Identifier Identifier}. */ - public static void registerListener(Identifier channel, Supplier initializer, PayloadListener listener) { + public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { ServerPlayNetworkingImpl.registerListener(channel, initializer, listener); } /** * Register a listener to receive data from the server through the given channel. * This listener may be called off the main thread. - * A channel can be any valid {@linkplain net.minecraft.resource.Identifier Identifier}. */ - public static void registerListenerAsync(Identifier channel, Supplier initializer, PayloadListener listener) { + public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { ServerPlayNetworkingImpl.registerListenerAsync(channel, initializer, listener); } /** * Register a listener to receive data from the server through the given channel. * This listener will only be called from the main thread. - * A channel can be any valid {@linkplain net.minecraft.resource.Identifier Identifier}. */ - public static void registerListener(Identifier channel, ByteBufListener listener) { + public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { ServerPlayNetworkingImpl.registerListener(channel, listener); } /** * Register a listener to receive data from the server through the given channel. * This listener may be called off the main thread. - * A channel can be any valid {@linkplain net.minecraft.resource.Identifier Identifier}. */ - public static void registerListenerAsync(Identifier channel, ByteBufListener listener) { + public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { + ServerPlayNetworkingImpl.registerListenerAsync(channel, listener); + } + + /** + * Register a listener to receive data from the server through the given channel. + * This listener will only be called from the main thread. + */ + public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { + ServerPlayNetworkingImpl.registerListener(channel, listener); + } + + /** + * Register a listener to receive data from the server through the given channel. + * This listener may be called off the main thread. + */ + public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { ServerPlayNetworkingImpl.registerListenerAsync(channel, listener); } /** * Remove the listener registered to the given channel. */ - public static void unregisterListener(Identifier channel) { + public static void unregisterListener(NamespacedIdentifier channel) { ServerPlayNetworkingImpl.unregisterListener(channel); } @@ -67,19 +76,19 @@ public static boolean isPlayReady(ServerPlayerEntity player) { } /** - * Check whether the given channel is open for data to be sent through it. + * Check whether the given channel is ready for data to be sent through it. * This method will return {@code false} if the client has no listeners for * the given channel. */ - public static boolean canSend(ServerPlayerEntity player, Identifier channel) { - return ServerPlayNetworkingImpl.canSend(player, channel); + public static boolean isPlayReady(ServerPlayerEntity player, NamespacedIdentifier channel) { + return ServerPlayNetworkingImpl.isPlayReady(player, channel); } /** * Send a packet to the given player through the given channel. The payload * will only be written if the channel is open. */ - public static void send(ServerPlayerEntity player, Identifier channel, CustomPayload payload) { + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, PacketPayload payload) { ServerPlayNetworkingImpl.send(player, channel, payload); } @@ -87,22 +96,29 @@ public static void send(ServerPlayerEntity player, Identifier channel, CustomPay * Send a packet to the given player through the given channel. The writer * will only be called if the channel is open. */ - public static void send(ServerPlayerEntity player, Identifier channel, IOConsumer writer) { + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, IOConsumer writer) { ServerPlayNetworkingImpl.send(player, channel, writer); } /** * Send a packet to the given player through the given channel. */ - public static void send(ServerPlayerEntity player, Identifier channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.send(player, channel, data); + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, PacketBuffer buffer) { + ServerPlayNetworkingImpl.send(player, channel, buffer); + } + + /** + * Send a packet to the given player through the given channel. + */ + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, byte[] bytes) { + ServerPlayNetworkingImpl.send(player, channel, bytes); } /** * Send a packet to the given players through the given channel. The payload * will only be written if the channel is open for at least one player. */ - public static void send(Iterable players, Identifier channel, CustomPayload payload) { + public static void send(Iterable players, NamespacedIdentifier channel, PacketPayload payload) { ServerPlayNetworkingImpl.send(players, channel, payload); } @@ -110,15 +126,22 @@ public static void send(Iterable players, Identifier channel * Send a packet to the given players through the given channel. The writer * will only be called if the channel is open for at least one player. */ - public static void send(Iterable players, Identifier channel, IOConsumer writer) { + public static void send(Iterable players, NamespacedIdentifier channel, IOConsumer writer) { ServerPlayNetworkingImpl.send(players, channel, writer); } /** * Send a packet to the given players through the given channel. */ - public static void send(Iterable players, Identifier channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.send(players, channel, data); + public static void send(Iterable players, NamespacedIdentifier channel, PacketBuffer buffer) { + ServerPlayNetworkingImpl.send(players, channel, buffer); + } + + /** + * Send a packet to the given players through the given channel. + */ + public static void send(Iterable players, NamespacedIdentifier channel, byte[] bytes) { + ServerPlayNetworkingImpl.send(players, channel, bytes); } /** @@ -126,7 +149,7 @@ public static void send(Iterable players, Identifier channel * channel. The payload will only be written if the channel is open for at * least one player. */ - public static void send(DimensionType dimension, Identifier channel, CustomPayload payload) { + public static void send(DimensionType dimension, NamespacedIdentifier channel, PacketPayload payload) { ServerPlayNetworkingImpl.send(dimension, channel, payload); } @@ -135,7 +158,7 @@ public static void send(DimensionType dimension, Identifier channel, CustomPaylo * channel. The writer will only be called if the channel is open for at * least one player. */ - public static void send(DimensionType dimension, Identifier channel, IOConsumer writer) { + public static void send(DimensionType dimension, NamespacedIdentifier channel, IOConsumer writer) { ServerPlayNetworkingImpl.send(dimension, channel, writer); } @@ -143,15 +166,23 @@ public static void send(DimensionType dimension, Identifier channel, IOConsumer< * Send a packet to the players in the given dimension through the given * channel. */ - public static void send(DimensionType dimension, Identifier channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.send(dimension, channel, data); + public static void send(DimensionType dimension, NamespacedIdentifier channel, PacketBuffer buffer) { + ServerPlayNetworkingImpl.send(dimension, channel, buffer); + } + + /** + * Send a packet to the players in the given dimension through the given + * channel. + */ + public static void send(DimensionType dimension, NamespacedIdentifier channel, byte[] bytes) { + ServerPlayNetworkingImpl.send(dimension, channel, bytes); } /** * Send a packet to all players through the given channel. The payload will * only be written if the channel is open for at least one player. */ - public static void send(Identifier channel, CustomPayload payload) { + public static void send(NamespacedIdentifier channel, PacketPayload payload) { ServerPlayNetworkingImpl.send(channel, payload); } @@ -159,15 +190,22 @@ public static void send(Identifier channel, CustomPayload payload) { * Send a packet to all players through the given channel. The writer will * only be called if the channel is open for at least one player. */ - public static void send(Identifier channel, IOConsumer writer) { + public static void send(NamespacedIdentifier channel, IOConsumer writer) { ServerPlayNetworkingImpl.send(channel, writer); } /** * Send a packet to all players through the given channel. */ - public static void send(Identifier channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.send(channel, data); + public static void send(NamespacedIdentifier channel, PacketBuffer buffer) { + ServerPlayNetworkingImpl.send(channel, buffer); + } + + /** + * Send a packet to all players through the given channel. + */ + public static void send(NamespacedIdentifier channel, byte[] bytes) { + ServerPlayNetworkingImpl.send(channel, bytes); } /** @@ -176,8 +214,8 @@ public static void send(Identifier channel, PacketByteBuf data) { * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(ServerPlayerEntity player, Identifier channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(player, channel, payload); + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, PacketPayload payload) { + ServerPlayNetworkingImpl.sendNoCheck(player, channel, payload); } /** @@ -186,8 +224,8 @@ public static void doSend(ServerPlayerEntity player, Identifier channel, CustomP * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(ServerPlayerEntity player, Identifier channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(player, channel, writer); + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, IOConsumer writer) { + ServerPlayNetworkingImpl.sendNoCheck(player, channel, writer); } /** @@ -196,8 +234,28 @@ public static void doSend(ServerPlayerEntity player, Identifier channel, IOConsu * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(ServerPlayerEntity player, Identifier channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.doSend(player, channel, data); + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, PacketBuffer buffer) { + ServerPlayNetworkingImpl.sendNoCheck(player, channel, buffer); + } + + /** + * Send a packet to the given player through the given channel, without + * checking whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the client. + */ + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, byte[] bytes) { + ServerPlayNetworkingImpl.sendNoCheck(player, channel, bytes); + } + + /** + * Send a packet to the given players through the given channel, without + * checking whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the client. + */ + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, PacketPayload payload) { + ServerPlayNetworkingImpl.sendNoCheck(players, channel, payload); } /** @@ -206,8 +264,8 @@ public static void doSend(ServerPlayerEntity player, Identifier channel, PacketB * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(Iterable players, Identifier channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(players, channel, payload); + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, IOConsumer writer) { + ServerPlayNetworkingImpl.sendNoCheck(players, channel, writer); } /** @@ -216,8 +274,8 @@ public static void doSend(Iterable players, Identifier chann * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(Iterable players, Identifier channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(players, channel, writer); + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, PacketBuffer buffer) { + ServerPlayNetworkingImpl.sendNoCheck(players, channel, buffer); } /** @@ -226,8 +284,8 @@ public static void doSend(Iterable players, Identifier chann * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(Iterable players, Identifier channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.doSend(players, channel, data); + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, byte[] bytes) { + ServerPlayNetworkingImpl.sendNoCheck(players, channel, bytes); } /** @@ -236,8 +294,8 @@ public static void doSend(Iterable players, Identifier chann * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(DimensionType dimension, Identifier channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(dimension, channel, payload); + public static void sendNoCheck(DimensionType dimension, NamespacedIdentifier channel, PacketPayload payload) { + ServerPlayNetworkingImpl.sendNoCheck(dimension, channel, payload); } /** @@ -246,8 +304,8 @@ public static void doSend(DimensionType dimension, Identifier channel, CustomPay * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(DimensionType dimension, Identifier channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(dimension, channel, writer); + public static void sendNoCheck(DimensionType dimension, NamespacedIdentifier channel, IOConsumer writer) { + ServerPlayNetworkingImpl.sendNoCheck(dimension, channel, writer); } /** @@ -256,18 +314,18 @@ public static void doSend(DimensionType dimension, Identifier channel, IOConsume * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(DimensionType dimension, Identifier channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.doSend(dimension, channel, data); + public static void sendNoCheck(DimensionType dimension, NamespacedIdentifier channel, PacketBuffer buffer) { + ServerPlayNetworkingImpl.sendNoCheck(dimension, channel, buffer); } /** - * Send a packet to all players through the given channel, without - * checking whether it is open. + * Send a packet to the players in the given dimension through the given + * channel, without checking whether it is open. * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(Identifier channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(channel, payload); + public static void sendNoCheck(DimensionType dimension, NamespacedIdentifier channel, byte[] bytes) { + ServerPlayNetworkingImpl.sendNoCheck(dimension, channel, bytes); } /** @@ -276,8 +334,8 @@ public static void doSend(Identifier channel, CustomPayload payload) { * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(Identifier channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(channel, writer); + public static void sendNoCheck(NamespacedIdentifier channel, PacketPayload payload) { + ServerPlayNetworkingImpl.sendNoCheck(channel, payload); } /** @@ -286,33 +344,27 @@ public static void doSend(Identifier channel, IOConsumer writer) * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(Identifier channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.doSend(channel, data); + public static void sendNoCheck(NamespacedIdentifier channel, IOConsumer writer) { + ServerPlayNetworkingImpl.sendNoCheck(channel, writer); } - public interface PayloadListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, T payload) throws IOException; - + /** + * Send a packet to all players through the given channel, without + * checking whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the client. + */ + public static void sendNoCheck(NamespacedIdentifier channel, PacketBuffer buffer) { + ServerPlayNetworkingImpl.sendNoCheck(channel, buffer); } - public interface ByteBufListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, PacketByteBuf data) throws IOException; - + /** + * Send a packet to all players through the given channel, without + * checking whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the client. + */ + public static void sendNoCheck(NamespacedIdentifier channel, byte[] bytes) { + ServerPlayNetworkingImpl.sendNoCheck(channel, bytes); } } diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java index 7ef2cb48..27d46bc9 100644 --- a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java +++ b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java @@ -4,52 +4,58 @@ import java.util.LinkedHashSet; import java.util.Set; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.resource.Identifier; - -import net.ornithemc.osl.networking.api.CustomPayload; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.api.ChannelIdentifiers; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketPayload; import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; -public class HandshakePayload implements CustomPayload { +public class HandshakePayload implements PacketPayload { - public static final Identifier CHANNEL = new Identifier("osl", "handshake"); + public static final NamespacedIdentifier CHANNEL = Constants.OSL_HANDSHAKE_CHANNEL; - public Set channels; + public byte protocol; + public Set channels; public HandshakePayload() { } - public HandshakePayload(Set channels) { - this.channels = channels; + public HandshakePayload(Set channels) { + this.protocol = Constants.OSL_HANDSHAKE_PROTOCOL; + // we allow registering listeners on channels that do not conform to OSL spec + // but payloads sent over these channels aren't sent via OSL so we can ignore + // them for the OSL handshake. + this.channels = ChannelIdentifiers.dropInvalid(channels); } public static HandshakePayload client() { - return new HandshakePayload(ClientPlayNetworkingImpl.LISTENERS.keySet()); + return new HandshakePayload(ClientPlayNetworkingImpl.CHANNEL_LISTENERS.keySet()); } public static HandshakePayload server() { - return new HandshakePayload(ServerPlayNetworkingImpl.LISTENERS.keySet()); + return new HandshakePayload(ServerPlayNetworkingImpl.CHANNEL_LISTENERS.keySet()); } @Override - public void read(PacketByteBuf buffer) throws IOException { + public void read(PacketBuffer buffer) throws IOException { + protocol = buffer.readByte(); channels = new LinkedHashSet<>(); + int channelCount = buffer.readInt(); - if (channelCount > 0) { - for (int i = 0; i < channelCount; i++) { - channels.add(buffer.readIdentifier()); - } + for (int i = 0; i < channelCount; i++) { + channels.add(buffer.readNamespacedIdentifier()); } } @Override - public void write(PacketByteBuf buffer) throws IOException { + public void write(PacketBuffer buffer) throws IOException { + buffer.writeByte(protocol); buffer.writeInt(channels.size()); - for (Identifier channel : channels) { - buffer.writeIdentifier(channel); + for (NamespacedIdentifier channel : channels) { + buffer.writeNamespacedIdentifier(channel); } } } diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/NetworkListener.java b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/NetworkListener.java deleted file mode 100644 index 7e34822c..00000000 --- a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/NetworkListener.java +++ /dev/null @@ -1,20 +0,0 @@ -package net.ornithemc.osl.networking.impl; - -public class NetworkListener { - - private final T listener; - private final boolean async; - - public NetworkListener(T listener, boolean async) { - this.listener = listener; - this.async = async; - } - - public T get() { - return listener; - } - - public boolean isAsync() { - return async; - } -} diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/Networking.java deleted file mode 100644 index 601d2f5d..00000000 --- a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/Networking.java +++ /dev/null @@ -1,57 +0,0 @@ -package net.ornithemc.osl.networking.impl; - -import net.ornithemc.osl.entrypoints.api.ModInitializer; -import net.ornithemc.osl.entrypoints.api.client.ClientModInitializer; -import net.ornithemc.osl.entrypoints.api.server.ServerModInitializer; -import net.ornithemc.osl.lifecycle.api.client.MinecraftClientEvents; -import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; -import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking; -import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking; -import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -public class Networking implements ModInitializer, ClientModInitializer, ServerModInitializer { - - @Override - public void init() { - MinecraftServerEvents.START.register(server -> { - ServerPlayNetworkingImpl.setUp(server); - }); - MinecraftServerEvents.STOP.register(server -> { - ServerPlayNetworkingImpl.destroy(server); - }); - ServerPlayNetworking.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { - // send channel registration data as a response to receiving client channel registration data - ServerPlayNetworkingImpl.doSend(player, HandshakePayload.CHANNEL, HandshakePayload.server()); - - ((INetworkHandler)handler).osl$networking$registerChannels(payload.channels); - ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); - - return true; - }); - } - - @Override - public void initClient() { - MinecraftClientEvents.START.register(minecraft -> { - ClientPlayNetworkingImpl.setUp(minecraft); - }); - MinecraftClientEvents.STOP.register(minecraft -> { - ClientPlayNetworkingImpl.destroy(minecraft); - }); - ClientPlayNetworking.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { - ((INetworkHandler)handler).osl$networking$registerChannels(payload.channels); - ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); - - return true; - }); - } - - @Override - public void initServer() { - // empty impl - } -} diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/PacketFactory.java b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/PacketFactory.java new file mode 100644 index 00000000..f2fe74a6 --- /dev/null +++ b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/PacketFactory.java @@ -0,0 +1,13 @@ +package net.ornithemc.osl.networking.impl; + +import net.minecraft.network.packet.Packet; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.api.PacketBuffer; + +@FunctionalInterface +public interface PacketFactory { + + Packet create(NamespacedIdentifier channel, PacketBuffer data); + +} diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/access/CustomPayloadPacketAccess.java b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/access/CustomPayloadPacketAccess.java new file mode 100644 index 00000000..3241aa75 --- /dev/null +++ b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/access/CustomPayloadPacketAccess.java @@ -0,0 +1,12 @@ +package net.ornithemc.osl.networking.impl.access; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.api.PacketBuffer; + +public interface CustomPayloadPacketAccess { + + NamespacedIdentifier osl$networking$getChannel(); + + PacketBuffer osl$networking$getData(); + +} diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/access/NetworkHandlerAccess.java b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/access/NetworkHandlerAccess.java new file mode 100644 index 00000000..d3e3c4e0 --- /dev/null +++ b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/access/NetworkHandlerAccess.java @@ -0,0 +1,15 @@ +package net.ornithemc.osl.networking.impl.access; + +import java.util.Set; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; + +public interface NetworkHandlerAccess { + + boolean osl$networking$isPlayReady(); + + boolean osl$networking$isPlayReady(NamespacedIdentifier channel); + + void osl$networking$registerChannels(Set channels); + +} diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/access/PlayerManagerAccess.java b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/access/PlayerManagerAccess.java new file mode 100644 index 00000000..6fc92ae4 --- /dev/null +++ b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/access/PlayerManagerAccess.java @@ -0,0 +1,11 @@ +package net.ornithemc.osl.networking.impl.access; + +import java.util.List; + +import net.minecraft.server.entity.living.player.ServerPlayerEntity; + +public interface PlayerManagerAccess { + + List osl$networking$getAll(); + +} diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/access/TaskRunnerAccess.java b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/access/TaskRunnerAccess.java new file mode 100644 index 00000000..bff1ba39 --- /dev/null +++ b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/access/TaskRunnerAccess.java @@ -0,0 +1,7 @@ +package net.ornithemc.osl.networking.impl.access; + +public interface TaskRunnerAccess { + + boolean osl$networking$submit(Runnable task); + +} diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java index 5faf509d..84d48a2c 100644 --- a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java +++ b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java @@ -10,174 +10,256 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.network.handler.ClientPlayNetworkHandler; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.network.PacketUtils; import net.minecraft.network.packet.Packet; -import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; -import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; -import net.minecraft.resource.Identifier; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.api.PacketByteBufs; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.ByteBufListener; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.PayloadListener; -import net.ornithemc.osl.networking.impl.NetworkListener; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketBuffers; +import net.ornithemc.osl.networking.api.PacketPayload; +import net.ornithemc.osl.networking.api.client.ClientPacketListener; +import net.ornithemc.osl.networking.impl.PacketFactory; +import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; +import net.ornithemc.osl.networking.impl.access.TaskRunnerAccess; public final class ClientPlayNetworkingImpl { private static final Logger LOGGER = LogManager.getLogger("OSL|Client Play Networking"); + private static PacketFactory packetFactory; private static Minecraft minecraft; + private static Thread thread; + + public static void setUpPacketFactory(PacketFactory factory) { + if (ClientPlayNetworkingImpl.packetFactory != null) { + throw new IllegalStateException("tried to set up client custom payload packet factory when it was already set up!"); + } + + ClientPlayNetworkingImpl.packetFactory = factory; + } public static void setUp(Minecraft minecraft) { if (ClientPlayNetworkingImpl.minecraft == minecraft) { - throw new IllegalStateException("tried to set up client networking when it was already set up!"); + throw new IllegalStateException("tried to set up client play networking when it was already set up!"); + } + if (ClientPlayNetworkingImpl.packetFactory == null) { + throw new IllegalStateException("tried to set up client play networking when no custom payload packet factory was set up!"); } ClientPlayNetworkingImpl.minecraft = minecraft; + ClientPlayNetworkingImpl.thread = Thread.currentThread(); } public static void destroy(Minecraft minecraft) { if (ClientPlayNetworkingImpl.minecraft != minecraft) { - throw new IllegalStateException("tried to destroy client networking when it was not set up!"); + throw new IllegalStateException("tried to destroy client play networking when it was not set up!"); } ClientPlayNetworkingImpl.minecraft = null; + ClientPlayNetworkingImpl.thread = null; } - public static final Map> LISTENERS = new LinkedHashMap<>(); + public static final Map CHANNEL_LISTENERS = new LinkedHashMap<>(); - public static void registerListener(Identifier channel, Supplier initializer, PayloadListener listener) { + public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { registerListener(channel, initializer, listener, false); } - public static void registerListenerAsync(Identifier channel, Supplier initializer, PayloadListener listener) { + public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { registerListener(channel, initializer, listener, true); } - private static void registerListener(Identifier channel, Supplier initializer, PayloadListener listener, boolean async) { - registerListenerImpl(channel, (minecraft, handler, data) -> { - T payload = initializer.get(); - payload.read(data); + private static void registerListener(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener, boolean async) { + registerListenerImpl(channel, new ChannelListener() { + + @Override + public boolean isAsync() { + return async; + } + + @Override + public boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, PacketBuffer buffer) throws IOException { + T payload = initializer.get(); + payload.read(buffer); + + return listener.handle(minecraft, handler, payload); + } + }); + } + + public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { + registerListener(channel, listener, false); + } + + public static void registerListenerAsync(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { + registerListener(channel, listener, true); + } + + private static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Buffer listener, boolean async) { + registerListenerImpl(channel, new ChannelListener() { + + @Override + public boolean isAsync() { + return async; + } - return listener.handle(minecraft, handler, payload); - }, async); + @Override + public boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, PacketBuffer buffer) throws IOException { + return listener.handle(minecraft, handler, buffer); + } + }); } - public static void registerListener(Identifier channel, ByteBufListener listener) { + public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { registerListener(channel, listener, false); } - public static void registerListenerAsync(Identifier channel, ByteBufListener listener) { + public static void registerListenerAsync(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { registerListener(channel, listener, true); } - private static void registerListener(Identifier channel, ByteBufListener listener, boolean async) { - registerListenerImpl(channel, listener::handle, async); + private static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Bytes listener, boolean async) { + registerListenerImpl(channel, new ChannelListener() { + + @Override + public boolean isAsync() { + return async; + } + + @Override + public boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, PacketBuffer buffer) throws IOException { + return listener.handle(minecraft, handler, buffer.readByteArray()); + } + }); } - private static void registerListenerImpl(Identifier channel, Listener listener, boolean async) { - LISTENERS.compute(channel, (key, value) -> { + private static void registerListenerImpl(NamespacedIdentifier channel, ChannelListener listener) { + CHANNEL_LISTENERS.compute(channel, (key, value) -> { if (value != null) { throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); } - return new NetworkListener<>(listener, async); + return listener; }); } - public static void unregisterListener(Identifier channel) { - LISTENERS.remove(channel); + public static void unregisterListener(NamespacedIdentifier channel) { + CHANNEL_LISTENERS.remove(channel); } - public static boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, CustomPayloadS2CPacket packet) { - Identifier channel = packet.getChannel(); - NetworkListener listener = LISTENERS.get(channel); + public static boolean handlePacket(Minecraft minecraft, ClientPlayNetworkHandler handler, Packet packet) { + CustomPayloadPacketAccess p = (CustomPayloadPacketAccess)packet; + + NamespacedIdentifier channel = p.osl$networking$getChannel(); + ChannelListener listener = CHANNEL_LISTENERS.get(channel); if (listener != null) { - if (!listener.isAsync()) { - PacketUtils.ensureOnSameThread(packet, handler, minecraft); - } + PacketBuffer data = p.osl$networking$getData(); - try { - return listener.get().handle(minecraft, handler, packet.getData()); - } catch (IOException e) { - LOGGER.warn("error handling custom payload on channel \'" + channel + "\'", e); - return true; + if (Thread.currentThread() == thread || listener.isAsync()) { + return handlePayload(minecraft, handler, listener, channel, data); + } else { + return ((TaskRunnerAccess) minecraft).osl$networking$submit(() -> handlePayload(minecraft, handler, listener, channel, data)); } } return false; } + private static boolean handlePayload(Minecraft minecraft, ClientPlayNetworkHandler handler, ChannelListener listener, NamespacedIdentifier channel, PacketBuffer data) { + try { + return listener.handle(minecraft, handler, data); + } catch (IOException e) { + LOGGER.warn("error handling custom payload on channel \'" + channel + "\'", e); + } + + return true; + } + public static boolean isPlayReady() { - INetworkHandler handler = (INetworkHandler)minecraft.getNetworkHandler(); + NetworkHandlerAccess handler = (NetworkHandlerAccess)minecraft.getNetworkHandler(); return handler != null && handler.osl$networking$isPlayReady(); } - public static boolean canSend(Identifier channel) { - INetworkHandler handler = (INetworkHandler)minecraft.getNetworkHandler(); - return handler != null && handler.osl$networking$isRegisteredChannel(channel); + public static boolean isPlayReady(NamespacedIdentifier channel) { + NetworkHandlerAccess handler = (NetworkHandlerAccess)minecraft.getNetworkHandler(); + return handler != null && handler.osl$networking$isPlayReady(channel); } - public static void send(Identifier channel, CustomPayload payload) { - if (canSend(channel)) { - doSend(channel, payload); + public static void send(NamespacedIdentifier channel, PacketPayload payload) { + if (isPlayReady(channel)) { + sendInternal(channel, payload); } } - public static void send(Identifier channel, IOConsumer writer) { - if (canSend(channel)) { - doSend(channel, writer); + public static void send(NamespacedIdentifier channel, IOConsumer writer) { + if (isPlayReady(channel)) { + sendInternal(channel, writer); } } - public static void send(Identifier channel, PacketByteBuf data) { - if (canSend(channel)) { - doSend(channel, data); + public static void send(NamespacedIdentifier channel, PacketBuffer buffer) { + if (isPlayReady(channel)) { + sendInternal(channel, buffer); } } - public static void doSend(Identifier channel, CustomPayload payload) { - sendPacket(makePacket(channel, payload)); + public static void send(NamespacedIdentifier channel, byte[] bytes) { + if (isPlayReady(channel)) { + sendInternal(channel, bytes); + } + } + + public static void sendNoCheck(NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(channel, payload); } - public static void doSend(Identifier channel, IOConsumer writer) { - sendPacket(makePacket(channel, writer)); + public static void sendNoCheck(NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(channel, writer); } - public static void doSend(Identifier channel, PacketByteBuf data) { - sendPacket(makePacket(channel, data)); + public static void sendNoCheck(NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(channel, buffer); } - private static Packet makePacket(Identifier channel, CustomPayload payload) { - return makePacket(channel, payload::write); + public static void sendNoCheck(NamespacedIdentifier channel, byte[] bytes) { + sendInternal(channel, bytes); + } + + private static void sendInternal(NamespacedIdentifier channel, PacketPayload payload) { + try { + sendPacket(channel, PacketBuffers.make(payload::write)); + } catch (IOException e) { + LOGGER.warn("error writing packet payload to channel \'" + channel + "\'", e); + } } - private static Packet makePacket(Identifier channel, IOConsumer writer) { + private static void sendInternal(NamespacedIdentifier channel, IOConsumer writer) { try { - return new CustomPayloadC2SPacket(channel, PacketByteBufs.make(writer)); + sendPacket(channel, PacketBuffers.make(writer)); } catch (IOException e) { - LOGGER.warn("error writing custom payload to channel \'" + channel + "\'", e); - return null; + LOGGER.warn("error writing buffer to channel \'" + channel + "\'", e); } } - private static Packet makePacket(Identifier channel, PacketByteBuf data) { - return new CustomPayloadC2SPacket(channel, data); + private static void sendInternal(NamespacedIdentifier channel, PacketBuffer buffer) { + sendPacket(channel, buffer); } - private static void sendPacket(Packet packet) { - if (packet != null) { - minecraft.getNetworkHandler().sendPacket(packet); - } + private static void sendInternal(NamespacedIdentifier channel, byte[] bytes) { + sendPacket(channel, PacketBuffers.wrap(bytes)); } - private interface Listener { + private static void sendPacket(NamespacedIdentifier channel, PacketBuffer data) { + minecraft.getNetworkHandler().sendPacket(packetFactory.create(channel, data)); + } + + private interface ChannelListener { + + boolean isAsync(); - boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, PacketByteBuf data) throws IOException; + boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, PacketBuffer buffer) throws IOException; } } diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/ICustomPayloadPacket.java b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/ICustomPayloadPacket.java deleted file mode 100644 index e4a813f5..00000000 --- a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/ICustomPayloadPacket.java +++ /dev/null @@ -1,12 +0,0 @@ -package net.ornithemc.osl.networking.impl.interfaces.mixin; - -import net.minecraft.network.PacketByteBuf; -import net.minecraft.resource.Identifier; - -public interface ICustomPayloadPacket { - - Identifier osl$networking$getChannel(); - - PacketByteBuf osl$networking$getData(); - -} diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java deleted file mode 100644 index e06f34db..00000000 --- a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java +++ /dev/null @@ -1,15 +0,0 @@ -package net.ornithemc.osl.networking.impl.interfaces.mixin; - -import java.util.Set; - -import net.minecraft.resource.Identifier; - -public interface INetworkHandler { - - boolean osl$networking$isPlayReady(); - - void osl$networking$registerChannels(Set channels); - - boolean osl$networking$isRegisteredChannel(Identifier channel); - -} diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java deleted file mode 100644 index 54cf473b..00000000 --- a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/ClientPlayNetworkHandlerMixin.java +++ /dev/null @@ -1,85 +0,0 @@ -package net.ornithemc.osl.networking.impl.mixin.client; - -import java.util.LinkedHashSet; -import java.util.Set; - -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.network.handler.ClientPlayNetworkHandler; -import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; -import net.minecraft.resource.Identifier; - -import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; -import net.ornithemc.osl.networking.impl.HandshakePayload; -import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; - -@Mixin(ClientPlayNetworkHandler.class) -public class ClientPlayNetworkHandlerMixin implements INetworkHandler { - - @Shadow @Final private Minecraft minecraft; - - /** - * Channels that the server is listening to. - */ - @Unique private Set serverChannels; - - @Inject( - method = "handleLogin", - at = @At( - value = "TAIL" - ) - ) - private void osl$networking$handleLogin(CallbackInfo ci) { - // send channel registration data as soon as login occurs - ClientPlayNetworkingImpl.doSend(HandshakePayload.CHANNEL, HandshakePayload.client()); - - ClientConnectionEvents.LOGIN.invoker().accept(minecraft); - } - - @Inject( - method = "onDisconnect", - at = @At( - value = "HEAD" - ) - ) - private void osl$networking$handleDisconnect(CallbackInfo ci) { - ClientConnectionEvents.DISCONNECT.invoker().accept(minecraft); - serverChannels = null; - } - - @Inject( - method = "handleCustomPayload", - cancellable = true, - at = @At( - value = "HEAD" - ) - ) - private void osl$networking$handleCustomPayload(CustomPayloadS2CPacket packet, CallbackInfo ci) { - if (ClientPlayNetworkingImpl.handle(minecraft, (ClientPlayNetworkHandler)(Object)this, packet)) { - ci.cancel(); - } - } - - @Override - public boolean osl$networking$isPlayReady() { - return serverChannels != null; - } - - @Override - public void osl$networking$registerChannels(Set channels) { - serverChannels = new LinkedHashSet<>(channels); - } - - @Override - public boolean osl$networking$isRegisteredChannel(Identifier channel) { - return serverChannels != null && serverChannels.contains(channel); - } -} diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java deleted file mode 100644 index 5719c0a7..00000000 --- a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/CustomPayloadC2SPacketMixin.java +++ /dev/null @@ -1,27 +0,0 @@ -package net.ornithemc.osl.networking.impl.mixin.common; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; - -import net.minecraft.network.PacketByteBuf; -import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; -import net.minecraft.resource.Identifier; - -import net.ornithemc.osl.networking.impl.interfaces.mixin.ICustomPayloadPacket; - -@Mixin(CustomPayloadC2SPacket.class) -public class CustomPayloadC2SPacketMixin implements ICustomPayloadPacket { - - @Shadow private Identifier channel; - @Shadow private PacketByteBuf data; - - @Override - public Identifier osl$networking$getChannel() { - return channel; - } - - @Override - public PacketByteBuf osl$networking$getData() { - return data; - } -} diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java deleted file mode 100644 index ffa9c8d3..00000000 --- a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/ServerPlayNetworkHandlerMixin.java +++ /dev/null @@ -1,73 +0,0 @@ -package net.ornithemc.osl.networking.impl.mixin.common; - -import java.util.LinkedHashSet; -import java.util.Set; - -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; -import net.minecraft.resource.Identifier; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.entity.living.player.ServerPlayerEntity; -import net.minecraft.server.network.handler.ServerPlayNetworkHandler; - -import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -@Mixin(ServerPlayNetworkHandler.class) -public class ServerPlayNetworkHandlerMixin implements INetworkHandler { - - @Shadow @Final private MinecraftServer server; - @Shadow @Final private ServerPlayerEntity player; - - /** - * Channels that the client is listening to. - */ - @Unique private Set clientChannels; - - @Inject( - method = "onDisconnect", - at = @At( - value = "HEAD" - ) - ) - private void osl$networking$handleDisconnect(CallbackInfo ci) { - ServerConnectionEvents.DISCONNECT.invoker().accept(server, player); - clientChannels = null; - } - - @Inject( - method = "handleCustomPayload", - cancellable = true, - at = @At( - value = "HEAD" - ) - ) - private void osl$networking$handleCustomPayload(CustomPayloadC2SPacket packet, CallbackInfo ci) { - if (ServerPlayNetworkingImpl.handle(server, (ServerPlayNetworkHandler)(Object)this, player, packet)) { - ci.cancel(); - } - } - - @Override - public boolean osl$networking$isPlayReady() { - return clientChannels != null; - } - - @Override - public void osl$networking$registerChannels(Set channels) { - clientChannels = new LinkedHashSet<>(channels); - } - - @Override - public boolean osl$networking$isRegisteredChannel(Identifier channel) { - return clientChannels != null && clientChannels.contains(channel); - } -} diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java index d7ff0a5c..b76d268f 100644 --- a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java +++ b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java @@ -11,229 +11,377 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.network.PacketUtils; import net.minecraft.network.packet.Packet; -import net.minecraft.network.packet.c2s.play.CustomPayloadC2SPacket; -import net.minecraft.network.packet.s2c.play.CustomPayloadS2CPacket; -import net.minecraft.resource.Identifier; import net.minecraft.server.MinecraftServer; import net.minecraft.server.entity.living.player.ServerPlayerEntity; import net.minecraft.server.network.handler.ServerPlayNetworkHandler; import net.minecraft.world.dimension.DimensionType; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.api.PacketByteBufs; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.ByteBufListener; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.PayloadListener; -import net.ornithemc.osl.networking.impl.NetworkListener; -import net.ornithemc.osl.networking.impl.interfaces.mixin.ICustomPayloadPacket; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketBuffers; +import net.ornithemc.osl.networking.api.PacketPayload; +import net.ornithemc.osl.networking.api.server.ServerPacketListener; +import net.ornithemc.osl.networking.impl.PacketFactory; +import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; +import net.ornithemc.osl.networking.impl.access.TaskRunnerAccess; public final class ServerPlayNetworkingImpl { private static final Logger LOGGER = LogManager.getLogger("OSL|Server Play Networking"); + private static PacketFactory packetFactory; private static MinecraftServer server; + private static Thread thread; + + public static void setUpPacketFactory(PacketFactory factory) { + if (ServerPlayNetworkingImpl.packetFactory != null) { + throw new IllegalStateException("tried to set up server custom payload packet factory when it was already set up!"); + } + + ServerPlayNetworkingImpl.packetFactory = factory; + } public static void setUp(MinecraftServer server) { if (ServerPlayNetworkingImpl.server == server) { - throw new IllegalStateException("tried to set up server networking when it was already set up!"); + throw new IllegalStateException("tried to set up server play networking when it was already set up!"); + } + if (ServerPlayNetworkingImpl.packetFactory == null) { + throw new IllegalStateException("tried to set up server play networking when no custom payload packet factory was set up!"); } ServerPlayNetworkingImpl.server = server; + ServerPlayNetworkingImpl.thread = Thread.currentThread(); } public static void destroy(MinecraftServer server) { if (ServerPlayNetworkingImpl.server != server) { - throw new IllegalStateException("tried to destroy server networking when it was not set up!"); + throw new IllegalStateException("tried to destroy server play networking when it was not set up!"); } ServerPlayNetworkingImpl.server = null; + ServerPlayNetworkingImpl.thread = null; } - public static final Map> LISTENERS = new LinkedHashMap<>(); + public static final Map CHANNEL_LISTENERS = new LinkedHashMap<>(); - public static void registerListener(Identifier channel, Supplier initializer, PayloadListener listener) { - registerListener(channel, initializer, listener, false); + public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { + ServerPlayNetworkingImpl.registerListener(channel, initializer, listener, false); } - public static void registerListenerAsync(Identifier channel, Supplier initializer, PayloadListener listener) { - registerListener(channel, initializer, listener, true); + public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { + ServerPlayNetworkingImpl.registerListener(channel, initializer, listener, true); + } + + private static void registerListener(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener, boolean async) { + registerListenerImpl(channel, new ChannelListener() { + + @Override + public boolean isAsync() { + return async; + } + + @Override + public boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, PacketBuffer buffer) throws IOException { + T payload = initializer.get(); + payload.read(buffer); + + return listener.handle(server, handler, player, payload); + } + }); } - private static void registerListener(Identifier channel, Supplier initializer, PayloadListener listener, boolean async) { - registerListenerImpl(channel, (server, handler, player, data) -> { - T payload = initializer.get(); - payload.read(data); + public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { + ServerPlayNetworkingImpl.registerListener(channel, listener, false); + } - return listener.handle(server, handler, player, payload); - }, async); + public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { + ServerPlayNetworkingImpl.registerListener(channel, listener, true); } - public static void registerListener(Identifier channel, ByteBufListener listener) { - registerListener(channel, listener, false); + private static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Buffer listener, boolean async) { + registerListenerImpl(channel, new ChannelListener() { + + @Override + public boolean isAsync() { + return async; + } + + @Override + public boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, PacketBuffer buffer) throws IOException { + return listener.handle(server, handler, player, buffer); + } + }); } - public static void registerListenerAsync(Identifier channel, ByteBufListener listener) { - registerListener(channel, listener, true); + public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { + ServerPlayNetworkingImpl.registerListener(channel, listener, false); } - private static void registerListener(Identifier channel, ByteBufListener listener, boolean async) { - registerListenerImpl(channel, listener::handle, async); + public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { + ServerPlayNetworkingImpl.registerListener(channel, listener, true); } - private static void registerListenerImpl(Identifier channel, Listener listener, boolean async) { - LISTENERS.compute(channel, (key, value) -> { + private static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener, boolean async) { + registerListenerImpl(channel, new ChannelListener() { + + @Override + public boolean isAsync() { + return async; + } + + @Override + public boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, PacketBuffer buffer) throws IOException { + return listener.handle(server, handler, player, buffer.readByteArray()); + } + }); + } + + private static void registerListenerImpl(NamespacedIdentifier channel, ChannelListener listener) { + CHANNEL_LISTENERS.compute(channel, (key, value) -> { if (value != null) { throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); } - return new NetworkListener<>(listener, async); + return listener; }); } - public static void unregisterListener(Identifier channel) { - LISTENERS.remove(channel); + public static void unregisterListener(NamespacedIdentifier channel) { + CHANNEL_LISTENERS.remove(channel); } - public static boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, CustomPayloadC2SPacket packet) { - ICustomPayloadPacket p = (ICustomPayloadPacket)packet; + public static boolean handlePacket(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, Packet packet) { + CustomPayloadPacketAccess p = (CustomPayloadPacketAccess)packet; - Identifier channel = p.osl$networking$getChannel(); - NetworkListener listener = LISTENERS.get(channel); + NamespacedIdentifier channel = p.osl$networking$getChannel(); + ChannelListener listener = CHANNEL_LISTENERS.get(channel); if (listener != null) { - if (!listener.isAsync()) { - PacketUtils.ensureOnSameThread(packet, handler, server); - } + PacketBuffer data = p.osl$networking$getData(); - try { - return listener.get().handle(server, handler, player, p.osl$networking$getData()); - } catch (IOException e) { - LOGGER.warn("error handling custom payload on channel \'" + channel + "\'", e); - return true; + if (Thread.currentThread() == thread || listener.isAsync()) { + return handlePayload(server, handler, player, listener, channel, data); + } else { + return ((TaskRunnerAccess) server).osl$networking$submit(() -> handlePayload(server, handler, player, listener, channel, data)); } } return false; } + private static boolean handlePayload(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, ChannelListener listener, NamespacedIdentifier channel, PacketBuffer data) { + try { + return listener.handle(server, handler, player, data); + } catch (IOException e) { + LOGGER.warn("error handling custom payload on channel \'" + channel + "\'", e); + } + + return true; + } + public static boolean isPlayReady(ServerPlayerEntity player) { - INetworkHandler handler = (INetworkHandler)player.networkHandler; + NetworkHandlerAccess handler = (NetworkHandlerAccess)player.networkHandler; return handler != null && handler.osl$networking$isPlayReady(); } - public static boolean canSend(ServerPlayerEntity player, Identifier channel) { - INetworkHandler handler = (INetworkHandler)player.networkHandler; - return handler != null && handler.osl$networking$isRegisteredChannel(channel); + public static boolean isPlayReady(ServerPlayerEntity player, NamespacedIdentifier channel) { + NetworkHandlerAccess handler = (NetworkHandlerAccess)player.networkHandler; + return handler != null && handler.osl$networking$isPlayReady(channel); } - public static void send(ServerPlayerEntity player, Identifier channel, CustomPayload payload) { - if (canSend(player, channel)) { - doSend(player, channel, payload); + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, PacketPayload payload) { + if (isPlayReady(player, channel)) { + sendInternal(player, channel, payload); } } - public static void send(ServerPlayerEntity player, Identifier channel, IOConsumer writer) { - if (canSend(player, channel)) { - doSend(player, channel, writer); + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, IOConsumer writer) { + if (isPlayReady(player, channel)) { + sendInternal(player, channel, writer); } } - public static void send(ServerPlayerEntity player, Identifier channel, PacketByteBuf data) { - if (canSend(player, channel)) { - doSend(player, channel, data); + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, PacketBuffer buffer) { + if (isPlayReady(player, channel)) { + sendInternal(player, channel, buffer); } } - public static void send(Iterable players, Identifier channel, CustomPayload payload) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, payload)); + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, byte[] bytes) { + if (isPlayReady(player, channel)) { + sendInternal(player, channel, bytes); + } + } + + public static void send(Iterable players, NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(collectPlayers(players, p -> isPlayReady(p, channel)), channel, payload); + } + + public static void send(Iterable players, NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(collectPlayers(players, p -> isPlayReady(p, channel)), channel, writer); + } + + public static void send(Iterable players, NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(collectPlayers(players, p -> isPlayReady(p, channel)), channel, buffer); + } + + public static void send(Iterable players, NamespacedIdentifier channel, byte[] bytes) { + sendInternal(collectPlayers(players, p -> isPlayReady(p, channel)), channel, bytes); + } + + public static void send(DimensionType dimension, NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(collectPlayers(p -> p.dimension == dimension && isPlayReady(p, channel)), channel, payload); + } + + public static void send(DimensionType dimension, NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(collectPlayers(p -> p.dimension == dimension && isPlayReady(p, channel)), channel, writer); } - public static void send(Iterable players, Identifier channel, IOConsumer writer) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, writer)); + public static void send(DimensionType dimension, NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(collectPlayers(p -> p.dimension == dimension && isPlayReady(p, channel)),channel, buffer); } - public static void send(Iterable players, Identifier channel, PacketByteBuf data) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, data)); + public static void send(DimensionType dimension, NamespacedIdentifier channel, byte[] bytes) { + sendInternal(collectPlayers(p -> p.dimension == dimension && isPlayReady(p, channel)),channel, bytes); } - public static void send(DimensionType dimension, Identifier channel, CustomPayload payload) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)), channel, payload); + public static void send(NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(collectPlayers(p -> isPlayReady(p, channel)), channel, payload); } - public static void send(DimensionType dimension, Identifier channel, IOConsumer writer) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)), channel, writer); + public static void send(NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(collectPlayers(p -> isPlayReady(p, channel)), channel, writer); } - public static void send(DimensionType dimension, Identifier channel, PacketByteBuf data) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)),channel, data); + public static void send(NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(collectPlayers(p -> isPlayReady(p, channel)), channel, buffer); } - public static void send(Identifier channel, CustomPayload payload) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, payload); + public static void send(NamespacedIdentifier channel, byte[] bytes) { + sendInternal(collectPlayers(p -> isPlayReady(p, channel)), channel, bytes); } - public static void send(Identifier channel, IOConsumer writer) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, writer); + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(player, channel, payload); } - public static void send(Identifier channel, PacketByteBuf data) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, data); + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(player, channel, writer); } - public static void doSend(ServerPlayerEntity player, Identifier channel, CustomPayload payload) { - sendPacket(player, makePacket(channel, payload)); + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(player, channel, buffer); } - public static void doSend(ServerPlayerEntity player, Identifier channel, IOConsumer writer) { - sendPacket(player, makePacket(channel, writer)); + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, byte[] bytes) { + sendInternal(player, channel, bytes); } - public static void doSend(ServerPlayerEntity player, Identifier channel, PacketByteBuf data) { - sendPacket(player, makePacket(channel, data)); + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(players, channel, payload); } - public static void doSend(Iterable players, Identifier channel, CustomPayload payload) { - sendPacket(players, makePacket(channel, payload)); + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(players, channel, writer); } - public static void doSend(Iterable players, Identifier channel, IOConsumer writer) { - sendPacket(players, makePacket(channel, writer)); + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(players, channel, buffer); } - public static void doSend(Iterable players, Identifier channel, PacketByteBuf data) { - sendPacket(players, makePacket(channel, data)); + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, byte[] bytes) { + sendInternal(players, channel, bytes); } - public static void doSend(DimensionType dimension, Identifier channel, CustomPayload payload) { - doSend(collectPlayers(p -> p.dimension == dimension), channel, payload); + public static void sendNoCheck(DimensionType dimension, NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(collectPlayers(p -> p.dimension == dimension), channel, payload); } - public static void doSend(DimensionType dimension, Identifier channel, IOConsumer writer) { - doSend(collectPlayers(p -> p.dimension == dimension), channel, writer); + public static void sendNoCheck(DimensionType dimension, NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(collectPlayers(p -> p.dimension == dimension), channel, writer); } - public static void doSend(DimensionType dimension, Identifier channel, PacketByteBuf data) { - doSend(collectPlayers(p -> p.dimension == dimension),channel, data); + public static void sendNoCheck(DimensionType dimension, NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(collectPlayers(p -> p.dimension == dimension),channel, buffer); } - public static void doSend(Identifier channel, CustomPayload payload) { - doSend(collectPlayers(p -> true), channel, payload); + public static void sendNoCheck(DimensionType dimension, NamespacedIdentifier channel, byte[] bytes) { + sendInternal(collectPlayers(p -> p.dimension == dimension),channel, bytes); } - public static void doSend(Identifier channel, IOConsumer writer) { - doSend(collectPlayers(p -> true), channel, writer); + public static void sendNoCheck(NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(allPlayers(), channel, payload); } - public static void doSend(Identifier channel, PacketByteBuf data) { - doSend(collectPlayers(p -> true), channel, data); + public static void sendNoCheck(NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(allPlayers(), channel, writer); + } + + public static void sendNoCheck(NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(allPlayers(), channel, buffer); + } + + public static void sendNoCheck(NamespacedIdentifier channel, byte[] bytes) { + sendInternal(allPlayers(), channel, bytes); + } + + private static void sendInternal(ServerPlayerEntity player, NamespacedIdentifier channel, PacketPayload payload) { + try { + sendPacket(player, channel, PacketBuffers.make(payload::write)); + } catch (IOException e) { + LOGGER.warn("error writing packet payload to channel \'" + channel + "\'", e); + } + } + + private static void sendInternal(ServerPlayerEntity player, NamespacedIdentifier channel, IOConsumer writer) { + try { + sendPacket(player, channel, PacketBuffers.make(writer)); + } catch (IOException e) { + LOGGER.warn("error writing buffer to channel \'" + channel + "\'", e); + } + } + + private static void sendInternal(ServerPlayerEntity player, NamespacedIdentifier channel, PacketBuffer buffer) { + sendPacket(player, channel, buffer); + } + + private static void sendInternal(ServerPlayerEntity player, NamespacedIdentifier channel, byte[] bytes) { + sendPacket(player, channel, PacketBuffers.wrap(bytes)); + } + + private static void sendInternal(Iterable players, NamespacedIdentifier channel, PacketPayload payload) { + try { + sendPacket(players, channel, PacketBuffers.make(payload::write)); + } catch (IOException e) { + LOGGER.warn("error writing packet payload to channel \'" + channel + "\'", e); + } + } + + private static void sendInternal(Iterable players, NamespacedIdentifier channel, IOConsumer writer) { + try { + sendPacket(players, channel, PacketBuffers.make(writer)); + } catch (IOException e) { + LOGGER.warn("error writing buffer to channel \'" + channel + "\'", e); + } + } + + private static void sendInternal(Iterable players, NamespacedIdentifier channel, PacketBuffer buffer) { + sendPacket(players, channel, buffer); + } + + private static void sendInternal(Iterable players, NamespacedIdentifier channel, byte[] bytes) { + sendPacket(players, channel, PacketBuffers.wrap(bytes)); + } + + private static Iterable allPlayers() { + return server.getPlayerManager().getAll(); } private static Iterable collectPlayers(Predicate filter) { - return collectPlayers(server.getPlayerManager().getAll(), filter); + return collectPlayers(allPlayers(), filter); } private static Iterable collectPlayers(Iterable src, Predicate filter) { @@ -248,40 +396,23 @@ private static Iterable collectPlayers(Iterable makePacket(Identifier channel, CustomPayload payload) { - return makePacket(channel, payload::write); - } - - private static Packet makePacket(Identifier channel, IOConsumer writer) { - try { - return new CustomPayloadS2CPacket(channel, PacketByteBufs.make(writer)); - } catch (IOException e) { - LOGGER.warn("error writing custom payload to channel \'" + channel + "\'", e); - return null; - } + private static void sendPacket(ServerPlayerEntity player, NamespacedIdentifier channel, PacketBuffer data) { + player.networkHandler.sendPacket(packetFactory.create(channel, data)); } - private static Packet makePacket(Identifier channel, PacketByteBuf data) { - return new CustomPayloadS2CPacket(channel, data); - } + private static void sendPacket(Iterable players, NamespacedIdentifier channel, PacketBuffer data) { + Packet packet = packetFactory.create(channel, data); - private static void sendPacket(ServerPlayerEntity player, Packet packet) { - if (packet != null) { + for (ServerPlayerEntity player : players) { player.networkHandler.sendPacket(packet); } } - private static void sendPacket(Iterable players, Packet packet) { - if (packet != null) { - for (ServerPlayerEntity player : players) { - sendPacket(player, packet); - } - } - } + private interface ChannelListener { - private interface Listener { + boolean isAsync(); - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, PacketByteBuf data) throws IOException; + boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, PacketBuffer buffer) throws IOException; } } diff --git a/libraries/networking/networking-mca1.0.16-mca1.2.6/build.gradle b/libraries/networking/networking-mca1.0.16-mca1.2.6/build.gradle index f7548915..a13b6e9a 100644 --- a/libraries/networking/networking-mca1.0.16-mca1.2.6/build.gradle +++ b/libraries/networking/networking-mca1.0.16-mca1.2.6/build.gradle @@ -1,4 +1,4 @@ setUpModule(project, 'entrypoints-mcin-20091223-1459-mc1.5.2', - 'lifecycle-events-mcb1.4-1507-mcb1.7.3' + 'lifecycle-events-mcinf-20100630-1340-mca1.2.6' ) diff --git a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java deleted file mode 100644 index 237d7e67..00000000 --- a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java +++ /dev/null @@ -1,13 +0,0 @@ -package net.ornithemc.osl.networking.api; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; - -public interface CustomPayload { - - void read(DataInputStream input) throws IOException; - - void write(DataOutputStream output) throws IOException; - -} diff --git a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java deleted file mode 100644 index f68e894c..00000000 --- a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java +++ /dev/null @@ -1,23 +0,0 @@ -package net.ornithemc.osl.networking.api; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; - -public final class DataStreams { - - public static DataInputStream input(byte[] bytes) { - return new DataInputStream(new ByteArrayInputStream(bytes == null ? new byte[0] : bytes)); - } - - public static ByteArrayOutputStream output(IOConsumer writer) throws IOException { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - DataOutputStream os = new DataOutputStream(bos); - writer.accept(os); - return bos; - } -} diff --git a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/PacketBuffer.java b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/PacketBuffer.java new file mode 100644 index 00000000..332c2370 --- /dev/null +++ b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/PacketBuffer.java @@ -0,0 +1,1217 @@ +package net.ornithemc.osl.networking.api; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.channels.FileChannel; +import java.nio.channels.GatheringByteChannel; +import java.nio.channels.ScatteringByteChannel; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.UUID; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufInputStream; +import io.netty.buffer.ByteBufOutputStream; +import io.netty.util.ByteProcessor; + +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtIo; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.NamespacedIdentifiers; + +public class PacketBuffer extends ByteBuf { + + private static final int VAR_VALUE_BITS = 7; + private static final int VAR_VALUE_MASK = 1 << VAR_VALUE_BITS - 1; + private static final int VAR_PARITY_VALUE = 1 << VAR_VALUE_BITS; + private static final int VAR_INT_MAX_BYTES = 5; + private static final int VAR_LONG_MAX_BYTES = 10; + + final ByteBuf delegate; + + public PacketBuffer(ByteBuf delegate) { + this.delegate = delegate; + } + + public int readVarInt() { + int value = 0; + + byte bytes = 0; + byte nextByte = 0; + + do { + nextByte = this.readByte(); + value |= (nextByte & VAR_VALUE_MASK) << bytes++ * VAR_VALUE_BITS; + + if (bytes > VAR_INT_MAX_BYTES) { + throw new RuntimeException("VarInt too big"); + } + } while ((nextByte & VAR_PARITY_VALUE) == VAR_PARITY_VALUE); + + return value; + } + + public long readVarLong() { + long value = 0; + + byte bytes = 0; + byte nextByte = 0; + + do { + nextByte = this.readByte(); + value |= (nextByte & VAR_VALUE_MASK) << bytes++ * VAR_VALUE_BITS; + + if (bytes > VAR_LONG_MAX_BYTES) { + throw new RuntimeException("VarLong too big"); + } + } while ((nextByte & VAR_PARITY_VALUE) == VAR_PARITY_VALUE); + + return value; + } + + public byte[] readByteArray() { + return this.readByteArray(this.readableBytes()); + } + + public byte[] readByteArray(int maxLength) { + int length = this.readVarInt(); + + if (length > maxLength) { + throw new RuntimeException("ByteArray with size " + length + " is bigger than allowed " + maxLength); + } + + byte[] values = new byte[length]; + + for (int i = 0; i < length; i++) { + values[i] = this.readByte(); + } + + return values; + } + + public int[] readIntArray() { + return this.readIntArray(this.readableBytes()); + } + + public int[] readIntArray(int maxLength) { + int length = this.readVarInt(); + + if (length > maxLength) { + throw new RuntimeException("IntArray with size " + length + " is bigger than allowed " + maxLength); + } + + int[] values = new int[length]; + + for (int i = 0; i < length; i++) { + values[i] = this.readVarInt(); + } + + return values; + } + + public long[] readLongArray() { + return this.readLongArray(this.readableBytes() / 8); + } + + public long[] readLongArray(int maxLength) { + int length = this.readVarInt(); + + if (length > maxLength) { + throw new IllegalStateException("LongArray with size " + length + " is bigger than allowed " + maxLength); + } + + long[] values = new long[length]; + + for (int i = 0; i < length; i++) { + values[i] = this.readVarLong(); + } + + return values; + } + + public String readString() { + return this.readString(Short.MAX_VALUE); + } + + public String readString(int maxLength) { + int length = this.readVarInt(); + + if (length > maxLength * 4) { + throw new RuntimeException("The received encoded string buffer length is longer than maximum allowed (" + length + " > " + maxLength * 4 + ")"); + } + if (length < 0) { + throw new RuntimeException("The received encoded string buffer length is less than zero! Weird string!"); + } + + String s = this.toString(this.readerIndex(), length, StandardCharsets.UTF_8); + this.readerIndex(this.readerIndex() + length); + + if (s.length() > maxLength) { + throw new RuntimeException("The received string length is longer than maximum allowed (" + length + " > " + maxLength + ")"); + } + + return s; + } + + public > T readEnum(Class type) { + return type.getEnumConstants()[this.readVarInt()]; + } + + public Date readDate() { + return new Date(this.readLong()); + } + + public UUID readUuid() { + return new UUID( + this.readLong(), + this.readLong() + ); + } + + public NamespacedIdentifier readNamespacedIdentifier() { + return NamespacedIdentifiers.parse(this.readString()); + } + + public NbtCompound readNbtCompound() { + int readerIndex = this.readerIndex(); + byte firstByte = this.readByte(); + + if (firstByte == 0) { + return null; + } else { + this.readerIndex(readerIndex); + + try { + return NbtIo.read(new ByteBufInputStream(this)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + public ByteBuf writeVarInt(int value) { + while ((value & -128) != 0) { + this.writeByte(value & VAR_VALUE_MASK | VAR_PARITY_VALUE); + value >>>= VAR_VALUE_BITS; + } + + this.writeByte(value); + + return this; + } + + public ByteBuf writeVarLong(long value) { + while ((value & -128) != 0) { + this.writeByte((int) (value & VAR_VALUE_MASK) | VAR_PARITY_VALUE); + value >>>= VAR_VALUE_BITS; + } + + this.writeByte((int) value); + + return this; + } + + public ByteBuf writeByteArray(byte[] values) { + this.writeVarInt(values.length); + + for (byte value : values) { + this.writeByte(value); + } + + return this; + } + + public ByteBuf writeIntArray(int[] values) { + this.writeVarInt(values.length); + + for (int value : values) { + this.writeVarInt(value); + } + + return this; + } + + public ByteBuf writeLongArray(long[] values) { + this.writeVarInt(values.length); + + for (long value : values) { + this.writeVarLong(value); + } + + return this; + } + + public ByteBuf writeString(String s) { + return this.writeString(s, Short.MAX_VALUE); + } + + public ByteBuf writeString(String s, int maxLength) { + byte[] bytes = s.getBytes(StandardCharsets.UTF_8); + + if (bytes.length > maxLength) { + throw new RuntimeException("String too big (was " + bytes.length + " bytes encoded, max " + maxLength + ")"); + } + + this.writeByteArray(bytes); + + return this; + } + + public ByteBuf writeEnum(Enum value) { + this.writeVarInt(value.ordinal()); + + return this; + } + + public ByteBuf writeDate(Date date) { + this.writeLong(date.getTime()); + + return this; + } + + public ByteBuf writeUuid(UUID uuid) { + this.writeLong(uuid.getMostSignificantBits()); + this.writeLong(uuid.getLeastSignificantBits()); + + return this; + } + + public ByteBuf writeNamespacedIdentifier(NamespacedIdentifier id) { + return this.writeString(id.toString()); + } + + public ByteBuf writeNbtCompound(NbtCompound nbt) { + if (nbt == null) { + this.writeByte(0); + } else { + try { + NbtIo.write(nbt, new ByteBufOutputStream(this)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + return this; + } + + @Override + public int capacity() { + return this.delegate.capacity(); + } + + @Override + public ByteBuf capacity(int newCapacity) { + return this.delegate.capacity(newCapacity); + } + + @Override + public int maxCapacity() { + return this.delegate.maxCapacity(); + } + + @Override + public ByteBufAllocator alloc() { + return this.delegate.alloc(); + } + + @Override + public ByteOrder order() { + return this.delegate.order(); + } + + @Override + public ByteBuf order(ByteOrder order) { + return this.delegate.order(order); + } + + @Override + public ByteBuf unwrap() { + return this.delegate.unwrap(); + } + + @Override + public boolean isDirect() { + return this.delegate.isDirect(); + } + + @Override + public boolean isReadOnly() { + return this.delegate.isReadOnly(); + } + + @Override + public ByteBuf asReadOnly() { + return this.delegate.asReadOnly(); + } + + @Override + public int readerIndex() { + return this.delegate.readerIndex(); + } + + @Override + public ByteBuf readerIndex(int readerIndex) { + return this.delegate.readerIndex(readerIndex); + } + + @Override + public int writerIndex() { + return this.delegate.writerIndex(); + } + + @Override + public ByteBuf writerIndex(int writerIndex) { + return this.delegate.writerIndex(writerIndex); + } + + @Override + public ByteBuf setIndex(int readerIndex, int writerIndex) { + return this.delegate.setIndex(readerIndex, writerIndex); + } + + @Override + public int readableBytes() { + return this.delegate.readableBytes(); + } + + @Override + public int writableBytes() { + return this.delegate.writableBytes(); + } + + @Override + public int maxWritableBytes() { + return this.delegate.maxWritableBytes(); + } + + @Override + public boolean isReadable() { + return this.delegate.isReadable(); + } + + @Override + public boolean isReadable(int size) { + return this.delegate.isReadable(size); + } + + @Override + public boolean isWritable() { + return this.delegate.isWritable(); + } + + @Override + public boolean isWritable(int size) { + return this.delegate.isWritable(size); + } + + @Override + public ByteBuf clear() { + return this.delegate.clear(); + } + + @Override + public ByteBuf markReaderIndex() { + return this.delegate.markReaderIndex(); + } + + @Override + public ByteBuf resetReaderIndex() { + return this.delegate.resetReaderIndex(); + } + + @Override + public ByteBuf markWriterIndex() { + return this.delegate.markWriterIndex(); + } + + @Override + public ByteBuf resetWriterIndex() { + return this.delegate.resetWriterIndex(); + } + + @Override + public ByteBuf discardReadBytes() { + return this.delegate.discardReadBytes(); + } + + @Override + public ByteBuf discardSomeReadBytes() { + return this.delegate.discardSomeReadBytes(); + } + + @Override + public ByteBuf ensureWritable(int minWritableBytes) { + return this.delegate.ensureWritable(minWritableBytes); + } + + @Override + public int ensureWritable(int minWritableBytes, boolean force) { + return this.delegate.ensureWritable(minWritableBytes, force); + } + + @Override + public boolean getBoolean(int index) { + return this.delegate.getBoolean(index); + } + + @Override + public byte getByte(int index) { + return this.delegate.getByte(index); + } + + @Override + public short getUnsignedByte(int index) { + return this.delegate.getUnsignedByte(index); + } + + @Override + public short getShort(int index) { + return this.delegate.getShort(index); + } + + @Override + public short getShortLE(int index) { + return this.delegate.getShortLE(index); + } + + @Override + public int getUnsignedShort(int index) { + return this.delegate.getUnsignedShort(index); + } + + @Override + public int getUnsignedShortLE(int index) { + return this.delegate.getUnsignedShortLE(index); + } + + @Override + public int getMedium(int index) { + return this.delegate.getMedium(index); + } + + @Override + public int getMediumLE(int index) { + return this.delegate.getMediumLE(index); + } + + @Override + public int getUnsignedMedium(int index) { + return this.delegate.getUnsignedMedium(index); + } + + @Override + public int getUnsignedMediumLE(int index) { + return this.delegate.getUnsignedMediumLE(index); + } + + @Override + public int getInt(int index) { + return this.delegate.getInt(index); + } + + @Override + public int getIntLE(int index) { + return this.delegate.getIntLE(index); + } + + @Override + public long getUnsignedInt(int index) { + return this.delegate.getUnsignedInt(index); + } + + @Override + public long getUnsignedIntLE(int index) { + return this.delegate.getUnsignedIntLE(index); + } + + @Override + public long getLong(int index) { + return this.delegate.getLong(index); + } + + @Override + public long getLongLE(int index) { + return this.delegate.getLongLE(index); + } + + @Override + public char getChar(int index) { + return this.delegate.getChar(index); + } + + @Override + public float getFloat(int index) { + return this.delegate.getFloat(index); + } + + @Override + public double getDouble(int index) { + return this.delegate.getDouble(index); + } + + @Override + public ByteBuf getBytes(int index, ByteBuf dst) { + return this.delegate.getBytes(index, dst); + } + + @Override + public ByteBuf getBytes(int index, ByteBuf dst, int length) { + return this.delegate.getBytes(index, dst, length); + } + + @Override + public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) { + return this.delegate.getBytes(index, dst, dstIndex, length); + } + + @Override + public ByteBuf getBytes(int index, byte[] dst) { + return this.delegate.getBytes(index, dst); + } + + @Override + public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) { + return this.delegate.getBytes(index, dst, dstIndex, length); + } + + @Override + public ByteBuf getBytes(int index, ByteBuffer dst) { + return this.delegate.getBytes(index, dst); + } + + @Override + public ByteBuf getBytes(int index, OutputStream out, int length) throws IOException { + return this.delegate.getBytes(index, out, length); + } + + @Override + public int getBytes(int index, GatheringByteChannel out, int length) throws IOException { + return this.delegate.getBytes(index, out, length); + } + + @Override + public int getBytes(int index, FileChannel out, long position, int length) throws IOException { + return this.delegate.getBytes(index, out, position, length); + } + + @Override + public CharSequence getCharSequence(int index, int length, Charset charset) { + return this.delegate.getCharSequence(index, length, charset); + } + + @Override + public ByteBuf setBoolean(int index, boolean value) { + return this.delegate.setBoolean(index, value); + } + + @Override + public ByteBuf setByte(int index, int value) { + return this.delegate.setByte(index, value); + } + + @Override + public ByteBuf setShort(int index, int value) { + return this.delegate.setShort(index, value); + } + + @Override + public ByteBuf setShortLE(int index, int value) { + return this.delegate.setShortLE(index, value); + } + + @Override + public ByteBuf setMedium(int index, int value) { + return this.delegate.setMedium(index, value); + } + + @Override + public ByteBuf setMediumLE(int index, int value) { + return this.delegate.setMediumLE(index, value); + } + + @Override + public ByteBuf setInt(int index, int value) { + return this.delegate.setInt(index, value); + } + + @Override + public ByteBuf setIntLE(int index, int value) { + return this.delegate.setIntLE(index, value); + } + + @Override + public ByteBuf setLong(int index, long value) { + return this.delegate.setLong(index, value); + } + + @Override + public ByteBuf setLongLE(int index, long value) { + return this.delegate.setLongLE(index, value); + } + + @Override + public ByteBuf setChar(int index, int value) { + return this.delegate.setChar(index, value); + } + + @Override + public ByteBuf setFloat(int index, float value) { + return this.delegate.setFloat(index, value); + } + + @Override + public ByteBuf setDouble(int index, double value) { + return this.delegate.setDouble(index, value); + } + + @Override + public ByteBuf setBytes(int index, ByteBuf src) { + return this.delegate.setBytes(index, src); + } + + @Override + public ByteBuf setBytes(int index, ByteBuf src, int length) { + return this.delegate.setBytes(index, src, length); + } + + @Override + public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) { + return this.delegate.setBytes(index, src, srcIndex, length); + } + + @Override + public ByteBuf setBytes(int index, byte[] src) { + return this.delegate.setBytes(index, src); + } + + @Override + public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) { + return this.delegate.setBytes(index, src, srcIndex, length); + } + + @Override + public ByteBuf setBytes(int index, ByteBuffer src) { + return this.delegate.setBytes(index, src); + } + + @Override + public int setBytes(int index, InputStream in, int length) throws IOException { + return this.delegate.setBytes(index, in, length); + } + + @Override + public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException { + return this.delegate.setBytes(index, in, length); + } + + @Override + public int setBytes(int index, FileChannel in, long position, int length) throws IOException { + return this.delegate.setBytes(index, in, position, length); + } + + @Override + public ByteBuf setZero(int index, int length) { + return this.delegate.setZero(index, length); + } + + @Override + public int setCharSequence(int index, CharSequence sequence, Charset charset) { + return this.delegate.setCharSequence(index, sequence, charset); + } + + @Override + public boolean readBoolean() { + return this.delegate.readBoolean(); + } + + @Override + public byte readByte() { + return this.delegate.readByte(); + } + + @Override + public short readUnsignedByte() { + return this.delegate.readUnsignedByte(); + } + + @Override + public short readShort() { + return this.delegate.readShort(); + } + + @Override + public short readShortLE() { + return this.delegate.readShortLE(); + } + + @Override + public int readUnsignedShort() { + return this.delegate.readUnsignedShort(); + } + + @Override + public int readUnsignedShortLE() { + return this.delegate.readUnsignedShortLE(); + } + + @Override + public int readMedium() { + return this.delegate.readMedium(); + } + + @Override + public int readMediumLE() { + return this.delegate.readMediumLE(); + } + + @Override + public int readUnsignedMedium() { + return this.delegate.readUnsignedMedium(); + } + + @Override + public int readUnsignedMediumLE() { + return this.delegate.readUnsignedMediumLE(); + } + + @Override + public int readInt() { + return this.delegate.readInt(); + } + + @Override + public int readIntLE() { + return this.delegate.readIntLE(); + } + + @Override + public long readUnsignedInt() { + return this.delegate.readUnsignedInt(); + } + + @Override + public long readUnsignedIntLE() { + return this.delegate.readUnsignedIntLE(); + } + + @Override + public long readLong() { + return this.delegate.readLong(); + } + + @Override + public long readLongLE() { + return this.delegate.readLongLE(); + } + + @Override + public char readChar() { + return this.delegate.readChar(); + } + + @Override + public float readFloat() { + return this.delegate.readFloat(); + } + + @Override + public double readDouble() { + return this.delegate.readDouble(); + } + + @Override + public ByteBuf readBytes(int length) { + return this.delegate.readBytes(length); + } + + @Override + public ByteBuf readSlice(int length) { + return this.delegate.readSlice(length); + } + + @Override + public ByteBuf readRetainedSlice(int length) { + return this.delegate.readRetainedSlice(length); + } + + @Override + public ByteBuf readBytes(ByteBuf dst) { + return this.delegate.readBytes(dst); + } + + @Override + public ByteBuf readBytes(ByteBuf dst, int length) { + return this.delegate.readBytes(dst, length); + } + + @Override + public ByteBuf readBytes(ByteBuf dst, int dstIndex, int length) { + return this.delegate.readBytes(dst, dstIndex, length); + } + + @Override + public ByteBuf readBytes(byte[] dst) { + return this.delegate.readBytes(dst); + } + + @Override + public ByteBuf readBytes(byte[] dst, int dstIndex, int length) { + return this.delegate.readBytes(dst, dstIndex, length); + } + + @Override + public ByteBuf readBytes(ByteBuffer dst) { + return this.delegate.readBytes(dst); + } + + @Override + public ByteBuf readBytes(OutputStream out, int length) throws IOException { + return this.delegate.readBytes(out, length); + } + + @Override + public int readBytes(GatheringByteChannel out, int length) throws IOException { + return this.delegate.readBytes(out, length); + } + + @Override + public CharSequence readCharSequence(int length, Charset charset) { + return this.delegate.readCharSequence(length, charset); + } + + @Override + public int readBytes(FileChannel out, long position, int length) throws IOException { + return this.delegate.readBytes(out, position, length); + } + + @Override + public ByteBuf skipBytes(int length) { + return this.delegate.skipBytes(length); + } + + @Override + public ByteBuf writeBoolean(boolean value) { + return this.delegate.writeBoolean(value); + } + + @Override + public ByteBuf writeByte(int value) { + return this.delegate.writeByte(value); + } + + @Override + public ByteBuf writeShort(int value) { + return this.delegate.writeShort(value); + } + + @Override + public ByteBuf writeShortLE(int value) { + return this.delegate.writeShortLE(value); + } + + @Override + public ByteBuf writeMedium(int value) { + return this.delegate.writeMedium(value); + } + + @Override + public ByteBuf writeMediumLE(int value) { + return this.delegate.writeMediumLE(value); + } + + @Override + public ByteBuf writeInt(int value) { + return this.delegate.writeInt(value); + } + + @Override + public ByteBuf writeIntLE(int value) { + return this.delegate.writeIntLE(value); + } + + @Override + public ByteBuf writeLong(long value) { + return this.delegate.writeLong(value); + } + + @Override + public ByteBuf writeLongLE(long value) { + return this.delegate.writeLongLE(value); + } + + @Override + public ByteBuf writeChar(int value) { + return this.delegate.writeChar(value); + } + + @Override + public ByteBuf writeFloat(float value) { + return this.delegate.writeFloat(value); + } + + @Override + public ByteBuf writeDouble(double value) { + return this.delegate.writeDouble(value); + } + + @Override + public ByteBuf writeBytes(ByteBuf src) { + return this.delegate.writeBytes(src); + } + + @Override + public ByteBuf writeBytes(ByteBuf src, int length) { + return this.delegate.writeBytes(src, length); + } + + @Override + public ByteBuf writeBytes(ByteBuf src, int srcIndex, int length) { + return this.delegate.writeBytes(src, srcIndex, length); + } + + @Override + public ByteBuf writeBytes(byte[] src) { + return this.delegate.writeBytes(src); + } + + @Override + public ByteBuf writeBytes(byte[] src, int srcIndex, int length) { + return this.delegate.writeBytes(src, srcIndex, length); + } + + @Override + public ByteBuf writeBytes(ByteBuffer src) { + return this.delegate.writeBytes(src); + } + + @Override + public int writeBytes(InputStream in, int length) throws IOException { + return this.delegate.writeBytes(in, length); + } + + @Override + public int writeBytes(ScatteringByteChannel in, int length) throws IOException { + return this.delegate.writeBytes(in, length); + } + + @Override + public int writeBytes(FileChannel in, long position, int length) throws IOException { + return this.delegate.writeBytes(in, position, length); + } + + @Override + public ByteBuf writeZero(int length) { + return this.delegate.writeZero(length); + } + + @Override + public int writeCharSequence(CharSequence sequence, Charset charset) { + return this.delegate.writeCharSequence(sequence, charset); + } + + @Override + public int indexOf(int fromIndex, int toIndex, byte value) { + return this.delegate.indexOf(fromIndex, toIndex, value); + } + + @Override + public int bytesBefore(byte value) { + return this.delegate.bytesBefore(value); + } + + @Override + public int bytesBefore(int length, byte value) { + return this.delegate.bytesBefore(length, value); + } + + @Override + public int bytesBefore(int index, int length, byte value) { + return this.delegate.bytesBefore(index, length, value); + } + + @Override + public int forEachByte(ByteProcessor processor) { + return this.delegate.forEachByte(processor); + } + + @Override + public int forEachByte(int index, int length, ByteProcessor processor) { + return this.delegate.forEachByte(index, length, processor); + } + + @Override + public int forEachByteDesc(ByteProcessor processor) { + return this.delegate.forEachByteDesc(processor); + } + + @Override + public int forEachByteDesc(int index, int length, ByteProcessor processor) { + return this.delegate.forEachByteDesc(index, length, processor); + } + + @Override + public ByteBuf copy() { + return this.delegate.copy(); + } + + @Override + public ByteBuf copy(int index, int length) { + return this.delegate.copy(index, length); + } + + @Override + public ByteBuf slice() { + return this.delegate.slice(); + } + + @Override + public ByteBuf retainedSlice() { + return this.delegate.retainedSlice(); + } + + @Override + public ByteBuf slice(int index, int length) { + return this.delegate.slice(index, length); + } + + @Override + public ByteBuf retainedSlice(int index, int length) { + return this.delegate.retainedSlice(index, length); + } + + @Override + public ByteBuf duplicate() { + return this.delegate.duplicate(); + } + + @Override + public ByteBuf retainedDuplicate() { + return this.delegate.retainedDuplicate(); + } + + @Override + public int nioBufferCount() { + return this.delegate.nioBufferCount(); + } + + @Override + public ByteBuffer nioBuffer() { + return this.delegate.nioBuffer(); + } + + @Override + public ByteBuffer nioBuffer(int index, int length) { + return this.delegate.nioBuffer(index, length); + } + + @Override + public ByteBuffer internalNioBuffer(int index, int length) { + return this.delegate.internalNioBuffer(index, length); + } + + @Override + public ByteBuffer[] nioBuffers() { + return this.delegate.nioBuffers(); + } + + @Override + public ByteBuffer[] nioBuffers(int index, int length) { + return this.delegate.nioBuffers(index, length); + } + + @Override + public boolean hasArray() { + return this.delegate.hasArray(); + } + + @Override + public byte[] array() { + return this.delegate.array(); + } + + @Override + public int arrayOffset() { + return this.delegate.arrayOffset(); + } + + @Override + public boolean hasMemoryAddress() { + return this.delegate.hasMemoryAddress(); + } + + @Override + public long memoryAddress() { + return this.delegate.memoryAddress(); + } + + @Override + public String toString(Charset charset) { + return this.delegate.toString(charset); + } + + @Override + public String toString(int index, int length, Charset charset) { + return this.delegate.toString(index, length, charset); + } + + @Override + public int hashCode() { + return this.delegate.hashCode(); + } + + @Override + public boolean equals(Object o) { + return this.delegate.equals(o); + } + + @Override + public int compareTo(ByteBuf o) { + return this.delegate.compareTo(o); + } + + @Override + public String toString() { + return this.delegate.toString(); + } + + @Override + public ByteBuf retain(int increment) { + return this.delegate.retain(increment); + } + + @Override + public ByteBuf retain() { + return this.delegate.retain(); + } + + @Override + public ByteBuf touch() { + return this.delegate.touch(); + } + + @Override + public ByteBuf touch(Object hint) { + return this.delegate.touch(hint); + } + + @Override + public int refCnt() { + return this.delegate.refCnt(); + } + + @Override + public boolean release() { + return this.delegate.release(); + } + + @Override + public boolean release(int decrement) { + return this.delegate.release(decrement); + } +} diff --git a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/PacketBuffers.java b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/PacketBuffers.java new file mode 100644 index 00000000..a9e6ccc8 --- /dev/null +++ b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/PacketBuffers.java @@ -0,0 +1,35 @@ +package net.ornithemc.osl.networking.api; + +import java.io.IOException; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; + +import net.ornithemc.osl.core.api.util.function.IOConsumer; + +public final class PacketBuffers { + + public static PacketBuffer make() { + return wrapped(Unpooled.buffer()); + } + + public static PacketBuffer make(IOConsumer writer) throws IOException { + PacketBuffer buffer = make(); + writer.accept(buffer); + return buffer; + } + + public static PacketBuffer wrap(byte[] bytes) { + return wrapped(Unpooled.wrappedBuffer(bytes)); + } + + public static byte[] unwrap(PacketBuffer buffer) { + byte[] bytes = new byte[buffer.writerIndex()]; + buffer.getBytes(0, bytes); + return bytes; + } + + public static PacketBuffer wrapped(ByteBuf buffer) { + return new PacketBuffer(buffer); + } +} diff --git a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/PacketPayload.java b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/PacketPayload.java new file mode 100644 index 00000000..7f7835e7 --- /dev/null +++ b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/PacketPayload.java @@ -0,0 +1,11 @@ +package net.ornithemc.osl.networking.api; + +import java.io.IOException; + +public interface PacketPayload { + + void read(PacketBuffer buffer) throws IOException; + + void write(PacketBuffer buffer) throws IOException; + +} diff --git a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java index f0963ed6..d5adcfb8 100644 --- a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java +++ b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java @@ -19,6 +19,10 @@ public class ClientConnectionEvents { * and until then data cannot safely be sent to the server. * *

+ * This applies to connections to dedicated servers as + * well as connections to integrated servers. + * + *

* Callbacks to this event should be registered in your mod's entrypoint, * and can be done as follows: * @@ -38,6 +42,10 @@ public class ClientConnectionEvents { * This marks the moment data can safely be sent to the server. * *

+ * This applies to connections to dedicated servers as + * well as connections to integrated servers. + * + *

* Callbacks to this event should be registered in your mod's entrypoint, * and can be done as follows: * @@ -54,6 +62,10 @@ public class ClientConnectionEvents { * This event is fired when the client disconnects from the server. * *

+ * This applies to connections to dedicated servers as + * well as connections to integrated servers. + * + *

* Callbacks to this event should be registered in your mod's entrypoint, * and can be done as follows: * diff --git a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/client/ClientPacketListener.java b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/client/ClientPacketListener.java new file mode 100644 index 00000000..4b9f15d4 --- /dev/null +++ b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/client/ClientPacketListener.java @@ -0,0 +1,31 @@ +package net.ornithemc.osl.networking.api.client; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.network.handler.ClientNetworkHandler; + +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketPayload; + +public interface ClientPacketListener { + + /** + * Receive incoming data from the server. + * + * @return + * Whether the data is consumed. Should only return {@code false} if the + * data is completely ignored. + */ + boolean handle(Minecraft minecraft, ClientNetworkHandler handler, T data); + + @FunctionalInterface + public interface Payload extends ClientPacketListener { + } + + @FunctionalInterface + public interface Buffer extends ClientPacketListener { + } + + @FunctionalInterface + public interface Bytes extends ClientPacketListener { + } +} diff --git a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java index e1594802..06d6ff52 100644 --- a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java +++ b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java @@ -1,15 +1,11 @@ package net.ornithemc.osl.networking.api.client; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.function.Supplier; -import net.minecraft.client.Minecraft; -import net.minecraft.client.network.handler.ClientNetworkHandler; - +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.CustomPayload; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketPayload; import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; public final class ClientPlayNetworking { @@ -17,34 +13,55 @@ public final class ClientPlayNetworking { /** * Register a listener to receive data from the server through the given channel. * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. */ - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { + public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { ClientPlayNetworkingImpl.registerListener(channel, initializer, listener); } + /** + * Register a listener to receive data from the server through the given channel. + * This listener may be called off the main thread. + */ + public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { + ClientPlayNetworkingImpl.registerListenerAsync(channel, initializer, listener); + } + /** * Register a listener to receive data from the server through the given channel. * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. */ - public static void registerListener(String channel, StreamListener listener) { + public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { ClientPlayNetworkingImpl.registerListener(channel, listener); } + /** + * Register a listener to receive data from the server through the given channel. + * This listener may be called off the main thread. + */ + public static void registerListenerAsync(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { + ClientPlayNetworkingImpl.registerListenerAsync(channel, listener); + } + /** * Register a listener to receive data from the server through the given channel. * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. */ - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - ClientPlayNetworkingImpl.registerListenerRaw(channel, listener); + public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { + ClientPlayNetworkingImpl.registerListener(channel, listener); + } + + /** + * Register a listener to receive data from the server through the given channel. + * This listener may be called off the main thread. + */ + public static void registerListenerAsync(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { + ClientPlayNetworkingImpl.registerListenerAsync(channel, listener); } /** * Remove the listener registered to the given channel. */ - public static void unregisterListener(String channel) { + public static void unregisterListener(NamespacedIdentifier channel) { ClientPlayNetworkingImpl.unregisterListener(channel); } @@ -60,15 +77,15 @@ public static boolean isPlayReady() { * This method will return {@code false} if the client is not connected to a * server, or if the server has no listeners for the given channel. */ - public static boolean canSend(String channel) { - return ClientPlayNetworkingImpl.canSend(channel); + public static boolean isPlayReady(NamespacedIdentifier channel) { + return ClientPlayNetworkingImpl.isPlayReady(channel); } /** * Send a packet to the server through the given channel. The payload will * only be written if the channel is open. */ - public static void send(String channel, CustomPayload payload) { + public static void send(NamespacedIdentifier channel, PacketPayload payload) { ClientPlayNetworkingImpl.send(channel, payload); } @@ -76,15 +93,22 @@ public static void send(String channel, CustomPayload payload) { * Send a packet to the server through the given channel. The writer will * only be called if the channel is open. */ - public static void send(String channel, IOConsumer writer) { + public static void send(NamespacedIdentifier channel, IOConsumer writer) { ClientPlayNetworkingImpl.send(channel, writer); } /** * Send a packet to the server through the given channel. */ - public static void send(String channel, byte[] data) { - ClientPlayNetworkingImpl.send(channel, data); + public static void send(NamespacedIdentifier channel, PacketBuffer buffer) { + ClientPlayNetworkingImpl.send(channel, buffer); + } + + /** + * Send a packet to the server through the given channel. + */ + public static void send(NamespacedIdentifier channel, byte[] bytes) { + ClientPlayNetworkingImpl.send(channel, bytes); } /** @@ -93,8 +117,8 @@ public static void send(String channel, byte[] data) { * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the server. */ - public static void doSend(String channel, CustomPayload payload) { - ClientPlayNetworkingImpl.doSend(channel, payload); + public static void sendNoCheck(NamespacedIdentifier channel, PacketPayload payload) { + ClientPlayNetworkingImpl.sendNoCheck(channel, payload); } /** @@ -103,8 +127,8 @@ public static void doSend(String channel, CustomPayload payload) { * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the server. */ - public static void doSend(String channel, IOConsumer writer) { - ClientPlayNetworkingImpl.doSend(channel, writer); + public static void sendNoCheck(NamespacedIdentifier channel, IOConsumer writer) { + ClientPlayNetworkingImpl.sendNoCheck(channel, writer); } /** @@ -113,46 +137,17 @@ public static void doSend(String channel, IOConsumer writer) { * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the server. */ - public static void doSend(String channel, byte[] data) { - ClientPlayNetworkingImpl.doSend(channel, data); - } - - public interface PayloadListener { - - /** - * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(Minecraft minecraft, ClientNetworkHandler handler, T payload) throws IOException; - + public static void sendNoCheck(NamespacedIdentifier channel, PacketBuffer buffer) { + ClientPlayNetworkingImpl.sendNoCheck(channel, buffer); } - public interface StreamListener { - - /** - * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(Minecraft minecraft, ClientNetworkHandler handler, DataInputStream data) throws IOException; - - } - - public interface ByteArrayListener { - - /** - * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(Minecraft minecraft, ClientNetworkHandler handler, byte[] data) throws IOException; - + /** + * Send a packet to the server through the given channel, without checking + * whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the server. + */ + public static void sendNoCheck(NamespacedIdentifier channel, byte[] bytes) { + ClientPlayNetworkingImpl.sendNoCheck(channel, bytes); } } diff --git a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/Connections.java b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/Connections.java new file mode 100644 index 00000000..836dd8ed --- /dev/null +++ b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/Connections.java @@ -0,0 +1,22 @@ +package net.ornithemc.osl.networking.impl; + +import net.minecraft.network.PacketHandler; +import net.minecraft.network.packet.Packet; + +import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; + +public final class Connections { + + public static boolean checkAsyncHandling(Packet packet, PacketHandler listener) { + boolean handleAsync = packet instanceof CustomPayloadPacketAccess + && listener instanceof NetworkHandlerAccess + && ((NetworkHandlerAccess) listener).osl$networking$canRunOffMainThread(); + + if (handleAsync) { + packet.handle(listener); + } + + return handleAsync; + } +} diff --git a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java deleted file mode 100644 index 76c2850d..00000000 --- a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java +++ /dev/null @@ -1,75 +0,0 @@ -package net.ornithemc.osl.networking.impl; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.UncheckedIOException; - -import net.minecraft.network.PacketHandler; -import net.minecraft.network.packet.Packet; - -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; - -public class CustomPayloadPacket extends Packet { - - public String channel; - public int size; - public byte[] data; - - public CustomPayloadPacket() { - } - - public CustomPayloadPacket(String channel, byte[] data) { - this.channel = channel; - this.data = data; - if (data != null) { - this.size = data.length; - if (this.size > Short.MAX_VALUE) { - throw new IllegalArgumentException("Payload may not be larger than 32k"); - } - } - } - - // the IOException has been stripped from the read/write methods - // by the obfuscator, thus we catch it and re-throw it as a - // runtime exception - it will be caught in Connection#read anyhow - - @Override - public void read(DataInputStream input) { - try { - this.channel = input.readUTF(); - this.size = input.readShort(); - if (this.size > 0 && this.size < Short.MAX_VALUE) { - this.data = new byte[this.size]; - input.readFully(this.data); - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - @Override - public void write(DataOutputStream output) { - try { - output.writeUTF(this.channel); - output.writeShort(this.size); - if (this.data != null) { - output.write(this.data); - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - @Override - public void handle(PacketHandler handler) { - if (handler instanceof INetworkHandler) { - ((INetworkHandler)handler).osl$networking$handleCustomPayload(this); - } - } - - @Override - public int getSize() { - return 2 + this.channel.length() * 2 + 2 + this.size; - } -} diff --git a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java index 3288d684..2866823a 100644 --- a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java +++ b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java @@ -1,53 +1,56 @@ package net.ornithemc.osl.networking.impl; -import java.io.DataInputStream; -import java.io.DataOutputStream; import java.io.IOException; import java.util.LinkedHashSet; import java.util.Set; -import net.ornithemc.osl.networking.api.CustomPayload; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.api.ChannelIdentifiers; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketPayload; import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; -public class HandshakePayload implements CustomPayload { +public class HandshakePayload implements PacketPayload { - public static final String CHANNEL = "OSL|Handshake"; + public static final NamespacedIdentifier CHANNEL = Constants.OSL_HANDSHAKE_CHANNEL; - public Set channels; + public byte protocol; + public Set channels; public HandshakePayload() { } - public HandshakePayload(Set channels) { - this.channels = channels; + public HandshakePayload(Set channels) { + this.protocol = Constants.OSL_HANDSHAKE_PROTOCOL; + // we allow registering listeners on channels that do not conform to OSL spec + // but payloads sent over these channels aren't sent via OSL so we can ignore + // them for the OSL handshake. + this.channels = ChannelIdentifiers.dropInvalid(channels); } public static HandshakePayload client() { - return new HandshakePayload(ClientPlayNetworkingImpl.LISTENERS.keySet()); - } - - public static HandshakePayload server() { - throw new UnsupportedOperationException(); + return new HandshakePayload(ClientPlayNetworkingImpl.CHANNEL_LISTENERS.keySet()); } @Override - public void read(DataInputStream input) throws IOException { + public void read(PacketBuffer buffer) throws IOException { + protocol = buffer.readByte(); channels = new LinkedHashSet<>(); - int channelCount = input.readInt(); - if (channelCount > 0) { - for (int i = 0; i < channelCount; i++) { - channels.add(input.readUTF()); - } + int channelCount = buffer.readInt(); + + for (int i = 0; i < channelCount; i++) { + channels.add(buffer.readNamespacedIdentifier()); } } @Override - public void write(DataOutputStream output) throws IOException { - output.writeInt(channels.size()); + public void write(PacketBuffer buffer) throws IOException { + buffer.writeByte(protocol); + buffer.writeInt(channels.size()); - for (String channel : channels) { - output.writeUTF(channel); + for (NamespacedIdentifier channel : channels) { + buffer.writeNamespacedIdentifier(channel); } } } diff --git a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/Networking.java deleted file mode 100644 index 7dfc242e..00000000 --- a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/Networking.java +++ /dev/null @@ -1,37 +0,0 @@ -package net.ornithemc.osl.networking.impl; - -import net.ornithemc.osl.entrypoints.api.ModInitializer; -import net.ornithemc.osl.entrypoints.api.client.ClientModInitializer; -import net.ornithemc.osl.lifecycle.api.client.MinecraftClientEvents; -import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking; -import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; -import net.ornithemc.osl.networking.impl.mixin.common.PacketAccessor; - -public class Networking implements ModInitializer, ClientModInitializer { - - @Override - public void init() { - PacketAccessor.register(Constants.CUSTOM_PAYLOAD_PACKET_ID, CustomPayloadPacket.class); - } - - @Override - public void initClient() { - MinecraftClientEvents.START.register(minecraft -> { - ClientPlayNetworkingImpl.setUp(minecraft); - }); - MinecraftClientEvents.STOP.register(minecraft -> { - ClientPlayNetworkingImpl.destroy(minecraft); - }); - ClientPlayNetworking.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { - // send channel registration data as a response to receiving server channel registration data - ClientPlayNetworking.doSend(HandshakePayload.CHANNEL, HandshakePayload.client()); - - ((INetworkHandler)handler).osl$networking$registerChannels(payload.channels); - ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); - - return true; - }); - } -} diff --git a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/PacketFactory.java b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/PacketFactory.java new file mode 100644 index 00000000..2a4f77aa --- /dev/null +++ b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/PacketFactory.java @@ -0,0 +1,11 @@ +package net.ornithemc.osl.networking.impl; + +import net.minecraft.network.packet.Packet; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; + +public interface PacketFactory { + + Packet create(NamespacedIdentifier channel, byte[] data); + +} diff --git a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/access/CustomPayloadPacketAccess.java b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/access/CustomPayloadPacketAccess.java new file mode 100644 index 00000000..9c17038b --- /dev/null +++ b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/access/CustomPayloadPacketAccess.java @@ -0,0 +1,11 @@ +package net.ornithemc.osl.networking.impl.access; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; + +public interface CustomPayloadPacketAccess { + + NamespacedIdentifier osl$networking$getChannel(); + + byte[] osl$networking$getData(); + +} diff --git a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/access/LocalClientPlayerAccess.java b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/access/LocalClientPlayerAccess.java new file mode 100644 index 00000000..1364c7c5 --- /dev/null +++ b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/access/LocalClientPlayerAccess.java @@ -0,0 +1,9 @@ +package net.ornithemc.osl.networking.impl.access; + +import net.minecraft.client.network.handler.ClientNetworkHandler; + +public interface LocalClientPlayerAccess { + + ClientNetworkHandler osl$networking$getNetworkHandler(); + +} diff --git a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/access/NetworkHandlerAccess.java b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/access/NetworkHandlerAccess.java new file mode 100644 index 00000000..81b86b1f --- /dev/null +++ b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/access/NetworkHandlerAccess.java @@ -0,0 +1,17 @@ +package net.ornithemc.osl.networking.impl.access; + +import java.util.Set; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; + +public interface NetworkHandlerAccess { + + boolean osl$networking$canRunOffMainThread(); + + boolean osl$networking$isPlayReady(); + + boolean osl$networking$isPlayReady(NamespacedIdentifier channel); + + void osl$networking$registerChannels(Set channels); + +} diff --git a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/access/TaskRunnerAccess.java b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/access/TaskRunnerAccess.java new file mode 100644 index 00000000..bff1ba39 --- /dev/null +++ b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/access/TaskRunnerAccess.java @@ -0,0 +1,7 @@ +package net.ornithemc.osl.networking.impl.access; + +public interface TaskRunnerAccess { + + boolean osl$networking$submit(Runnable task); + +} diff --git a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java index 29bc2aa0..8ef8c508 100644 --- a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java +++ b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java @@ -1,6 +1,5 @@ package net.ornithemc.osl.networking.impl.client; -import java.io.DataOutputStream; import java.io.IOException; import java.util.LinkedHashMap; import java.util.Map; @@ -10,68 +9,134 @@ import org.apache.logging.log4j.Logger; import net.minecraft.client.Minecraft; -import net.minecraft.client.entity.mob.player.LocalClientPlayerEntity; import net.minecraft.client.network.handler.ClientNetworkHandler; import net.minecraft.network.packet.Packet; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.Channels; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.api.DataStreams; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.ByteArrayListener; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.PayloadListener; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.StreamListener; -import net.ornithemc.osl.networking.impl.CustomPayloadPacket; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; -import net.ornithemc.osl.networking.impl.mixin.client.LocalClientPlayerEntityAccessor; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketBuffers; +import net.ornithemc.osl.networking.api.PacketPayload; +import net.ornithemc.osl.networking.api.client.ClientPacketListener; +import net.ornithemc.osl.networking.impl.PacketFactory; +import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; +import net.ornithemc.osl.networking.impl.access.LocalClientPlayerAccess; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; +import net.ornithemc.osl.networking.impl.access.TaskRunnerAccess; public final class ClientPlayNetworkingImpl { private static final Logger LOGGER = LogManager.getLogger("OSL|Client Play Networking"); + private static PacketFactory packetFactory; private static Minecraft minecraft; + private static Thread thread; + + public static void setUpPacketFactory(PacketFactory factory) { + if (ClientPlayNetworkingImpl.packetFactory != null) { + throw new IllegalStateException("tried to set up client custom payload packet factory when it was already set up!"); + } + + ClientPlayNetworkingImpl.packetFactory = factory; + } public static void setUp(Minecraft minecraft) { if (ClientPlayNetworkingImpl.minecraft == minecraft) { - throw new IllegalStateException("tried to set up client networking when it was already set up!"); + throw new IllegalStateException("tried to set up client play networking when it was already set up!"); + } + if (ClientPlayNetworkingImpl.packetFactory == null) { + throw new IllegalStateException("tried to set up client play networking when no custom payload packet factory was set up!"); } ClientPlayNetworkingImpl.minecraft = minecraft; + ClientPlayNetworkingImpl.thread = Thread.currentThread(); } public static void destroy(Minecraft minecraft) { if (ClientPlayNetworkingImpl.minecraft != minecraft) { - throw new IllegalStateException("tried to destroy client networking when it was not set up!"); + throw new IllegalStateException("tried to destroy client play networking when it was not set up!"); } ClientPlayNetworkingImpl.minecraft = null; + ClientPlayNetworkingImpl.thread = null; } - public static final Map LISTENERS = new LinkedHashMap<>(); + public static final Map CHANNEL_LISTENERS = new LinkedHashMap<>(); - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - registerListenerImpl(channel, (minecraft, handler, data) -> { - T payload = initializer.get(); - payload.read(DataStreams.input(data)); + public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { + registerListener(channel, initializer, listener, false); + } - return listener.handle(minecraft, handler, payload); + public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { + registerListener(channel, initializer, listener, true); + } + + private static void registerListener(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener, boolean async) { + registerListenerImpl(channel, new ChannelListener() { + + @Override + public boolean isAsync() { + return async; + } + + @Override + public boolean handle(Minecraft minecraft, ClientNetworkHandler handler, byte[] bytes) throws IOException { + T payload = initializer.get(); + payload.read(PacketBuffers.wrap(bytes)); + + return listener.handle(minecraft, handler, payload); + } }); } - public static void registerListener(String channel, StreamListener listener) { - registerListenerImpl(channel, (minecraft, handler, data) -> { - return listener.handle(minecraft, handler, DataStreams.input(data)); + public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { + registerListener(channel, listener, false); + } + + public static void registerListenerAsync(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { + registerListener(channel, listener, true); + } + + private static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Buffer listener, boolean async) { + registerListenerImpl(channel, new ChannelListener() { + + @Override + public boolean isAsync() { + return async; + } + + @Override + public boolean handle(Minecraft minecraft, ClientNetworkHandler handler, byte[] bytes) throws IOException { + return listener.handle(minecraft, handler, PacketBuffers.wrap(bytes)); + } }); } - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - registerListenerImpl(channel, listener::handle); + public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { + registerListener(channel, listener, false); + } + + public static void registerListenerAsync(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { + registerListener(channel, listener, true); } - private static void registerListenerImpl(String channel, Listener listener) { - LISTENERS.compute(channel, (key, value) -> { - Channels.validate(channel); + private static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Bytes listener, boolean async) { + registerListenerImpl(channel, new ChannelListener() { + + @Override + public boolean isAsync() { + return async; + } + @Override + public boolean handle(Minecraft minecraft, ClientNetworkHandler handler, byte[] bytes) throws IOException { + return listener.handle(minecraft, handler, bytes); + } + }); + } + + private static void registerListenerImpl(NamespacedIdentifier channel, ChannelListener listener) { + CHANNEL_LISTENERS.compute(channel, (key, value) -> { if (value != null) { throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); } @@ -80,96 +145,127 @@ private static void registerListenerImpl(String channel, Listener listener) { }); } - public static void unregisterListener(String channel) { - LISTENERS.remove(channel); + public static void unregisterListener(NamespacedIdentifier channel) { + CHANNEL_LISTENERS.remove(channel); } - public static boolean handle(Minecraft minecraft, ClientNetworkHandler handler, CustomPayloadPacket packet) { - Listener listener = LISTENERS.get(packet.channel); + public static boolean handlePacket(Minecraft minecraft, ClientNetworkHandler handler, Packet packet) { + CustomPayloadPacketAccess p = (CustomPayloadPacketAccess)packet; + + NamespacedIdentifier channel = p.osl$networking$getChannel(); + ChannelListener listener = CHANNEL_LISTENERS.get(channel); if (listener != null) { - try { - return listener.handle(minecraft, handler, packet.data); - } catch (IOException e) { - LOGGER.warn("error handling custom payload on channel \'" + packet.channel + "\'", e); - return true; + byte[] data = p.osl$networking$getData(); + + if (Thread.currentThread() == thread || listener.isAsync()) { + return handlePayload(minecraft, handler, listener, channel, data); + } else { + return ((TaskRunnerAccess) minecraft).osl$networking$submit(() -> handlePayload(minecraft, handler, listener, channel, data)); } } return false; } - private static ClientNetworkHandler getNetworkHandler() { - LocalClientPlayerEntity player = ((LocalClientPlayerEntity)minecraft.player); - return player != null ? ((LocalClientPlayerEntityAccessor)player).getNetworkHandler() : null; + private static boolean handlePayload(Minecraft minecraft, ClientNetworkHandler handler, ChannelListener listener, NamespacedIdentifier channel, byte[] data) { + try { + return listener.handle(minecraft, handler, data); + } catch (IOException e) { + LOGGER.warn("error handling custom payload on channel \'" + channel + "\'", e); + } + + return true; + } + + private static ClientNetworkHandler networkHandler() { + LocalClientPlayerAccess player = (LocalClientPlayerAccess) minecraft.player; + return player != null ? player.osl$networking$getNetworkHandler() : null; } public static boolean isPlayReady() { - INetworkHandler handler = (INetworkHandler)ClientPlayNetworkingImpl.getNetworkHandler(); + NetworkHandlerAccess handler = (NetworkHandlerAccess) networkHandler(); return handler != null && handler.osl$networking$isPlayReady(); } - public static boolean canSend(String channel) { - INetworkHandler handler = (INetworkHandler)ClientPlayNetworkingImpl.getNetworkHandler(); - return handler != null && handler.osl$networking$isRegisteredChannel(channel); + public static boolean isPlayReady(NamespacedIdentifier channel) { + NetworkHandlerAccess handler = (NetworkHandlerAccess) networkHandler(); + return handler != null && handler.osl$networking$isPlayReady(channel); } - public static void send(String channel, CustomPayload payload) { - if (canSend(channel)) { - doSend(channel, payload); + public static void send(NamespacedIdentifier channel, PacketPayload payload) { + if (isPlayReady(channel)) { + sendInternal(channel, payload); } } - public static void send(String channel, IOConsumer writer) { - if (canSend(channel)) { - doSend(channel, writer); + public static void send(NamespacedIdentifier channel, IOConsumer writer) { + if (isPlayReady(channel)) { + sendInternal(channel, writer); } } - public static void send(String channel, byte[] data) { - if (canSend(channel)) { - doSend(channel, data); + public static void send(NamespacedIdentifier channel, PacketBuffer buffer) { + if (isPlayReady(channel)) { + sendInternal(channel, buffer); } } - public static void doSend(String channel, CustomPayload payload) { - sendPacket(makePacket(channel, payload)); + public static void send(NamespacedIdentifier channel, byte[] bytes) { + if (isPlayReady(channel)) { + sendInternal(channel, bytes); + } + } + + public static void sendNoCheck(NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(channel, payload); } - public static void doSend(String channel, IOConsumer writer) { - sendPacket(makePacket(channel, writer)); + public static void sendNoCheck(NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(channel, writer); } - public static void doSend(String channel, byte[] data) { - sendPacket(makePacket(channel, data)); + public static void sendNoCheck(NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(channel, buffer); } - private static Packet makePacket(String channel, CustomPayload payload) { - return makePacket(channel, payload::write); + public static void sendNoCheck(NamespacedIdentifier channel, byte[] bytes) { + sendInternal(channel, bytes); + } + + private static void sendInternal(NamespacedIdentifier channel, PacketPayload payload) { + try { + sendPacket(channel, PacketBuffers.unwrap(PacketBuffers.make(payload::write))); + } catch (IOException e) { + LOGGER.warn("error writing packet payload to channel \'" + channel + "\'", e); + } } - private static Packet makePacket(String channel, IOConsumer writer) { + private static void sendInternal(NamespacedIdentifier channel, IOConsumer writer) { try { - return new CustomPayloadPacket(channel, DataStreams.output(writer).toByteArray()); + sendPacket(channel, PacketBuffers.unwrap(PacketBuffers.make(writer))); } catch (IOException e) { - LOGGER.warn("error writing custom payload to channel \'" + channel + "\'", e); - return null; + LOGGER.warn("error writing buffer to channel \'" + channel + "\'", e); } } - private static Packet makePacket(String channel, byte[] data) { - return new CustomPayloadPacket(channel, data); + private static void sendInternal(NamespacedIdentifier channel, PacketBuffer buffer) { + sendPacket(channel, PacketBuffers.unwrap(buffer)); } - private static void sendPacket(Packet packet) { - if (packet != null) { - ClientPlayNetworkingImpl.getNetworkHandler().sendPacket(packet); - } + private static void sendInternal(NamespacedIdentifier channel, byte[] bytes) { + sendPacket(channel, bytes); } - private interface Listener { + private static void sendPacket(NamespacedIdentifier channel, byte[] data) { + networkHandler().sendPacket(packetFactory.create(channel, data)); + } + + private interface ChannelListener { + + boolean isAsync(); - boolean handle(Minecraft minecraft, ClientNetworkHandler handler, byte[] data) throws IOException; + boolean handle(Minecraft minecraft, ClientNetworkHandler handler, byte[] bytes) throws IOException; } } diff --git a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/LocalClientPlayerEntityAccessor.java b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/LocalClientPlayerEntityAccessor.java deleted file mode 100644 index d7c7b828..00000000 --- a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/mixin/client/LocalClientPlayerEntityAccessor.java +++ /dev/null @@ -1,16 +0,0 @@ -package net.ornithemc.osl.networking.impl.mixin.client; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Accessor; - -import net.minecraft.client.entity.mob.player.LocalClientPlayerEntity; -import net.minecraft.client.network.handler.ClientNetworkHandler; - -@Mixin(LocalClientPlayerEntity.class) -public interface LocalClientPlayerEntityAccessor { - - @Accessor("networkHandler") - default ClientNetworkHandler getNetworkHandler() { - throw new UnsupportedOperationException(); - } -} diff --git a/libraries/networking/networking-mc12w21a-mc13w39b/build.gradle b/libraries/networking/networking-mcb1.0-mc13w39b/build.gradle similarity index 100% rename from libraries/networking/networking-mc12w21a-mc13w39b/build.gradle rename to libraries/networking/networking-mcb1.0-mc13w39b/build.gradle diff --git a/libraries/networking/networking-mcb1.0-mc13w39b/gradle.properties b/libraries/networking/networking-mcb1.0-mc13w39b/gradle.properties new file mode 100644 index 00000000..41bc8da8 --- /dev/null +++ b/libraries/networking/networking-mcb1.0-mc13w39b/gradle.properties @@ -0,0 +1,8 @@ +environment = * +min_mc_version = b1.0 +max_mc_version = 13w39b +mc_version_range = >=1.0.0-beta.0 <=1.7-alpha.13.39.b + +minecraft_version = 1.5.2 +feather_build = 1 +nests_build = 5 diff --git a/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/PacketBuffer.java b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/PacketBuffer.java new file mode 100644 index 00000000..332c2370 --- /dev/null +++ b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/PacketBuffer.java @@ -0,0 +1,1217 @@ +package net.ornithemc.osl.networking.api; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.channels.FileChannel; +import java.nio.channels.GatheringByteChannel; +import java.nio.channels.ScatteringByteChannel; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.UUID; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufInputStream; +import io.netty.buffer.ByteBufOutputStream; +import io.netty.util.ByteProcessor; + +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtIo; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.NamespacedIdentifiers; + +public class PacketBuffer extends ByteBuf { + + private static final int VAR_VALUE_BITS = 7; + private static final int VAR_VALUE_MASK = 1 << VAR_VALUE_BITS - 1; + private static final int VAR_PARITY_VALUE = 1 << VAR_VALUE_BITS; + private static final int VAR_INT_MAX_BYTES = 5; + private static final int VAR_LONG_MAX_BYTES = 10; + + final ByteBuf delegate; + + public PacketBuffer(ByteBuf delegate) { + this.delegate = delegate; + } + + public int readVarInt() { + int value = 0; + + byte bytes = 0; + byte nextByte = 0; + + do { + nextByte = this.readByte(); + value |= (nextByte & VAR_VALUE_MASK) << bytes++ * VAR_VALUE_BITS; + + if (bytes > VAR_INT_MAX_BYTES) { + throw new RuntimeException("VarInt too big"); + } + } while ((nextByte & VAR_PARITY_VALUE) == VAR_PARITY_VALUE); + + return value; + } + + public long readVarLong() { + long value = 0; + + byte bytes = 0; + byte nextByte = 0; + + do { + nextByte = this.readByte(); + value |= (nextByte & VAR_VALUE_MASK) << bytes++ * VAR_VALUE_BITS; + + if (bytes > VAR_LONG_MAX_BYTES) { + throw new RuntimeException("VarLong too big"); + } + } while ((nextByte & VAR_PARITY_VALUE) == VAR_PARITY_VALUE); + + return value; + } + + public byte[] readByteArray() { + return this.readByteArray(this.readableBytes()); + } + + public byte[] readByteArray(int maxLength) { + int length = this.readVarInt(); + + if (length > maxLength) { + throw new RuntimeException("ByteArray with size " + length + " is bigger than allowed " + maxLength); + } + + byte[] values = new byte[length]; + + for (int i = 0; i < length; i++) { + values[i] = this.readByte(); + } + + return values; + } + + public int[] readIntArray() { + return this.readIntArray(this.readableBytes()); + } + + public int[] readIntArray(int maxLength) { + int length = this.readVarInt(); + + if (length > maxLength) { + throw new RuntimeException("IntArray with size " + length + " is bigger than allowed " + maxLength); + } + + int[] values = new int[length]; + + for (int i = 0; i < length; i++) { + values[i] = this.readVarInt(); + } + + return values; + } + + public long[] readLongArray() { + return this.readLongArray(this.readableBytes() / 8); + } + + public long[] readLongArray(int maxLength) { + int length = this.readVarInt(); + + if (length > maxLength) { + throw new IllegalStateException("LongArray with size " + length + " is bigger than allowed " + maxLength); + } + + long[] values = new long[length]; + + for (int i = 0; i < length; i++) { + values[i] = this.readVarLong(); + } + + return values; + } + + public String readString() { + return this.readString(Short.MAX_VALUE); + } + + public String readString(int maxLength) { + int length = this.readVarInt(); + + if (length > maxLength * 4) { + throw new RuntimeException("The received encoded string buffer length is longer than maximum allowed (" + length + " > " + maxLength * 4 + ")"); + } + if (length < 0) { + throw new RuntimeException("The received encoded string buffer length is less than zero! Weird string!"); + } + + String s = this.toString(this.readerIndex(), length, StandardCharsets.UTF_8); + this.readerIndex(this.readerIndex() + length); + + if (s.length() > maxLength) { + throw new RuntimeException("The received string length is longer than maximum allowed (" + length + " > " + maxLength + ")"); + } + + return s; + } + + public > T readEnum(Class type) { + return type.getEnumConstants()[this.readVarInt()]; + } + + public Date readDate() { + return new Date(this.readLong()); + } + + public UUID readUuid() { + return new UUID( + this.readLong(), + this.readLong() + ); + } + + public NamespacedIdentifier readNamespacedIdentifier() { + return NamespacedIdentifiers.parse(this.readString()); + } + + public NbtCompound readNbtCompound() { + int readerIndex = this.readerIndex(); + byte firstByte = this.readByte(); + + if (firstByte == 0) { + return null; + } else { + this.readerIndex(readerIndex); + + try { + return NbtIo.read(new ByteBufInputStream(this)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + public ByteBuf writeVarInt(int value) { + while ((value & -128) != 0) { + this.writeByte(value & VAR_VALUE_MASK | VAR_PARITY_VALUE); + value >>>= VAR_VALUE_BITS; + } + + this.writeByte(value); + + return this; + } + + public ByteBuf writeVarLong(long value) { + while ((value & -128) != 0) { + this.writeByte((int) (value & VAR_VALUE_MASK) | VAR_PARITY_VALUE); + value >>>= VAR_VALUE_BITS; + } + + this.writeByte((int) value); + + return this; + } + + public ByteBuf writeByteArray(byte[] values) { + this.writeVarInt(values.length); + + for (byte value : values) { + this.writeByte(value); + } + + return this; + } + + public ByteBuf writeIntArray(int[] values) { + this.writeVarInt(values.length); + + for (int value : values) { + this.writeVarInt(value); + } + + return this; + } + + public ByteBuf writeLongArray(long[] values) { + this.writeVarInt(values.length); + + for (long value : values) { + this.writeVarLong(value); + } + + return this; + } + + public ByteBuf writeString(String s) { + return this.writeString(s, Short.MAX_VALUE); + } + + public ByteBuf writeString(String s, int maxLength) { + byte[] bytes = s.getBytes(StandardCharsets.UTF_8); + + if (bytes.length > maxLength) { + throw new RuntimeException("String too big (was " + bytes.length + " bytes encoded, max " + maxLength + ")"); + } + + this.writeByteArray(bytes); + + return this; + } + + public ByteBuf writeEnum(Enum value) { + this.writeVarInt(value.ordinal()); + + return this; + } + + public ByteBuf writeDate(Date date) { + this.writeLong(date.getTime()); + + return this; + } + + public ByteBuf writeUuid(UUID uuid) { + this.writeLong(uuid.getMostSignificantBits()); + this.writeLong(uuid.getLeastSignificantBits()); + + return this; + } + + public ByteBuf writeNamespacedIdentifier(NamespacedIdentifier id) { + return this.writeString(id.toString()); + } + + public ByteBuf writeNbtCompound(NbtCompound nbt) { + if (nbt == null) { + this.writeByte(0); + } else { + try { + NbtIo.write(nbt, new ByteBufOutputStream(this)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + return this; + } + + @Override + public int capacity() { + return this.delegate.capacity(); + } + + @Override + public ByteBuf capacity(int newCapacity) { + return this.delegate.capacity(newCapacity); + } + + @Override + public int maxCapacity() { + return this.delegate.maxCapacity(); + } + + @Override + public ByteBufAllocator alloc() { + return this.delegate.alloc(); + } + + @Override + public ByteOrder order() { + return this.delegate.order(); + } + + @Override + public ByteBuf order(ByteOrder order) { + return this.delegate.order(order); + } + + @Override + public ByteBuf unwrap() { + return this.delegate.unwrap(); + } + + @Override + public boolean isDirect() { + return this.delegate.isDirect(); + } + + @Override + public boolean isReadOnly() { + return this.delegate.isReadOnly(); + } + + @Override + public ByteBuf asReadOnly() { + return this.delegate.asReadOnly(); + } + + @Override + public int readerIndex() { + return this.delegate.readerIndex(); + } + + @Override + public ByteBuf readerIndex(int readerIndex) { + return this.delegate.readerIndex(readerIndex); + } + + @Override + public int writerIndex() { + return this.delegate.writerIndex(); + } + + @Override + public ByteBuf writerIndex(int writerIndex) { + return this.delegate.writerIndex(writerIndex); + } + + @Override + public ByteBuf setIndex(int readerIndex, int writerIndex) { + return this.delegate.setIndex(readerIndex, writerIndex); + } + + @Override + public int readableBytes() { + return this.delegate.readableBytes(); + } + + @Override + public int writableBytes() { + return this.delegate.writableBytes(); + } + + @Override + public int maxWritableBytes() { + return this.delegate.maxWritableBytes(); + } + + @Override + public boolean isReadable() { + return this.delegate.isReadable(); + } + + @Override + public boolean isReadable(int size) { + return this.delegate.isReadable(size); + } + + @Override + public boolean isWritable() { + return this.delegate.isWritable(); + } + + @Override + public boolean isWritable(int size) { + return this.delegate.isWritable(size); + } + + @Override + public ByteBuf clear() { + return this.delegate.clear(); + } + + @Override + public ByteBuf markReaderIndex() { + return this.delegate.markReaderIndex(); + } + + @Override + public ByteBuf resetReaderIndex() { + return this.delegate.resetReaderIndex(); + } + + @Override + public ByteBuf markWriterIndex() { + return this.delegate.markWriterIndex(); + } + + @Override + public ByteBuf resetWriterIndex() { + return this.delegate.resetWriterIndex(); + } + + @Override + public ByteBuf discardReadBytes() { + return this.delegate.discardReadBytes(); + } + + @Override + public ByteBuf discardSomeReadBytes() { + return this.delegate.discardSomeReadBytes(); + } + + @Override + public ByteBuf ensureWritable(int minWritableBytes) { + return this.delegate.ensureWritable(minWritableBytes); + } + + @Override + public int ensureWritable(int minWritableBytes, boolean force) { + return this.delegate.ensureWritable(minWritableBytes, force); + } + + @Override + public boolean getBoolean(int index) { + return this.delegate.getBoolean(index); + } + + @Override + public byte getByte(int index) { + return this.delegate.getByte(index); + } + + @Override + public short getUnsignedByte(int index) { + return this.delegate.getUnsignedByte(index); + } + + @Override + public short getShort(int index) { + return this.delegate.getShort(index); + } + + @Override + public short getShortLE(int index) { + return this.delegate.getShortLE(index); + } + + @Override + public int getUnsignedShort(int index) { + return this.delegate.getUnsignedShort(index); + } + + @Override + public int getUnsignedShortLE(int index) { + return this.delegate.getUnsignedShortLE(index); + } + + @Override + public int getMedium(int index) { + return this.delegate.getMedium(index); + } + + @Override + public int getMediumLE(int index) { + return this.delegate.getMediumLE(index); + } + + @Override + public int getUnsignedMedium(int index) { + return this.delegate.getUnsignedMedium(index); + } + + @Override + public int getUnsignedMediumLE(int index) { + return this.delegate.getUnsignedMediumLE(index); + } + + @Override + public int getInt(int index) { + return this.delegate.getInt(index); + } + + @Override + public int getIntLE(int index) { + return this.delegate.getIntLE(index); + } + + @Override + public long getUnsignedInt(int index) { + return this.delegate.getUnsignedInt(index); + } + + @Override + public long getUnsignedIntLE(int index) { + return this.delegate.getUnsignedIntLE(index); + } + + @Override + public long getLong(int index) { + return this.delegate.getLong(index); + } + + @Override + public long getLongLE(int index) { + return this.delegate.getLongLE(index); + } + + @Override + public char getChar(int index) { + return this.delegate.getChar(index); + } + + @Override + public float getFloat(int index) { + return this.delegate.getFloat(index); + } + + @Override + public double getDouble(int index) { + return this.delegate.getDouble(index); + } + + @Override + public ByteBuf getBytes(int index, ByteBuf dst) { + return this.delegate.getBytes(index, dst); + } + + @Override + public ByteBuf getBytes(int index, ByteBuf dst, int length) { + return this.delegate.getBytes(index, dst, length); + } + + @Override + public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) { + return this.delegate.getBytes(index, dst, dstIndex, length); + } + + @Override + public ByteBuf getBytes(int index, byte[] dst) { + return this.delegate.getBytes(index, dst); + } + + @Override + public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) { + return this.delegate.getBytes(index, dst, dstIndex, length); + } + + @Override + public ByteBuf getBytes(int index, ByteBuffer dst) { + return this.delegate.getBytes(index, dst); + } + + @Override + public ByteBuf getBytes(int index, OutputStream out, int length) throws IOException { + return this.delegate.getBytes(index, out, length); + } + + @Override + public int getBytes(int index, GatheringByteChannel out, int length) throws IOException { + return this.delegate.getBytes(index, out, length); + } + + @Override + public int getBytes(int index, FileChannel out, long position, int length) throws IOException { + return this.delegate.getBytes(index, out, position, length); + } + + @Override + public CharSequence getCharSequence(int index, int length, Charset charset) { + return this.delegate.getCharSequence(index, length, charset); + } + + @Override + public ByteBuf setBoolean(int index, boolean value) { + return this.delegate.setBoolean(index, value); + } + + @Override + public ByteBuf setByte(int index, int value) { + return this.delegate.setByte(index, value); + } + + @Override + public ByteBuf setShort(int index, int value) { + return this.delegate.setShort(index, value); + } + + @Override + public ByteBuf setShortLE(int index, int value) { + return this.delegate.setShortLE(index, value); + } + + @Override + public ByteBuf setMedium(int index, int value) { + return this.delegate.setMedium(index, value); + } + + @Override + public ByteBuf setMediumLE(int index, int value) { + return this.delegate.setMediumLE(index, value); + } + + @Override + public ByteBuf setInt(int index, int value) { + return this.delegate.setInt(index, value); + } + + @Override + public ByteBuf setIntLE(int index, int value) { + return this.delegate.setIntLE(index, value); + } + + @Override + public ByteBuf setLong(int index, long value) { + return this.delegate.setLong(index, value); + } + + @Override + public ByteBuf setLongLE(int index, long value) { + return this.delegate.setLongLE(index, value); + } + + @Override + public ByteBuf setChar(int index, int value) { + return this.delegate.setChar(index, value); + } + + @Override + public ByteBuf setFloat(int index, float value) { + return this.delegate.setFloat(index, value); + } + + @Override + public ByteBuf setDouble(int index, double value) { + return this.delegate.setDouble(index, value); + } + + @Override + public ByteBuf setBytes(int index, ByteBuf src) { + return this.delegate.setBytes(index, src); + } + + @Override + public ByteBuf setBytes(int index, ByteBuf src, int length) { + return this.delegate.setBytes(index, src, length); + } + + @Override + public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) { + return this.delegate.setBytes(index, src, srcIndex, length); + } + + @Override + public ByteBuf setBytes(int index, byte[] src) { + return this.delegate.setBytes(index, src); + } + + @Override + public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) { + return this.delegate.setBytes(index, src, srcIndex, length); + } + + @Override + public ByteBuf setBytes(int index, ByteBuffer src) { + return this.delegate.setBytes(index, src); + } + + @Override + public int setBytes(int index, InputStream in, int length) throws IOException { + return this.delegate.setBytes(index, in, length); + } + + @Override + public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException { + return this.delegate.setBytes(index, in, length); + } + + @Override + public int setBytes(int index, FileChannel in, long position, int length) throws IOException { + return this.delegate.setBytes(index, in, position, length); + } + + @Override + public ByteBuf setZero(int index, int length) { + return this.delegate.setZero(index, length); + } + + @Override + public int setCharSequence(int index, CharSequence sequence, Charset charset) { + return this.delegate.setCharSequence(index, sequence, charset); + } + + @Override + public boolean readBoolean() { + return this.delegate.readBoolean(); + } + + @Override + public byte readByte() { + return this.delegate.readByte(); + } + + @Override + public short readUnsignedByte() { + return this.delegate.readUnsignedByte(); + } + + @Override + public short readShort() { + return this.delegate.readShort(); + } + + @Override + public short readShortLE() { + return this.delegate.readShortLE(); + } + + @Override + public int readUnsignedShort() { + return this.delegate.readUnsignedShort(); + } + + @Override + public int readUnsignedShortLE() { + return this.delegate.readUnsignedShortLE(); + } + + @Override + public int readMedium() { + return this.delegate.readMedium(); + } + + @Override + public int readMediumLE() { + return this.delegate.readMediumLE(); + } + + @Override + public int readUnsignedMedium() { + return this.delegate.readUnsignedMedium(); + } + + @Override + public int readUnsignedMediumLE() { + return this.delegate.readUnsignedMediumLE(); + } + + @Override + public int readInt() { + return this.delegate.readInt(); + } + + @Override + public int readIntLE() { + return this.delegate.readIntLE(); + } + + @Override + public long readUnsignedInt() { + return this.delegate.readUnsignedInt(); + } + + @Override + public long readUnsignedIntLE() { + return this.delegate.readUnsignedIntLE(); + } + + @Override + public long readLong() { + return this.delegate.readLong(); + } + + @Override + public long readLongLE() { + return this.delegate.readLongLE(); + } + + @Override + public char readChar() { + return this.delegate.readChar(); + } + + @Override + public float readFloat() { + return this.delegate.readFloat(); + } + + @Override + public double readDouble() { + return this.delegate.readDouble(); + } + + @Override + public ByteBuf readBytes(int length) { + return this.delegate.readBytes(length); + } + + @Override + public ByteBuf readSlice(int length) { + return this.delegate.readSlice(length); + } + + @Override + public ByteBuf readRetainedSlice(int length) { + return this.delegate.readRetainedSlice(length); + } + + @Override + public ByteBuf readBytes(ByteBuf dst) { + return this.delegate.readBytes(dst); + } + + @Override + public ByteBuf readBytes(ByteBuf dst, int length) { + return this.delegate.readBytes(dst, length); + } + + @Override + public ByteBuf readBytes(ByteBuf dst, int dstIndex, int length) { + return this.delegate.readBytes(dst, dstIndex, length); + } + + @Override + public ByteBuf readBytes(byte[] dst) { + return this.delegate.readBytes(dst); + } + + @Override + public ByteBuf readBytes(byte[] dst, int dstIndex, int length) { + return this.delegate.readBytes(dst, dstIndex, length); + } + + @Override + public ByteBuf readBytes(ByteBuffer dst) { + return this.delegate.readBytes(dst); + } + + @Override + public ByteBuf readBytes(OutputStream out, int length) throws IOException { + return this.delegate.readBytes(out, length); + } + + @Override + public int readBytes(GatheringByteChannel out, int length) throws IOException { + return this.delegate.readBytes(out, length); + } + + @Override + public CharSequence readCharSequence(int length, Charset charset) { + return this.delegate.readCharSequence(length, charset); + } + + @Override + public int readBytes(FileChannel out, long position, int length) throws IOException { + return this.delegate.readBytes(out, position, length); + } + + @Override + public ByteBuf skipBytes(int length) { + return this.delegate.skipBytes(length); + } + + @Override + public ByteBuf writeBoolean(boolean value) { + return this.delegate.writeBoolean(value); + } + + @Override + public ByteBuf writeByte(int value) { + return this.delegate.writeByte(value); + } + + @Override + public ByteBuf writeShort(int value) { + return this.delegate.writeShort(value); + } + + @Override + public ByteBuf writeShortLE(int value) { + return this.delegate.writeShortLE(value); + } + + @Override + public ByteBuf writeMedium(int value) { + return this.delegate.writeMedium(value); + } + + @Override + public ByteBuf writeMediumLE(int value) { + return this.delegate.writeMediumLE(value); + } + + @Override + public ByteBuf writeInt(int value) { + return this.delegate.writeInt(value); + } + + @Override + public ByteBuf writeIntLE(int value) { + return this.delegate.writeIntLE(value); + } + + @Override + public ByteBuf writeLong(long value) { + return this.delegate.writeLong(value); + } + + @Override + public ByteBuf writeLongLE(long value) { + return this.delegate.writeLongLE(value); + } + + @Override + public ByteBuf writeChar(int value) { + return this.delegate.writeChar(value); + } + + @Override + public ByteBuf writeFloat(float value) { + return this.delegate.writeFloat(value); + } + + @Override + public ByteBuf writeDouble(double value) { + return this.delegate.writeDouble(value); + } + + @Override + public ByteBuf writeBytes(ByteBuf src) { + return this.delegate.writeBytes(src); + } + + @Override + public ByteBuf writeBytes(ByteBuf src, int length) { + return this.delegate.writeBytes(src, length); + } + + @Override + public ByteBuf writeBytes(ByteBuf src, int srcIndex, int length) { + return this.delegate.writeBytes(src, srcIndex, length); + } + + @Override + public ByteBuf writeBytes(byte[] src) { + return this.delegate.writeBytes(src); + } + + @Override + public ByteBuf writeBytes(byte[] src, int srcIndex, int length) { + return this.delegate.writeBytes(src, srcIndex, length); + } + + @Override + public ByteBuf writeBytes(ByteBuffer src) { + return this.delegate.writeBytes(src); + } + + @Override + public int writeBytes(InputStream in, int length) throws IOException { + return this.delegate.writeBytes(in, length); + } + + @Override + public int writeBytes(ScatteringByteChannel in, int length) throws IOException { + return this.delegate.writeBytes(in, length); + } + + @Override + public int writeBytes(FileChannel in, long position, int length) throws IOException { + return this.delegate.writeBytes(in, position, length); + } + + @Override + public ByteBuf writeZero(int length) { + return this.delegate.writeZero(length); + } + + @Override + public int writeCharSequence(CharSequence sequence, Charset charset) { + return this.delegate.writeCharSequence(sequence, charset); + } + + @Override + public int indexOf(int fromIndex, int toIndex, byte value) { + return this.delegate.indexOf(fromIndex, toIndex, value); + } + + @Override + public int bytesBefore(byte value) { + return this.delegate.bytesBefore(value); + } + + @Override + public int bytesBefore(int length, byte value) { + return this.delegate.bytesBefore(length, value); + } + + @Override + public int bytesBefore(int index, int length, byte value) { + return this.delegate.bytesBefore(index, length, value); + } + + @Override + public int forEachByte(ByteProcessor processor) { + return this.delegate.forEachByte(processor); + } + + @Override + public int forEachByte(int index, int length, ByteProcessor processor) { + return this.delegate.forEachByte(index, length, processor); + } + + @Override + public int forEachByteDesc(ByteProcessor processor) { + return this.delegate.forEachByteDesc(processor); + } + + @Override + public int forEachByteDesc(int index, int length, ByteProcessor processor) { + return this.delegate.forEachByteDesc(index, length, processor); + } + + @Override + public ByteBuf copy() { + return this.delegate.copy(); + } + + @Override + public ByteBuf copy(int index, int length) { + return this.delegate.copy(index, length); + } + + @Override + public ByteBuf slice() { + return this.delegate.slice(); + } + + @Override + public ByteBuf retainedSlice() { + return this.delegate.retainedSlice(); + } + + @Override + public ByteBuf slice(int index, int length) { + return this.delegate.slice(index, length); + } + + @Override + public ByteBuf retainedSlice(int index, int length) { + return this.delegate.retainedSlice(index, length); + } + + @Override + public ByteBuf duplicate() { + return this.delegate.duplicate(); + } + + @Override + public ByteBuf retainedDuplicate() { + return this.delegate.retainedDuplicate(); + } + + @Override + public int nioBufferCount() { + return this.delegate.nioBufferCount(); + } + + @Override + public ByteBuffer nioBuffer() { + return this.delegate.nioBuffer(); + } + + @Override + public ByteBuffer nioBuffer(int index, int length) { + return this.delegate.nioBuffer(index, length); + } + + @Override + public ByteBuffer internalNioBuffer(int index, int length) { + return this.delegate.internalNioBuffer(index, length); + } + + @Override + public ByteBuffer[] nioBuffers() { + return this.delegate.nioBuffers(); + } + + @Override + public ByteBuffer[] nioBuffers(int index, int length) { + return this.delegate.nioBuffers(index, length); + } + + @Override + public boolean hasArray() { + return this.delegate.hasArray(); + } + + @Override + public byte[] array() { + return this.delegate.array(); + } + + @Override + public int arrayOffset() { + return this.delegate.arrayOffset(); + } + + @Override + public boolean hasMemoryAddress() { + return this.delegate.hasMemoryAddress(); + } + + @Override + public long memoryAddress() { + return this.delegate.memoryAddress(); + } + + @Override + public String toString(Charset charset) { + return this.delegate.toString(charset); + } + + @Override + public String toString(int index, int length, Charset charset) { + return this.delegate.toString(index, length, charset); + } + + @Override + public int hashCode() { + return this.delegate.hashCode(); + } + + @Override + public boolean equals(Object o) { + return this.delegate.equals(o); + } + + @Override + public int compareTo(ByteBuf o) { + return this.delegate.compareTo(o); + } + + @Override + public String toString() { + return this.delegate.toString(); + } + + @Override + public ByteBuf retain(int increment) { + return this.delegate.retain(increment); + } + + @Override + public ByteBuf retain() { + return this.delegate.retain(); + } + + @Override + public ByteBuf touch() { + return this.delegate.touch(); + } + + @Override + public ByteBuf touch(Object hint) { + return this.delegate.touch(hint); + } + + @Override + public int refCnt() { + return this.delegate.refCnt(); + } + + @Override + public boolean release() { + return this.delegate.release(); + } + + @Override + public boolean release(int decrement) { + return this.delegate.release(decrement); + } +} diff --git a/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/PacketBuffers.java b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/PacketBuffers.java new file mode 100644 index 00000000..a9e6ccc8 --- /dev/null +++ b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/PacketBuffers.java @@ -0,0 +1,35 @@ +package net.ornithemc.osl.networking.api; + +import java.io.IOException; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; + +import net.ornithemc.osl.core.api.util.function.IOConsumer; + +public final class PacketBuffers { + + public static PacketBuffer make() { + return wrapped(Unpooled.buffer()); + } + + public static PacketBuffer make(IOConsumer writer) throws IOException { + PacketBuffer buffer = make(); + writer.accept(buffer); + return buffer; + } + + public static PacketBuffer wrap(byte[] bytes) { + return wrapped(Unpooled.wrappedBuffer(bytes)); + } + + public static byte[] unwrap(PacketBuffer buffer) { + byte[] bytes = new byte[buffer.writerIndex()]; + buffer.getBytes(0, bytes); + return bytes; + } + + public static PacketBuffer wrapped(ByteBuf buffer) { + return new PacketBuffer(buffer); + } +} diff --git a/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/PacketPayload.java b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/PacketPayload.java new file mode 100644 index 00000000..7f7835e7 --- /dev/null +++ b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/PacketPayload.java @@ -0,0 +1,11 @@ +package net.ornithemc.osl.networking.api; + +import java.io.IOException; + +public interface PacketPayload { + + void read(PacketBuffer buffer) throws IOException; + + void write(PacketBuffer buffer) throws IOException; + +} diff --git a/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java similarity index 100% rename from libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java rename to libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java diff --git a/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPacketListener.java b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPacketListener.java new file mode 100644 index 00000000..4b9f15d4 --- /dev/null +++ b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPacketListener.java @@ -0,0 +1,31 @@ +package net.ornithemc.osl.networking.api.client; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.network.handler.ClientNetworkHandler; + +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketPayload; + +public interface ClientPacketListener { + + /** + * Receive incoming data from the server. + * + * @return + * Whether the data is consumed. Should only return {@code false} if the + * data is completely ignored. + */ + boolean handle(Minecraft minecraft, ClientNetworkHandler handler, T data); + + @FunctionalInterface + public interface Payload extends ClientPacketListener { + } + + @FunctionalInterface + public interface Buffer extends ClientPacketListener { + } + + @FunctionalInterface + public interface Bytes extends ClientPacketListener { + } +} diff --git a/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java new file mode 100644 index 00000000..06d6ff52 --- /dev/null +++ b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java @@ -0,0 +1,153 @@ +package net.ornithemc.osl.networking.api.client; + +import java.util.function.Supplier; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.function.IOConsumer; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketPayload; +import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; + +public final class ClientPlayNetworking { + + /** + * Register a listener to receive data from the server through the given channel. + * This listener will only be called from the main thread. + */ + public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { + ClientPlayNetworkingImpl.registerListener(channel, initializer, listener); + } + + /** + * Register a listener to receive data from the server through the given channel. + * This listener may be called off the main thread. + */ + public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { + ClientPlayNetworkingImpl.registerListenerAsync(channel, initializer, listener); + } + + /** + * Register a listener to receive data from the server through the given channel. + * This listener will only be called from the main thread. + */ + public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { + ClientPlayNetworkingImpl.registerListener(channel, listener); + } + + /** + * Register a listener to receive data from the server through the given channel. + * This listener may be called off the main thread. + */ + public static void registerListenerAsync(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { + ClientPlayNetworkingImpl.registerListenerAsync(channel, listener); + } + + /** + * Register a listener to receive data from the server through the given channel. + * This listener will only be called from the main thread. + */ + public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { + ClientPlayNetworkingImpl.registerListener(channel, listener); + } + + /** + * Register a listener to receive data from the server through the given channel. + * This listener may be called off the main thread. + */ + public static void registerListenerAsync(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { + ClientPlayNetworkingImpl.registerListenerAsync(channel, listener); + } + + /** + * Remove the listener registered to the given channel. + */ + public static void unregisterListener(NamespacedIdentifier channel) { + ClientPlayNetworkingImpl.unregisterListener(channel); + } + + /** + * Check whether the connection is ready for data to be sent to the server. + */ + public static boolean isPlayReady() { + return ClientPlayNetworkingImpl.isPlayReady(); + } + + /** + * Check whether the given channel is open for data to be sent through it. + * This method will return {@code false} if the client is not connected to a + * server, or if the server has no listeners for the given channel. + */ + public static boolean isPlayReady(NamespacedIdentifier channel) { + return ClientPlayNetworkingImpl.isPlayReady(channel); + } + + /** + * Send a packet to the server through the given channel. The payload will + * only be written if the channel is open. + */ + public static void send(NamespacedIdentifier channel, PacketPayload payload) { + ClientPlayNetworkingImpl.send(channel, payload); + } + + /** + * Send a packet to the server through the given channel. The writer will + * only be called if the channel is open. + */ + public static void send(NamespacedIdentifier channel, IOConsumer writer) { + ClientPlayNetworkingImpl.send(channel, writer); + } + + /** + * Send a packet to the server through the given channel. + */ + public static void send(NamespacedIdentifier channel, PacketBuffer buffer) { + ClientPlayNetworkingImpl.send(channel, buffer); + } + + /** + * Send a packet to the server through the given channel. + */ + public static void send(NamespacedIdentifier channel, byte[] bytes) { + ClientPlayNetworkingImpl.send(channel, bytes); + } + + /** + * Send a packet to the server through the given channel, without checking + * whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the server. + */ + public static void sendNoCheck(NamespacedIdentifier channel, PacketPayload payload) { + ClientPlayNetworkingImpl.sendNoCheck(channel, payload); + } + + /** + * Send a packet to the server through the given channel, without checking + * whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the server. + */ + public static void sendNoCheck(NamespacedIdentifier channel, IOConsumer writer) { + ClientPlayNetworkingImpl.sendNoCheck(channel, writer); + } + + /** + * Send a packet to the server through the given channel, without checking + * whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the server. + */ + public static void sendNoCheck(NamespacedIdentifier channel, PacketBuffer buffer) { + ClientPlayNetworkingImpl.sendNoCheck(channel, buffer); + } + + /** + * Send a packet to the server through the given channel, without checking + * whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the server. + */ + public static void sendNoCheck(NamespacedIdentifier channel, byte[] bytes) { + ClientPlayNetworkingImpl.sendNoCheck(channel, bytes); + } +} diff --git a/libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java similarity index 100% rename from libraries/networking/networking-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java rename to libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java diff --git a/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java new file mode 100644 index 00000000..1ec5a4f0 --- /dev/null +++ b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java @@ -0,0 +1,32 @@ +package net.ornithemc.osl.networking.api.server; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.entity.mob.player.ServerPlayerEntity; +import net.minecraft.server.network.handler.ServerPlayNetworkHandler; + +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketPayload; + +public interface ServerPacketListener { + + /** + * Receive incoming data from the client. + * + * @return + * Whether the data is consumed. Should only return {@code false} if the + * data is completely ignored. + */ + boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, T data); + + @FunctionalInterface + public interface Payload extends ServerPacketListener { + } + + @FunctionalInterface + public interface Buffer extends ServerPacketListener { + } + + @FunctionalInterface + public interface Bytes extends ServerPacketListener { + } +} diff --git a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java similarity index 52% rename from libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java rename to libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java index ecfc060e..c46df829 100644 --- a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java +++ b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java @@ -1,15 +1,13 @@ package net.ornithemc.osl.networking.api.server; -import java.io.IOException; import java.util.function.Supplier; -import net.minecraft.network.PacketByteBuf; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.entity.living.player.ServerPlayerEntity; -import net.minecraft.server.network.handler.ServerPlayNetworkHandler; +import net.minecraft.server.entity.mob.player.ServerPlayerEntity; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.CustomPayload; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketPayload; import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; public final class ServerPlayNetworking { @@ -17,34 +15,55 @@ public final class ServerPlayNetworking { /** * Register a listener to receive data from the server through the given channel. * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. */ - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { + public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { ServerPlayNetworkingImpl.registerListener(channel, initializer, listener); } + /** + * Register a listener to receive data from the server through the given channel. + * This listener may be called off the main thread. + */ + public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { + ServerPlayNetworkingImpl.registerListenerAsync(channel, initializer, listener); + } + /** * Register a listener to receive data from the server through the given channel. * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. */ - public static void registerListener(String channel, ByteBufListener listener) { + public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { ServerPlayNetworkingImpl.registerListener(channel, listener); } + /** + * Register a listener to receive data from the server through the given channel. + * This listener may be called off the main thread. + */ + public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { + ServerPlayNetworkingImpl.registerListenerAsync(channel, listener); + } + /** * Register a listener to receive data from the server through the given channel. * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. */ - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - ServerPlayNetworkingImpl.registerListenerRaw(channel, listener); + public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { + ServerPlayNetworkingImpl.registerListener(channel, listener); + } + + /** + * Register a listener to receive data from the server through the given channel. + * This listener may be called off the main thread. + */ + public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { + ServerPlayNetworkingImpl.registerListenerAsync(channel, listener); } /** * Remove the listener registered to the given channel. */ - public static void unregisterListener(String channel) { + public static void unregisterListener(NamespacedIdentifier channel) { ServerPlayNetworkingImpl.unregisterListener(channel); } @@ -56,19 +75,19 @@ public static boolean isPlayReady(ServerPlayerEntity player) { } /** - * Check whether the given channel is open for data to be sent through it. + * Check whether the given channel is ready for data to be sent through it. * This method will return {@code false} if the client has no listeners for * the given channel. */ - public static boolean canSend(ServerPlayerEntity player, String channel) { - return ServerPlayNetworkingImpl.canSend(player, channel); + public static boolean isPlayReady(ServerPlayerEntity player, NamespacedIdentifier channel) { + return ServerPlayNetworkingImpl.isPlayReady(player, channel); } /** * Send a packet to the given player through the given channel. The payload * will only be written if the channel is open. */ - public static void send(ServerPlayerEntity player, String channel, CustomPayload payload) { + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, PacketPayload payload) { ServerPlayNetworkingImpl.send(player, channel, payload); } @@ -76,29 +95,29 @@ public static void send(ServerPlayerEntity player, String channel, CustomPayload * Send a packet to the given player through the given channel. The writer * will only be called if the channel is open. */ - public static void send(ServerPlayerEntity player, String channel, IOConsumer writer) { + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, IOConsumer writer) { ServerPlayNetworkingImpl.send(player, channel, writer); } /** * Send a packet to the given player through the given channel. */ - public static void send(ServerPlayerEntity player, String channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.send(player, channel, data); + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, PacketBuffer buffer) { + ServerPlayNetworkingImpl.send(player, channel, buffer); } /** * Send a packet to the given player through the given channel. */ - public static void send(ServerPlayerEntity player, String channel, byte[] data) { - ServerPlayNetworkingImpl.send(player, channel, data); + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, byte[] bytes) { + ServerPlayNetworkingImpl.send(player, channel, bytes); } /** * Send a packet to the given players through the given channel. The payload * will only be written if the channel is open for at least one player. */ - public static void send(Iterable players, String channel, CustomPayload payload) { + public static void send(Iterable players, NamespacedIdentifier channel, PacketPayload payload) { ServerPlayNetworkingImpl.send(players, channel, payload); } @@ -106,22 +125,22 @@ public static void send(Iterable players, String channel, Cu * Send a packet to the given players through the given channel. The writer * will only be called if the channel is open for at least one player. */ - public static void send(Iterable players, String channel, IOConsumer writer) { + public static void send(Iterable players, NamespacedIdentifier channel, IOConsumer writer) { ServerPlayNetworkingImpl.send(players, channel, writer); } /** * Send a packet to the given players through the given channel. */ - public static void send(Iterable players, String channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.send(players, channel, data); + public static void send(Iterable players, NamespacedIdentifier channel, PacketBuffer buffer) { + ServerPlayNetworkingImpl.send(players, channel, buffer); } /** * Send a packet to the given players through the given channel. */ - public static void send(Iterable players, String channel, byte[] data) { - ServerPlayNetworkingImpl.send(players, channel, data); + public static void send(Iterable players, NamespacedIdentifier channel, byte[] bytes) { + ServerPlayNetworkingImpl.send(players, channel, bytes); } /** @@ -129,7 +148,7 @@ public static void send(Iterable players, String channel, by * channel. The payload will only be written if the channel is open for at * least one player. */ - public static void send(int dimension, String channel, CustomPayload payload) { + public static void send(int dimension, NamespacedIdentifier channel, PacketPayload payload) { ServerPlayNetworkingImpl.send(dimension, channel, payload); } @@ -138,7 +157,7 @@ public static void send(int dimension, String channel, CustomPayload payload) { * channel. The writer will only be called if the channel is open for at * least one player. */ - public static void send(int dimension, String channel, IOConsumer writer) { + public static void send(int dimension, NamespacedIdentifier channel, IOConsumer writer) { ServerPlayNetworkingImpl.send(dimension, channel, writer); } @@ -146,23 +165,23 @@ public static void send(int dimension, String channel, IOConsumer * Send a packet to the players in the given dimension through the given * channel. */ - public static void send(int dimension, String channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.send(dimension, channel, data); + public static void send(int dimension, NamespacedIdentifier channel, PacketBuffer buffer) { + ServerPlayNetworkingImpl.send(dimension, channel, buffer); } /** * Send a packet to the players in the given dimension through the given * channel. */ - public static void send(int dimension, String channel, byte[] data) { - ServerPlayNetworkingImpl.send(dimension, channel, data); + public static void send(int dimension, NamespacedIdentifier channel, byte[] bytes) { + ServerPlayNetworkingImpl.send(dimension, channel, bytes); } /** * Send a packet to all players through the given channel. The payload will * only be written if the channel is open for at least one player. */ - public static void send(String channel, CustomPayload payload) { + public static void send(NamespacedIdentifier channel, PacketPayload payload) { ServerPlayNetworkingImpl.send(channel, payload); } @@ -170,22 +189,22 @@ public static void send(String channel, CustomPayload payload) { * Send a packet to all players through the given channel. The writer will * only be called if the channel is open for at least one player. */ - public static void send(String channel, IOConsumer writer) { + public static void send(NamespacedIdentifier channel, IOConsumer writer) { ServerPlayNetworkingImpl.send(channel, writer); } /** * Send a packet to all players through the given channel. */ - public static void send(String channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.send(channel, data); + public static void send(NamespacedIdentifier channel, PacketBuffer buffer) { + ServerPlayNetworkingImpl.send(channel, buffer); } /** * Send a packet to all players through the given channel. */ - public static void send(String channel, byte[] data) { - ServerPlayNetworkingImpl.send(channel, data); + public static void send(NamespacedIdentifier channel, byte[] bytes) { + ServerPlayNetworkingImpl.send(channel, bytes); } /** @@ -194,8 +213,8 @@ public static void send(String channel, byte[] data) { * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(ServerPlayerEntity player, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(player, channel, payload); + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, PacketPayload payload) { + ServerPlayNetworkingImpl.sendNoCheck(player, channel, payload); } /** @@ -204,8 +223,8 @@ public static void doSend(ServerPlayerEntity player, String channel, CustomPaylo * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(ServerPlayerEntity player, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(player, channel, writer); + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, IOConsumer writer) { + ServerPlayNetworkingImpl.sendNoCheck(player, channel, writer); } /** @@ -214,8 +233,8 @@ public static void doSend(ServerPlayerEntity player, String channel, IOConsumer< * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(ServerPlayerEntity player, String channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.doSend(player, channel, data); + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, PacketBuffer buffer) { + ServerPlayNetworkingImpl.sendNoCheck(player, channel, buffer); } /** @@ -224,8 +243,8 @@ public static void doSend(ServerPlayerEntity player, String channel, PacketByteB * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(ServerPlayerEntity player, String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(player, channel, data); + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, byte[] bytes) { + ServerPlayNetworkingImpl.sendNoCheck(player, channel, bytes); } /** @@ -234,8 +253,8 @@ public static void doSend(ServerPlayerEntity player, String channel, byte[] data * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(Iterable players, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(players, channel, payload); + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, PacketPayload payload) { + ServerPlayNetworkingImpl.sendNoCheck(players, channel, payload); } /** @@ -244,8 +263,8 @@ public static void doSend(Iterable players, String channel, * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(Iterable players, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(players, channel, writer); + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, IOConsumer writer) { + ServerPlayNetworkingImpl.sendNoCheck(players, channel, writer); } /** @@ -254,8 +273,8 @@ public static void doSend(Iterable players, String channel, * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(Iterable players, String channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.doSend(players, channel, data); + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, PacketBuffer buffer) { + ServerPlayNetworkingImpl.sendNoCheck(players, channel, buffer); } /** @@ -264,8 +283,8 @@ public static void doSend(Iterable players, String channel, * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(Iterable players, String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(players, channel, data); + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, byte[] bytes) { + ServerPlayNetworkingImpl.sendNoCheck(players, channel, bytes); } /** @@ -274,8 +293,8 @@ public static void doSend(Iterable players, String channel, * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(int dimension, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(dimension, channel, payload); + public static void sendNoCheck(int dimension, NamespacedIdentifier channel, PacketPayload payload) { + ServerPlayNetworkingImpl.sendNoCheck(dimension, channel, payload); } /** @@ -284,8 +303,8 @@ public static void doSend(int dimension, String channel, CustomPayload payload) * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(int dimension, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(dimension, channel, writer); + public static void sendNoCheck(int dimension, NamespacedIdentifier channel, IOConsumer writer) { + ServerPlayNetworkingImpl.sendNoCheck(dimension, channel, writer); } /** @@ -294,8 +313,8 @@ public static void doSend(int dimension, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(channel, writer); + public static void sendNoCheck(NamespacedIdentifier channel, IOConsumer writer) { + ServerPlayNetworkingImpl.sendNoCheck(channel, writer); } /** @@ -334,8 +353,8 @@ public static void doSend(String channel, IOConsumer writer) { * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(String channel, PacketByteBuf data) { - ServerPlayNetworkingImpl.doSend(channel, data); + public static void sendNoCheck(NamespacedIdentifier channel, PacketBuffer buffer) { + ServerPlayNetworkingImpl.sendNoCheck(channel, buffer); } /** @@ -344,46 +363,7 @@ public static void doSend(String channel, PacketByteBuf data) { * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(channel, data); - } - - public interface PayloadListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, T payload) throws IOException; - - } - - public interface ByteBufListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, PacketByteBuf data) throws IOException; - - } - - public interface ByteArrayListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] data) throws IOException; - + public static void sendNoCheck(NamespacedIdentifier channel, byte[] bytes) { + ServerPlayNetworkingImpl.sendNoCheck(channel, bytes); } } diff --git a/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/Connections.java b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/Connections.java new file mode 100644 index 00000000..836dd8ed --- /dev/null +++ b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/Connections.java @@ -0,0 +1,22 @@ +package net.ornithemc.osl.networking.impl; + +import net.minecraft.network.PacketHandler; +import net.minecraft.network.packet.Packet; + +import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; + +public final class Connections { + + public static boolean checkAsyncHandling(Packet packet, PacketHandler listener) { + boolean handleAsync = packet instanceof CustomPayloadPacketAccess + && listener instanceof NetworkHandlerAccess + && ((NetworkHandlerAccess) listener).osl$networking$canRunOffMainThread(); + + if (handleAsync) { + packet.handle(listener); + } + + return handleAsync; + } +} diff --git a/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java new file mode 100644 index 00000000..27d46bc9 --- /dev/null +++ b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java @@ -0,0 +1,61 @@ +package net.ornithemc.osl.networking.impl; + +import java.io.IOException; +import java.util.LinkedHashSet; +import java.util.Set; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.api.ChannelIdentifiers; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketPayload; +import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; +import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; + +public class HandshakePayload implements PacketPayload { + + public static final NamespacedIdentifier CHANNEL = Constants.OSL_HANDSHAKE_CHANNEL; + + public byte protocol; + public Set channels; + + public HandshakePayload() { + } + + public HandshakePayload(Set channels) { + this.protocol = Constants.OSL_HANDSHAKE_PROTOCOL; + // we allow registering listeners on channels that do not conform to OSL spec + // but payloads sent over these channels aren't sent via OSL so we can ignore + // them for the OSL handshake. + this.channels = ChannelIdentifiers.dropInvalid(channels); + } + + public static HandshakePayload client() { + return new HandshakePayload(ClientPlayNetworkingImpl.CHANNEL_LISTENERS.keySet()); + } + + public static HandshakePayload server() { + return new HandshakePayload(ServerPlayNetworkingImpl.CHANNEL_LISTENERS.keySet()); + } + + @Override + public void read(PacketBuffer buffer) throws IOException { + protocol = buffer.readByte(); + channels = new LinkedHashSet<>(); + + int channelCount = buffer.readInt(); + + for (int i = 0; i < channelCount; i++) { + channels.add(buffer.readNamespacedIdentifier()); + } + } + + @Override + public void write(PacketBuffer buffer) throws IOException { + buffer.writeByte(protocol); + buffer.writeInt(channels.size()); + + for (NamespacedIdentifier channel : channels) { + buffer.writeNamespacedIdentifier(channel); + } + } +} diff --git a/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/PacketFactory.java b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/PacketFactory.java new file mode 100644 index 00000000..2a4f77aa --- /dev/null +++ b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/PacketFactory.java @@ -0,0 +1,11 @@ +package net.ornithemc.osl.networking.impl; + +import net.minecraft.network.packet.Packet; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; + +public interface PacketFactory { + + Packet create(NamespacedIdentifier channel, byte[] data); + +} diff --git a/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/access/CustomPayloadPacketAccess.java b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/access/CustomPayloadPacketAccess.java new file mode 100644 index 00000000..9c17038b --- /dev/null +++ b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/access/CustomPayloadPacketAccess.java @@ -0,0 +1,11 @@ +package net.ornithemc.osl.networking.impl.access; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; + +public interface CustomPayloadPacketAccess { + + NamespacedIdentifier osl$networking$getChannel(); + + byte[] osl$networking$getData(); + +} diff --git a/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/access/NetworkHandlerAccess.java b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/access/NetworkHandlerAccess.java new file mode 100644 index 00000000..81b86b1f --- /dev/null +++ b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/access/NetworkHandlerAccess.java @@ -0,0 +1,17 @@ +package net.ornithemc.osl.networking.impl.access; + +import java.util.Set; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; + +public interface NetworkHandlerAccess { + + boolean osl$networking$canRunOffMainThread(); + + boolean osl$networking$isPlayReady(); + + boolean osl$networking$isPlayReady(NamespacedIdentifier channel); + + void osl$networking$registerChannels(Set channels); + +} diff --git a/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/access/TaskRunnerAccess.java b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/access/TaskRunnerAccess.java new file mode 100644 index 00000000..bff1ba39 --- /dev/null +++ b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/access/TaskRunnerAccess.java @@ -0,0 +1,7 @@ +package net.ornithemc.osl.networking.impl.access; + +public interface TaskRunnerAccess { + + boolean osl$networking$submit(Runnable task); + +} diff --git a/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java new file mode 100644 index 00000000..86440add --- /dev/null +++ b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java @@ -0,0 +1,265 @@ +package net.ornithemc.osl.networking.impl.client; + +import java.io.IOException; +import java.util.LinkedHashMap; +import java.util.Map; +import java.util.function.Supplier; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.network.handler.ClientNetworkHandler; +import net.minecraft.network.packet.Packet; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.function.IOConsumer; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketBuffers; +import net.ornithemc.osl.networking.api.PacketPayload; +import net.ornithemc.osl.networking.api.client.ClientPacketListener; +import net.ornithemc.osl.networking.impl.PacketFactory; +import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; +import net.ornithemc.osl.networking.impl.access.TaskRunnerAccess; + +public final class ClientPlayNetworkingImpl { + + private static final Logger LOGGER = LogManager.getLogger("OSL|Client Play Networking"); + + private static PacketFactory packetFactory; + private static Minecraft minecraft; + private static Thread thread; + + public static void setUpPacketFactory(PacketFactory factory) { + if (ClientPlayNetworkingImpl.packetFactory != null) { + throw new IllegalStateException("tried to set up client custom payload packet factory when it was already set up!"); + } + + ClientPlayNetworkingImpl.packetFactory = factory; + } + + public static void setUp(Minecraft minecraft) { + if (ClientPlayNetworkingImpl.minecraft == minecraft) { + throw new IllegalStateException("tried to set up client play networking when it was already set up!"); + } + if (ClientPlayNetworkingImpl.packetFactory == null) { + throw new IllegalStateException("tried to set up client play networking when no custom payload packet factory was set up!"); + } + + ClientPlayNetworkingImpl.minecraft = minecraft; + ClientPlayNetworkingImpl.thread = Thread.currentThread(); + } + + public static void destroy(Minecraft minecraft) { + if (ClientPlayNetworkingImpl.minecraft != minecraft) { + throw new IllegalStateException("tried to destroy client play networking when it was not set up!"); + } + + ClientPlayNetworkingImpl.minecraft = null; + ClientPlayNetworkingImpl.thread = null; + } + + public static final Map CHANNEL_LISTENERS = new LinkedHashMap<>(); + + public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { + registerListener(channel, initializer, listener, false); + } + + public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { + registerListener(channel, initializer, listener, true); + } + + private static void registerListener(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener, boolean async) { + registerListenerImpl(channel, new ChannelListener() { + + @Override + public boolean isAsync() { + return async; + } + + @Override + public boolean handle(Minecraft minecraft, ClientNetworkHandler handler, byte[] bytes) throws IOException { + T payload = initializer.get(); + payload.read(PacketBuffers.wrap(bytes)); + + return listener.handle(minecraft, handler, payload); + } + }); + } + + public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { + registerListener(channel, listener, false); + } + + public static void registerListenerAsync(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { + registerListener(channel, listener, true); + } + + private static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Buffer listener, boolean async) { + registerListenerImpl(channel, new ChannelListener() { + + @Override + public boolean isAsync() { + return async; + } + + @Override + public boolean handle(Minecraft minecraft, ClientNetworkHandler handler, byte[] bytes) throws IOException { + return listener.handle(minecraft, handler, PacketBuffers.wrap(bytes)); + } + }); + } + + public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { + registerListener(channel, listener, false); + } + + public static void registerListenerAsync(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { + registerListener(channel, listener, true); + } + + private static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Bytes listener, boolean async) { + registerListenerImpl(channel, new ChannelListener() { + + @Override + public boolean isAsync() { + return async; + } + + @Override + public boolean handle(Minecraft minecraft, ClientNetworkHandler handler, byte[] bytes) throws IOException { + return listener.handle(minecraft, handler, bytes); + } + }); + } + + private static void registerListenerImpl(NamespacedIdentifier channel, ChannelListener listener) { + CHANNEL_LISTENERS.compute(channel, (key, value) -> { + if (value != null) { + throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); + } + + return listener; + }); + } + + public static void unregisterListener(NamespacedIdentifier channel) { + CHANNEL_LISTENERS.remove(channel); + } + + public static boolean handlePacket(Minecraft minecraft, ClientNetworkHandler handler, Packet packet) { + CustomPayloadPacketAccess p = (CustomPayloadPacketAccess)packet; + + NamespacedIdentifier channel = p.osl$networking$getChannel(); + ChannelListener listener = CHANNEL_LISTENERS.get(channel); + + if (listener != null) { + byte[] data = p.osl$networking$getData(); + + if (Thread.currentThread() == thread || listener.isAsync()) { + return handlePayload(minecraft, handler, listener, channel, data); + } else { + return ((TaskRunnerAccess) minecraft).osl$networking$submit(() -> handlePayload(minecraft, handler, listener, channel, data)); + } + } + + return false; + } + + private static boolean handlePayload(Minecraft minecraft, ClientNetworkHandler handler, ChannelListener listener, NamespacedIdentifier channel, byte[] data) { + try { + return listener.handle(minecraft, handler, data); + } catch (IOException e) { + LOGGER.warn("error handling custom payload on channel \'" + channel + "\'", e); + } + + return true; + } + + public static boolean isPlayReady() { + NetworkHandlerAccess handler = (NetworkHandlerAccess)minecraft.getNetworkHandler(); + return handler != null && handler.osl$networking$isPlayReady(); + } + + public static boolean isPlayReady(NamespacedIdentifier channel) { + NetworkHandlerAccess handler = (NetworkHandlerAccess)minecraft.getNetworkHandler(); + return handler != null && handler.osl$networking$isPlayReady(channel); + } + + public static void send(NamespacedIdentifier channel, PacketPayload payload) { + if (isPlayReady(channel)) { + sendInternal(channel, payload); + } + } + + public static void send(NamespacedIdentifier channel, IOConsumer writer) { + if (isPlayReady(channel)) { + sendInternal(channel, writer); + } + } + + public static void send(NamespacedIdentifier channel, PacketBuffer buffer) { + if (isPlayReady(channel)) { + sendInternal(channel, buffer); + } + } + + public static void send(NamespacedIdentifier channel, byte[] bytes) { + if (isPlayReady(channel)) { + sendInternal(channel, bytes); + } + } + + public static void sendNoCheck(NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(channel, payload); + } + + public static void sendNoCheck(NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(channel, writer); + } + + public static void sendNoCheck(NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(channel, buffer); + } + + public static void sendNoCheck(NamespacedIdentifier channel, byte[] bytes) { + sendInternal(channel, bytes); + } + + private static void sendInternal(NamespacedIdentifier channel, PacketPayload payload) { + try { + sendPacket(channel, PacketBuffers.unwrap(PacketBuffers.make(payload::write))); + } catch (IOException e) { + LOGGER.warn("error writing packet payload to channel \'" + channel + "\'", e); + } + } + + private static void sendInternal(NamespacedIdentifier channel, IOConsumer writer) { + try { + sendPacket(channel, PacketBuffers.unwrap(PacketBuffers.make(writer))); + } catch (IOException e) { + LOGGER.warn("error writing buffer to channel \'" + channel + "\'", e); + } + } + + private static void sendInternal(NamespacedIdentifier channel, PacketBuffer buffer) { + sendPacket(channel, PacketBuffers.unwrap(buffer)); + } + + private static void sendInternal(NamespacedIdentifier channel, byte[] bytes) { + sendPacket(channel, bytes); + } + + private static void sendPacket(NamespacedIdentifier channel, byte[] data) { + minecraft.getNetworkHandler().sendPacket(packetFactory.create(channel, data)); + } + + private interface ChannelListener { + + boolean isAsync(); + + boolean handle(Minecraft minecraft, ClientNetworkHandler handler, byte[] bytes) throws IOException; + + } +} diff --git a/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java new file mode 100644 index 00000000..bed7ee2c --- /dev/null +++ b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java @@ -0,0 +1,417 @@ +package net.ornithemc.osl.networking.impl.server; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.function.Supplier; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import net.minecraft.network.packet.Packet; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.entity.mob.player.ServerPlayerEntity; +import net.minecraft.server.network.handler.ServerPlayNetworkHandler; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.function.IOConsumer; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketBuffers; +import net.ornithemc.osl.networking.api.PacketPayload; +import net.ornithemc.osl.networking.api.server.ServerPacketListener; +import net.ornithemc.osl.networking.impl.PacketFactory; +import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; +import net.ornithemc.osl.networking.impl.access.TaskRunnerAccess; + +public final class ServerPlayNetworkingImpl { + + private static final Logger LOGGER = LogManager.getLogger("OSL|Server Play Networking"); + + private static PacketFactory packetFactory; + private static MinecraftServer server; + private static Thread thread; + + public static void setUpPacketFactory(PacketFactory factory) { + if (ServerPlayNetworkingImpl.packetFactory != null) { + throw new IllegalStateException("tried to set up server custom payload packet factory when it was already set up!"); + } + + ServerPlayNetworkingImpl.packetFactory = factory; + } + + public static void setUp(MinecraftServer server) { + if (ServerPlayNetworkingImpl.server == server) { + throw new IllegalStateException("tried to set up server play networking when it was already set up!"); + } + if (ServerPlayNetworkingImpl.packetFactory == null) { + throw new IllegalStateException("tried to set up server play networking when no custom payload packet factory was set up!"); + } + + ServerPlayNetworkingImpl.server = server; + ServerPlayNetworkingImpl.thread = Thread.currentThread(); + } + + public static void destroy(MinecraftServer server) { + if (ServerPlayNetworkingImpl.server != server) { + throw new IllegalStateException("tried to destroy server play networking when it was not set up!"); + } + + ServerPlayNetworkingImpl.server = null; + ServerPlayNetworkingImpl.thread = null; + } + + public static final Map CHANNEL_LISTENERS = new LinkedHashMap<>(); + + public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { + ServerPlayNetworkingImpl.registerListener(channel, initializer, listener, false); + } + + public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { + ServerPlayNetworkingImpl.registerListener(channel, initializer, listener, true); + } + + private static void registerListener(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener, boolean async) { + registerListenerImpl(channel, new ChannelListener() { + + @Override + public boolean isAsync() { + return async; + } + + @Override + public boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] bytes) throws IOException { + T payload = initializer.get(); + payload.read(PacketBuffers.wrap(bytes)); + + return listener.handle(server, handler, player, payload); + } + }); + } + + public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { + ServerPlayNetworkingImpl.registerListener(channel, listener, false); + } + + public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { + ServerPlayNetworkingImpl.registerListener(channel, listener, true); + } + + private static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Buffer listener, boolean async) { + registerListenerImpl(channel, new ChannelListener() { + + @Override + public boolean isAsync() { + return async; + } + + @Override + public boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] bytes) throws IOException { + return listener.handle(server, handler, player, PacketBuffers.wrap(bytes)); + } + }); + } + + public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { + ServerPlayNetworkingImpl.registerListener(channel, listener, false); + } + + public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { + ServerPlayNetworkingImpl.registerListener(channel, listener, true); + } + + private static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener, boolean async) { + registerListenerImpl(channel, new ChannelListener() { + + @Override + public boolean isAsync() { + return async; + } + + @Override + public boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] bytes) throws IOException { + return listener.handle(server, handler, player, bytes); + } + }); + } + + private static void registerListenerImpl(NamespacedIdentifier channel, ChannelListener listener) { + CHANNEL_LISTENERS.compute(channel, (key, value) -> { + if (value != null) { + throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); + } + + return listener; + }); + } + + public static void unregisterListener(NamespacedIdentifier channel) { + CHANNEL_LISTENERS.remove(channel); + } + + public static boolean handlePacket(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, Packet packet) { + CustomPayloadPacketAccess p = (CustomPayloadPacketAccess)packet; + + NamespacedIdentifier channel = p.osl$networking$getChannel(); + ChannelListener listener = CHANNEL_LISTENERS.get(channel); + + if (listener != null) { + byte[] data = p.osl$networking$getData(); + + if (Thread.currentThread() == thread || listener.isAsync()) { + return handlePayload(server, handler, player, listener, channel, data); + } else { + return ((TaskRunnerAccess) server).osl$networking$submit(() -> handlePayload(server, handler, player, listener, channel, data)); + } + } + + return false; + } + + private static boolean handlePayload(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, ChannelListener listener, NamespacedIdentifier channel, byte[] data) { + try { + return listener.handle(server, handler, player, data); + } catch (IOException e) { + LOGGER.warn("error handling custom payload on channel \'" + channel + "\'", e); + } + + return true; + } + + public static boolean isPlayReady(ServerPlayerEntity player) { + NetworkHandlerAccess handler = (NetworkHandlerAccess)player.networkHandler; + return handler != null && handler.osl$networking$isPlayReady(); + } + + public static boolean isPlayReady(ServerPlayerEntity player, NamespacedIdentifier channel) { + NetworkHandlerAccess handler = (NetworkHandlerAccess)player.networkHandler; + return handler != null && handler.osl$networking$isPlayReady(channel); + } + + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, PacketPayload payload) { + if (isPlayReady(player, channel)) { + sendInternal(player, channel, payload); + } + } + + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, IOConsumer writer) { + if (isPlayReady(player, channel)) { + sendInternal(player, channel, writer); + } + } + + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, PacketBuffer buffer) { + if (isPlayReady(player, channel)) { + sendInternal(player, channel, buffer); + } + } + + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, byte[] bytes) { + if (isPlayReady(player, channel)) { + sendInternal(player, channel, bytes); + } + } + + public static void send(Iterable players, NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(collectPlayers(players, p -> isPlayReady(p, channel)), channel, payload); + } + + public static void send(Iterable players, NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(collectPlayers(players, p -> isPlayReady(p, channel)), channel, writer); + } + + public static void send(Iterable players, NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(collectPlayers(players, p -> isPlayReady(p, channel)), channel, buffer); + } + + public static void send(Iterable players, NamespacedIdentifier channel, byte[] bytes) { + sendInternal(collectPlayers(players, p -> isPlayReady(p, channel)), channel, bytes); + } + + public static void send(int dimension, NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(collectPlayers(p -> p.dimension == dimension && isPlayReady(p, channel)), channel, payload); + } + + public static void send(int dimension, NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(collectPlayers(p -> p.dimension == dimension && isPlayReady(p, channel)), channel, writer); + } + + public static void send(int dimension, NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(collectPlayers(p -> p.dimension == dimension && isPlayReady(p, channel)),channel, buffer); + } + + public static void send(int dimension, NamespacedIdentifier channel, byte[] bytes) { + sendInternal(collectPlayers(p -> p.dimension == dimension && isPlayReady(p, channel)),channel, bytes); + } + + public static void send(NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(collectPlayers(p -> isPlayReady(p, channel)), channel, payload); + } + + public static void send(NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(collectPlayers(p -> isPlayReady(p, channel)), channel, writer); + } + + public static void send(NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(collectPlayers(p -> isPlayReady(p, channel)), channel, buffer); + } + + public static void send(NamespacedIdentifier channel, byte[] bytes) { + sendInternal(collectPlayers(p -> isPlayReady(p, channel)), channel, bytes); + } + + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(player, channel, payload); + } + + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(player, channel, writer); + } + + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(player, channel, buffer); + } + + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, byte[] bytes) { + sendInternal(player, channel, bytes); + } + + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(players, channel, payload); + } + + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(players, channel, writer); + } + + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(players, channel, buffer); + } + + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, byte[] bytes) { + sendInternal(players, channel, bytes); + } + + public static void sendNoCheck(int dimension, NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(collectPlayers(p -> p.dimension == dimension), channel, payload); + } + + public static void sendNoCheck(int dimension, NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(collectPlayers(p -> p.dimension == dimension), channel, writer); + } + + public static void sendNoCheck(int dimension, NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(collectPlayers(p -> p.dimension == dimension),channel, buffer); + } + + public static void sendNoCheck(int dimension, NamespacedIdentifier channel, byte[] bytes) { + sendInternal(collectPlayers(p -> p.dimension == dimension),channel, bytes); + } + + public static void sendNoCheck(NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(allPlayers(), channel, payload); + } + + public static void sendNoCheck(NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(allPlayers(), channel, writer); + } + + public static void sendNoCheck(NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(allPlayers(), channel, buffer); + } + + public static void sendNoCheck(NamespacedIdentifier channel, byte[] bytes) { + sendInternal(allPlayers(), channel, bytes); + } + + private static void sendInternal(ServerPlayerEntity player, NamespacedIdentifier channel, PacketPayload payload) { + try { + sendPacket(player, channel, PacketBuffers.unwrap(PacketBuffers.make(payload::write))); + } catch (IOException e) { + LOGGER.warn("error writing packet payload to channel \'" + channel + "\'", e); + } + } + + private static void sendInternal(ServerPlayerEntity player, NamespacedIdentifier channel, IOConsumer writer) { + try { + sendPacket(player, channel, PacketBuffers.unwrap(PacketBuffers.make(writer))); + } catch (IOException e) { + LOGGER.warn("error writing buffer to channel \'" + channel + "\'", e); + } + } + + private static void sendInternal(ServerPlayerEntity player, NamespacedIdentifier channel, PacketBuffer buffer) { + sendPacket(player, channel, PacketBuffers.unwrap(buffer)); + } + + private static void sendInternal(ServerPlayerEntity player, NamespacedIdentifier channel, byte[] bytes) { + sendPacket(player, channel, bytes); + } + + private static void sendInternal(Iterable players, NamespacedIdentifier channel, PacketPayload payload) { + try { + sendPacket(players, channel, PacketBuffers.unwrap(PacketBuffers.make(payload::write))); + } catch (IOException e) { + LOGGER.warn("error writing packet payload to channel \'" + channel + "\'", e); + } + } + + private static void sendInternal(Iterable players, NamespacedIdentifier channel, IOConsumer writer) { + try { + sendPacket(players, channel, PacketBuffers.unwrap(PacketBuffers.make(writer))); + } catch (IOException e) { + LOGGER.warn("error writing buffer to channel \'" + channel + "\'", e); + } + } + + private static void sendInternal(Iterable players, NamespacedIdentifier channel, PacketBuffer buffer) { + sendPacket(players, channel, PacketBuffers.unwrap(buffer)); + } + + private static void sendInternal(Iterable players, NamespacedIdentifier channel, byte[] bytes) { + sendPacket(players, channel, bytes); + } + + private static Iterable allPlayers() { + return server.getPlayerManager().players; + } + + private static Iterable collectPlayers(Predicate filter) { + return collectPlayers(allPlayers(), filter); + } + + private static Iterable collectPlayers(Iterable src, Predicate filter) { + List players = new ArrayList<>(); + + for (ServerPlayerEntity player : src) { + if (filter.test(player)) { + players.add(player); + } + } + + return players; + } + + private static void sendPacket(ServerPlayerEntity player, NamespacedIdentifier channel, byte[] data) { + player.networkHandler.sendPacket(packetFactory.create(channel, data)); + } + + private static void sendPacket(Iterable players, NamespacedIdentifier channel, byte[] data) { + Packet packet = packetFactory.create(channel, data); + + for (ServerPlayerEntity player : players) { + player.networkHandler.sendPacket(packet); + } + } + + private interface ChannelListener { + + boolean isAsync(); + + boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] bytes) throws IOException; + + } +} diff --git a/libraries/networking/networking-mcb1.0-mcb1.4_01/build.gradle b/libraries/networking/networking-mcb1.0-mcb1.4_01/build.gradle deleted file mode 100644 index f7548915..00000000 --- a/libraries/networking/networking-mcb1.0-mcb1.4_01/build.gradle +++ /dev/null @@ -1,4 +0,0 @@ -setUpModule(project, - 'entrypoints-mcin-20091223-1459-mc1.5.2', - 'lifecycle-events-mcb1.4-1507-mcb1.7.3' -) diff --git a/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java b/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java deleted file mode 100644 index 237d7e67..00000000 --- a/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java +++ /dev/null @@ -1,13 +0,0 @@ -package net.ornithemc.osl.networking.api; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; - -public interface CustomPayload { - - void read(DataInputStream input) throws IOException; - - void write(DataOutputStream output) throws IOException; - -} diff --git a/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java b/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java deleted file mode 100644 index f68e894c..00000000 --- a/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java +++ /dev/null @@ -1,23 +0,0 @@ -package net.ornithemc.osl.networking.api; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; - -public final class DataStreams { - - public static DataInputStream input(byte[] bytes) { - return new DataInputStream(new ByteArrayInputStream(bytes == null ? new byte[0] : bytes)); - } - - public static ByteArrayOutputStream output(IOConsumer writer) throws IOException { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - DataOutputStream os = new DataOutputStream(bos); - writer.accept(os); - return bos; - } -} diff --git a/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java b/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java deleted file mode 100644 index f0963ed6..00000000 --- a/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java +++ /dev/null @@ -1,70 +0,0 @@ -package net.ornithemc.osl.networking.api.client; - -import java.util.function.Consumer; - -import net.minecraft.client.Minecraft; - -import net.ornithemc.osl.core.api.events.Event; - -/** - * Events related to the client side of a client-server connection. - */ -public class ClientConnectionEvents { - - /** - * This event is fired after a successful login occurs. - * - *

- * Note that channel registration happens after login, - * and until then data cannot safely be sent to the server. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ClientConnectionEvents.LOGIN.register(minecraft -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> LOGIN = Event.consumer(); - /** - * This event is fired after login, once channel registration is complete. - * - *

- * This marks the moment data can safely be sent to the server. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ClientConnectionEvents.PLAY_READY.register(minecraft -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> PLAY_READY = Event.consumer(); - /** - * This event is fired when the client disconnects from the server. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ClientConnectionEvents.DISCONNECT.register(minecraft -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> DISCONNECT = Event.consumer(); - -} diff --git a/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java b/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java deleted file mode 100644 index e1594802..00000000 --- a/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java +++ /dev/null @@ -1,158 +0,0 @@ -package net.ornithemc.osl.networking.api.client; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.function.Supplier; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.network.handler.ClientNetworkHandler; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; - -public final class ClientPlayNetworking { - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - ClientPlayNetworkingImpl.registerListener(channel, initializer, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListener(String channel, StreamListener listener) { - ClientPlayNetworkingImpl.registerListener(channel, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - ClientPlayNetworkingImpl.registerListenerRaw(channel, listener); - } - - /** - * Remove the listener registered to the given channel. - */ - public static void unregisterListener(String channel) { - ClientPlayNetworkingImpl.unregisterListener(channel); - } - - /** - * Check whether the connection is ready for data to be sent to the server. - */ - public static boolean isPlayReady() { - return ClientPlayNetworkingImpl.isPlayReady(); - } - - /** - * Check whether the given channel is open for data to be sent through it. - * This method will return {@code false} if the client is not connected to a - * server, or if the server has no listeners for the given channel. - */ - public static boolean canSend(String channel) { - return ClientPlayNetworkingImpl.canSend(channel); - } - - /** - * Send a packet to the server through the given channel. The payload will - * only be written if the channel is open. - */ - public static void send(String channel, CustomPayload payload) { - ClientPlayNetworkingImpl.send(channel, payload); - } - - /** - * Send a packet to the server through the given channel. The writer will - * only be called if the channel is open. - */ - public static void send(String channel, IOConsumer writer) { - ClientPlayNetworkingImpl.send(channel, writer); - } - - /** - * Send a packet to the server through the given channel. - */ - public static void send(String channel, byte[] data) { - ClientPlayNetworkingImpl.send(channel, data); - } - - /** - * Send a packet to the server through the given channel, without checking - * whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the server. - */ - public static void doSend(String channel, CustomPayload payload) { - ClientPlayNetworkingImpl.doSend(channel, payload); - } - - /** - * Send a packet to the server through the given channel, without checking - * whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the server. - */ - public static void doSend(String channel, IOConsumer writer) { - ClientPlayNetworkingImpl.doSend(channel, writer); - } - - /** - * Send a packet to the server through the given channel, without checking - * whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the server. - */ - public static void doSend(String channel, byte[] data) { - ClientPlayNetworkingImpl.doSend(channel, data); - } - - public interface PayloadListener { - - /** - * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(Minecraft minecraft, ClientNetworkHandler handler, T payload) throws IOException; - - } - - public interface StreamListener { - - /** - * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(Minecraft minecraft, ClientNetworkHandler handler, DataInputStream data) throws IOException; - - } - - public interface ByteArrayListener { - - /** - * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(Minecraft minecraft, ClientNetworkHandler handler, byte[] data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java b/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java deleted file mode 100644 index dbe85275..00000000 --- a/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java +++ /dev/null @@ -1,71 +0,0 @@ -package net.ornithemc.osl.networking.api.server; - -import java.util.function.BiConsumer; - -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.entity.mob.player.ServerPlayerEntity; - -import net.ornithemc.osl.core.api.events.Event; - -/** - * Events related to the server side of a client-server connection. - */ -public class ServerConnectionEvents { - - /** - * This event is fired after a successful login occurs. - * - *

- * Note that channel registration happens after login, - * and until then data cannot safely be sent to the client. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ServerConnectionEvents.LOGIN.register((server, player) -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> LOGIN = Event.biConsumer(); - /** - * This event is fired after login, once channel registration is complete. - * - *

- * This marks the moment data can safely be sent to the client. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ServerConnectionEvents.PLAY_READY.register((server, player) -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> PLAY_READY = Event.biConsumer(); - /** - * This event is fired when a client disconnects from the server. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ServerConnectionEvents.DISCONNECT.register((server, player) -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> DISCONNECT = Event.biConsumer(); - -} diff --git a/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java b/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java deleted file mode 100644 index 7eda8cca..00000000 --- a/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java +++ /dev/null @@ -1,321 +0,0 @@ -package net.ornithemc.osl.networking.api.server; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.function.Supplier; - -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.entity.mob.player.ServerPlayerEntity; -import net.minecraft.server.network.handler.ServerPlayNetworkHandler; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -public final class ServerPlayNetworking { - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - ServerPlayNetworkingImpl.registerListener(channel, initializer, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListener(String channel, StreamListener listener) { - ServerPlayNetworkingImpl.registerListener(channel, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - ServerPlayNetworkingImpl.registerListenerRaw(channel, listener); - } - - /** - * Remove the listener registered to the given channel. - */ - public static void unregisterListener(String channel) { - ServerPlayNetworkingImpl.unregisterListener(channel); - } - - /** - * Check whether the connection is ready for data to be sent to the client. - */ - public static boolean isPlayReady(ServerPlayerEntity player) { - return ServerPlayNetworkingImpl.isPlayReady(player); - } - - /** - * Check whether the given channel is open for data to be sent through it. - * This method will return {@code false} if the client has no listeners for - * the given channel. - */ - public static boolean canSend(ServerPlayerEntity player, String channel) { - return ServerPlayNetworkingImpl.canSend(player, channel); - } - - /** - * Send a packet to the given player through the given channel. The payload - * will only be written if the channel is open. - */ - public static void send(ServerPlayerEntity player, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.send(player, channel, payload); - } - - /** - * Send a packet to the given player through the given channel. The writer - * will only be called if the channel is open. - */ - public static void send(ServerPlayerEntity player, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.send(player, channel, writer); - } - - /** - * Send a packet to the given player through the given channel. - */ - public static void send(ServerPlayerEntity player, String channel, byte[] data) { - ServerPlayNetworkingImpl.send(player, channel, data); - } - - /** - * Send a packet to the given players through the given channel. The payload - * will only be written if the channel is open for at least one player. - */ - public static void send(Iterable players, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.send(players, channel, payload); - } - - /** - * Send a packet to the given players through the given channel. The writer - * will only be called if the channel is open for at least one player. - */ - public static void send(Iterable players, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.send(players, channel, writer); - } - - /** - * Send a packet to the given players through the given channel. - */ - public static void send(Iterable players, String channel, byte[] data) { - ServerPlayNetworkingImpl.send(players, channel, data); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel. The payload will only be written if the channel is open for at - * least one player. - */ - public static void send(int dimension, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.send(dimension, channel, payload); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel. The writer will only be called if the channel is open for at - * least one player. - */ - public static void send(int dimension, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.send(dimension, channel, writer); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel. - */ - public static void send(int dimension, String channel, byte[] data) { - ServerPlayNetworkingImpl.send(dimension, channel, data); - } - - /** - * Send a packet to all players through the given channel. The payload will - * only be written if the channel is open for at least one player. - */ - public static void send(String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.send(channel, payload); - } - - /** - * Send a packet to all players through the given channel. The writer will - * only be called if the channel is open for at least one player. - */ - public static void send(String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.send(channel, writer); - } - - /** - * Send a packet to all players through the given channel. - */ - public static void send(String channel, byte[] data) { - ServerPlayNetworkingImpl.send(channel, data); - } - - /** - * Send a packet to the given player through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(ServerPlayerEntity player, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(player, channel, payload); - } - - /** - * Send a packet to the given player through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(ServerPlayerEntity player, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(player, channel, writer); - } - - /** - * Send a packet to the given player through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(ServerPlayerEntity player, String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(player, channel, data); - } - - /** - * Send a packet to the given players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(Iterable players, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(players, channel, payload); - } - - /** - * Send a packet to the given players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(Iterable players, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(players, channel, writer); - } - - /** - * Send a packet to the given players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(Iterable players, String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(players, channel, data); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel, without checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(int dimension, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(dimension, channel, payload); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel, without checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(int dimension, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(dimension, channel, writer); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel, without checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(int dimension, String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(dimension, channel, data); - } - - /** - * Send a packet to all players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(channel, payload); - } - - /** - * Send a packet to all players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(channel, writer); - } - - /** - * Send a packet to all players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(channel, data); - } - - public interface PayloadListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, T payload) throws IOException; - - } - - public interface StreamListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, DataInputStream data) throws IOException; - - } - - public interface ByteArrayListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java b/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java deleted file mode 100644 index 76c2850d..00000000 --- a/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java +++ /dev/null @@ -1,75 +0,0 @@ -package net.ornithemc.osl.networking.impl; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.UncheckedIOException; - -import net.minecraft.network.PacketHandler; -import net.minecraft.network.packet.Packet; - -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; - -public class CustomPayloadPacket extends Packet { - - public String channel; - public int size; - public byte[] data; - - public CustomPayloadPacket() { - } - - public CustomPayloadPacket(String channel, byte[] data) { - this.channel = channel; - this.data = data; - if (data != null) { - this.size = data.length; - if (this.size > Short.MAX_VALUE) { - throw new IllegalArgumentException("Payload may not be larger than 32k"); - } - } - } - - // the IOException has been stripped from the read/write methods - // by the obfuscator, thus we catch it and re-throw it as a - // runtime exception - it will be caught in Connection#read anyhow - - @Override - public void read(DataInputStream input) { - try { - this.channel = input.readUTF(); - this.size = input.readShort(); - if (this.size > 0 && this.size < Short.MAX_VALUE) { - this.data = new byte[this.size]; - input.readFully(this.data); - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - @Override - public void write(DataOutputStream output) { - try { - output.writeUTF(this.channel); - output.writeShort(this.size); - if (this.data != null) { - output.write(this.data); - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - @Override - public void handle(PacketHandler handler) { - if (handler instanceof INetworkHandler) { - ((INetworkHandler)handler).osl$networking$handleCustomPayload(this); - } - } - - @Override - public int getSize() { - return 2 + this.channel.length() * 2 + 2 + this.size; - } -} diff --git a/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java b/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java deleted file mode 100644 index bfe9ec89..00000000 --- a/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java +++ /dev/null @@ -1,54 +0,0 @@ -package net.ornithemc.osl.networking.impl; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.LinkedHashSet; -import java.util.Set; - -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -public class HandshakePayload implements CustomPayload { - - public static final String CHANNEL = "OSL|Handshake"; - - public Set channels; - - public HandshakePayload() { - } - - public HandshakePayload(Set channels) { - this.channels = channels; - } - - public static HandshakePayload client() { - return new HandshakePayload(ClientPlayNetworkingImpl.LISTENERS.keySet()); - } - - public static HandshakePayload server() { - return new HandshakePayload(ServerPlayNetworkingImpl.LISTENERS.keySet()); - } - - @Override - public void read(DataInputStream input) throws IOException { - channels = new LinkedHashSet<>(); - int channelCount = input.readInt(); - - if (channelCount > 0) { - for (int i = 0; i < channelCount; i++) { - channels.add(input.readUTF()); - } - } - } - - @Override - public void write(DataOutputStream output) throws IOException { - output.writeInt(channels.size()); - - for (String channel : channels) { - output.writeUTF(channel); - } - } -} diff --git a/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/Networking.java deleted file mode 100644 index 3213aa87..00000000 --- a/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/Networking.java +++ /dev/null @@ -1,58 +0,0 @@ -package net.ornithemc.osl.networking.impl; - -import net.ornithemc.osl.entrypoints.api.ModInitializer; -import net.ornithemc.osl.entrypoints.api.client.ClientModInitializer; -import net.ornithemc.osl.entrypoints.api.server.ServerModInitializer; -import net.ornithemc.osl.lifecycle.api.client.MinecraftClientEvents; -import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; -import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking; -import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking; -import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; -import net.ornithemc.osl.networking.impl.mixin.common.PacketAccessor; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -public class Networking implements ModInitializer, ClientModInitializer, ServerModInitializer { - - @Override - public void init() { - PacketAccessor.register(Constants.CUSTOM_PAYLOAD_PACKET_ID, CustomPayloadPacket.class); - } - - @Override - public void initClient() { - MinecraftClientEvents.START.register(minecraft -> { - ClientPlayNetworkingImpl.setUp(minecraft); - }); - MinecraftClientEvents.STOP.register(minecraft -> { - ClientPlayNetworkingImpl.destroy(minecraft); - }); - ClientPlayNetworking.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { - // send channel registration data as a response to receiving server channel registration data - ClientPlayNetworking.doSend(HandshakePayload.CHANNEL, HandshakePayload.client()); - - ((INetworkHandler)handler).osl$networking$registerChannels(payload.channels); - ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); - - return true; - }); - } - - @Override - public void initServer() { - MinecraftServerEvents.START.register(server -> { - ServerPlayNetworkingImpl.setUp(server); - }); - MinecraftServerEvents.STOP.register(server -> { - ServerPlayNetworkingImpl.destroy(server); - }); - ServerPlayNetworking.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { - ((INetworkHandler)handler).osl$networking$registerChannels(payload.channels); - ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); - - return true; - }); - } -} diff --git a/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java b/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java deleted file mode 100644 index c4eb3d66..00000000 --- a/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java +++ /dev/null @@ -1,168 +0,0 @@ -package net.ornithemc.osl.networking.impl.client; - -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.function.Supplier; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.network.handler.ClientNetworkHandler; -import net.minecraft.network.packet.Packet; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.Channels; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.api.DataStreams; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.ByteArrayListener; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.PayloadListener; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.StreamListener; -import net.ornithemc.osl.networking.impl.CustomPayloadPacket; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; - -public final class ClientPlayNetworkingImpl { - - private static final Logger LOGGER = LogManager.getLogger("OSL|Client Play Networking"); - - private static Minecraft minecraft; - - public static void setUp(Minecraft minecraft) { - if (ClientPlayNetworkingImpl.minecraft == minecraft) { - throw new IllegalStateException("tried to set up client networking when it was already set up!"); - } - - ClientPlayNetworkingImpl.minecraft = minecraft; - } - - public static void destroy(Minecraft minecraft) { - if (ClientPlayNetworkingImpl.minecraft != minecraft) { - throw new IllegalStateException("tried to destroy client networking when it was not set up!"); - } - - ClientPlayNetworkingImpl.minecraft = null; - } - - public static final Map LISTENERS = new LinkedHashMap<>(); - - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - registerListenerImpl(channel, (minecraft, handler, data) -> { - T payload = initializer.get(); - payload.read(DataStreams.input(data)); - - return listener.handle(minecraft, handler, payload); - }); - } - - public static void registerListener(String channel, StreamListener listener) { - registerListenerImpl(channel, (minecraft, handler, data) -> { - return listener.handle(minecraft, handler, DataStreams.input(data)); - }); - } - - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - registerListenerImpl(channel, listener::handle); - } - - private static void registerListenerImpl(String channel, Listener listener) { - LISTENERS.compute(channel, (key, value) -> { - Channels.validate(channel); - - if (value != null) { - throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); - } - - return listener; - }); - } - - public static void unregisterListener(String channel) { - LISTENERS.remove(channel); - } - - public static boolean handle(Minecraft minecraft, ClientNetworkHandler handler, CustomPayloadPacket packet) { - Listener listener = LISTENERS.get(packet.channel); - - if (listener != null) { - try { - return listener.handle(minecraft, handler, packet.data); - } catch (IOException e) { - LOGGER.warn("error handling custom payload on channel \'" + packet.channel + "\'", e); - return true; - } - } - - return false; - } - - public static boolean isPlayReady() { - INetworkHandler handler = (INetworkHandler)minecraft.getNetworkHandler(); - return handler != null && handler.osl$networking$isPlayReady(); - } - - public static boolean canSend(String channel) { - INetworkHandler handler = (INetworkHandler)minecraft.getNetworkHandler(); - return handler != null && handler.osl$networking$isRegisteredChannel(channel); - } - - public static void send(String channel, CustomPayload payload) { - if (canSend(channel)) { - doSend(channel, payload); - } - } - - public static void send(String channel, IOConsumer writer) { - if (canSend(channel)) { - doSend(channel, writer); - } - } - - public static void send(String channel, byte[] data) { - if (canSend(channel)) { - doSend(channel, data); - } - } - - public static void doSend(String channel, CustomPayload payload) { - sendPacket(makePacket(channel, payload)); - } - - public static void doSend(String channel, IOConsumer writer) { - sendPacket(makePacket(channel, writer)); - } - - public static void doSend(String channel, byte[] data) { - sendPacket(makePacket(channel, data)); - } - - private static Packet makePacket(String channel, CustomPayload payload) { - return makePacket(channel, payload::write); - } - - private static Packet makePacket(String channel, IOConsumer writer) { - try { - return new CustomPayloadPacket(channel, DataStreams.output(writer).toByteArray()); - } catch (IOException e) { - LOGGER.warn("error writing custom payload to channel \'" + channel + "\'", e); - return null; - } - } - - private static Packet makePacket(String channel, byte[] data) { - return new CustomPayloadPacket(channel, data); - } - - private static void sendPacket(Packet packet) { - if (packet != null) { - minecraft.getNetworkHandler().sendPacket(packet); - } - } - - private interface Listener { - - boolean handle(Minecraft minecraft, ClientNetworkHandler handler, byte[] data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerLoginNetworkHandlerMixin.java b/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerLoginNetworkHandlerMixin.java deleted file mode 100644 index d57902df..00000000 --- a/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerLoginNetworkHandlerMixin.java +++ /dev/null @@ -1,61 +0,0 @@ -package net.ornithemc.osl.networking.impl.mixin.server; - -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; -import org.spongepowered.asm.mixin.injection.callback.LocalCapture; - -import net.minecraft.network.packet.HandshakePacket; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.entity.mob.player.ServerPlayerEntity; -import net.minecraft.server.network.handler.ServerLoginNetworkHandler; - -import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; -import net.ornithemc.osl.networking.impl.Constants; -import net.ornithemc.osl.networking.impl.HandshakePayload; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -@Mixin(ServerLoginNetworkHandler.class) -public class ServerLoginNetworkHandlerMixin { - - @Shadow @Final private MinecraftServer server; - - /** - * is the client also running OSL? - */ - @Unique private boolean ornithe; - - @Inject( - method = "handleHandshake", - at = @At( - value = "HEAD" - ) - ) - private void osl$networking$handleHandshake(HandshakePacket packet, CallbackInfo ci) { - if (Constants.OSL_HANDSHAKE_KEY.equals(packet.key)) { - ornithe = true; - } - } - - @Inject( - method = "acceptLogin", - locals = LocalCapture.CAPTURE_FAILHARD, - at = @At( - value = "TAIL" - ) - ) - private void osl$networking$handleLogin(CallbackInfo ci, ServerPlayerEntity player) { - if (player != null) { - if (ornithe) { - // send channel registration data as soon as login occurs - ServerPlayNetworkingImpl.doSend(player, HandshakePayload.CHANNEL, HandshakePayload.server()); - } - - ServerConnectionEvents.LOGIN.invoker().accept(server, player); - } - } -} diff --git a/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java b/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java deleted file mode 100644 index 11335ca1..00000000 --- a/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/mixin/server/ServerPlayNetworkHandlerMixin.java +++ /dev/null @@ -1,64 +0,0 @@ -package net.ornithemc.osl.networking.impl.mixin.server; - -import java.util.LinkedHashSet; -import java.util.Set; - -import org.spongepowered.asm.mixin.Final; -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.Shadow; -import org.spongepowered.asm.mixin.Unique; -import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; -import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; - -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.entity.mob.player.ServerPlayerEntity; -import net.minecraft.server.network.handler.ServerPlayNetworkHandler; - -import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; -import net.ornithemc.osl.networking.impl.CustomPayloadPacket; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -@Mixin(ServerPlayNetworkHandler.class) -public class ServerPlayNetworkHandlerMixin implements INetworkHandler { - - @Shadow @Final private MinecraftServer server; - @Shadow @Final private ServerPlayerEntity player; - - /** - * Channels that the client is listening to. - */ - @Unique private Set clientChannels; - - @Inject( - method = "onDisconnect", - at = @At( - value = "HEAD" - ) - ) - private void osl$networking$handleDisconnect(CallbackInfo ci) { - ServerConnectionEvents.DISCONNECT.invoker().accept(server, player); - clientChannels = null; - } - - @Override - public boolean osl$networking$handleCustomPayload(CustomPayloadPacket packet) { - return ServerPlayNetworkingImpl.handle(server, (ServerPlayNetworkHandler)(Object)this, player, packet); - } - - @Override - public boolean osl$networking$isPlayReady() { - return clientChannels != null; - } - - @Override - public void osl$networking$registerChannels(Set channels) { - clientChannels = new LinkedHashSet<>(channels); - } - - @Override - public boolean osl$networking$isRegisteredChannel(String channel) { - return clientChannels != null && clientChannels.contains(channel); - } -} diff --git a/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java b/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java deleted file mode 100644 index 711978a2..00000000 --- a/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java +++ /dev/null @@ -1,269 +0,0 @@ -package net.ornithemc.osl.networking.impl.server; - -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.function.Supplier; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import net.minecraft.network.packet.Packet; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.entity.mob.player.ServerPlayerEntity; -import net.minecraft.server.network.handler.ServerPlayNetworkHandler; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.Channels; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.api.DataStreams; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.ByteArrayListener; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.PayloadListener; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.StreamListener; -import net.ornithemc.osl.networking.impl.CustomPayloadPacket; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; - -public final class ServerPlayNetworkingImpl { - - private static final Logger LOGGER = LogManager.getLogger("OSL|Server Play Networking"); - - private static MinecraftServer server; - - public static void setUp(MinecraftServer server) { - if (ServerPlayNetworkingImpl.server == server) { - throw new IllegalStateException("tried to set up server networking when it was already set up!"); - } - - ServerPlayNetworkingImpl.server = server; - } - - public static void destroy(MinecraftServer server) { - if (ServerPlayNetworkingImpl.server != server) { - throw new IllegalStateException("tried to destroy server networking when it was not set up!"); - } - - ServerPlayNetworkingImpl.server = null; - } - - public static final Map LISTENERS = new LinkedHashMap<>(); - - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - registerListenerImpl(channel, (server, handler, player, data) -> { - T payload = initializer.get(); - payload.read(DataStreams.input(data)); - - return listener.handle(server, handler, player, payload); - }); - } - - public static void registerListener(String channel, StreamListener listener) { - registerListenerImpl(channel, (server, handler, player, data) -> { - return listener.handle(server, handler, player, DataStreams.input(data)); - }); - } - - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - registerListenerImpl(channel, listener::handle); - } - - private static void registerListenerImpl(String channel, Listener listener) { - LISTENERS.compute(channel, (key, value) -> { - Channels.validate(channel); - - if (value != null) { - throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); - } - - return listener; - }); - } - - public static void unregisterListener(String channel) { - LISTENERS.remove(channel); - } - - public static boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, CustomPayloadPacket packet) { - Listener listener = LISTENERS.get(packet.channel); - - if (listener != null) { - try { - return listener.handle(server, handler, player, packet.data); - } catch (IOException e) { - LOGGER.warn("error handling custom payload on channel \'" + packet.channel + "\'", e); - return true; - } - } - - return false; - } - - public static boolean isPlayReady(ServerPlayerEntity player) { - INetworkHandler handler = (INetworkHandler)player.networkHandler; - return handler != null && handler.osl$networking$isPlayReady(); - } - - public static boolean canSend(ServerPlayerEntity player, String channel) { - INetworkHandler handler = (INetworkHandler)player.networkHandler; - return handler != null && handler.osl$networking$isRegisteredChannel(channel); - } - - public static void send(ServerPlayerEntity player, String channel, CustomPayload payload) { - if (canSend(player, channel)) { - doSend(player, channel, payload); - } - } - - public static void send(ServerPlayerEntity player, String channel, IOConsumer writer) { - if (canSend(player, channel)) { - doSend(player, channel, writer); - } - } - - public static void send(ServerPlayerEntity player, String channel, byte[] data) { - if (canSend(player, channel)) { - doSend(player, channel, data); - } - } - - public static void send(Iterable players, String channel, CustomPayload payload) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, payload)); - } - - public static void send(Iterable players, String channel, IOConsumer writer) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, writer)); - } - - public static void send(Iterable players, String channel, byte[] data) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, data)); - } - - public static void send(int dimension, String channel, CustomPayload payload) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)), channel, payload); - } - - public static void send(int dimension, String channel, IOConsumer writer) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)), channel, writer); - } - - public static void send(int dimension, String channel, byte[] data) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)),channel, data); - } - - public static void send(String channel, CustomPayload payload) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, payload); - } - - public static void send(String channel, IOConsumer writer) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, writer); - } - - public static void send(String channel, byte[] data) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, data); - } - - public static void doSend(ServerPlayerEntity player, String channel, CustomPayload payload) { - sendPacket(player, makePacket(channel, payload)); - } - - public static void doSend(ServerPlayerEntity player, String channel, IOConsumer writer) { - sendPacket(player, makePacket(channel, writer)); - } - - public static void doSend(ServerPlayerEntity player, String channel, byte[] data) { - sendPacket(player, makePacket(channel, data)); - } - - public static void doSend(Iterable players, String channel, CustomPayload payload) { - sendPacket(players, makePacket(channel, payload)); - } - - public static void doSend(Iterable players, String channel, IOConsumer writer) { - sendPacket(players, makePacket(channel, writer)); - } - - public static void doSend(Iterable players, String channel, byte[] data) { - sendPacket(players, makePacket(channel, data)); - } - - public static void doSend(int dimension, String channel, CustomPayload payload) { - doSend(collectPlayers(p -> p.dimension == dimension), channel, payload); - } - - public static void doSend(int dimension, String channel, IOConsumer writer) { - doSend(collectPlayers(p -> p.dimension == dimension), channel, writer); - } - - public static void doSend(int dimension, String channel, byte[] data) { - doSend(collectPlayers(p -> p.dimension == dimension),channel, data); - } - - public static void doSend(String channel, CustomPayload payload) { - doSend(collectPlayers(p -> true), channel, payload); - } - - public static void doSend(String channel, IOConsumer writer) { - doSend(collectPlayers(p -> true), channel, writer); - } - - public static void doSend(String channel, byte[] data) { - doSend(collectPlayers(p -> true), channel, data); - } - - @SuppressWarnings("unchecked") // thanks proguard - private static Iterable collectPlayers(Predicate filter) { - return collectPlayers(server.playerManager.players, filter); - } - - private static Iterable collectPlayers(Iterable src, Predicate filter) { - List players = new ArrayList<>(); - - for (ServerPlayerEntity player : src) { - if (filter.test(player)) { - players.add(player); - } - } - - return players; - } - - private static Packet makePacket(String channel, CustomPayload payload) { - return makePacket(channel, payload::write); - } - - private static Packet makePacket(String channel, IOConsumer writer) { - try { - return new CustomPayloadPacket(channel, DataStreams.output(writer).toByteArray()); - } catch (IOException e) { - LOGGER.warn("error writing custom payload to channel \'" + channel + "\'", e); - return null; - } - } - - private static Packet makePacket(String channel, byte[] data) { - return new CustomPayloadPacket(channel, data); - } - - private static void sendPacket(ServerPlayerEntity player, Packet packet) { - if (packet != null) { - player.networkHandler.sendPacket(packet); - } - } - - private static void sendPacket(Iterable players, Packet packet) { - if (packet != null) { - for (ServerPlayerEntity player : players) { - sendPacket(player, packet); - } - } - } - - private interface Listener { - - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mcb1.5-mc11w48a/build.gradle b/libraries/networking/networking-mcb1.5-mc11w48a/build.gradle deleted file mode 100644 index 4f17952b..00000000 --- a/libraries/networking/networking-mcb1.5-mc11w48a/build.gradle +++ /dev/null @@ -1,4 +0,0 @@ -setUpModule(project, - 'entrypoints-mcin-20091223-1459-mc1.5.2', - 'lifecycle-events-mcb1.8-pre1-201109081459-mc11w50a' -) diff --git a/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java b/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java deleted file mode 100644 index 237d7e67..00000000 --- a/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java +++ /dev/null @@ -1,13 +0,0 @@ -package net.ornithemc.osl.networking.api; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; - -public interface CustomPayload { - - void read(DataInputStream input) throws IOException; - - void write(DataOutputStream output) throws IOException; - -} diff --git a/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java b/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java deleted file mode 100644 index f68e894c..00000000 --- a/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java +++ /dev/null @@ -1,23 +0,0 @@ -package net.ornithemc.osl.networking.api; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; - -public final class DataStreams { - - public static DataInputStream input(byte[] bytes) { - return new DataInputStream(new ByteArrayInputStream(bytes == null ? new byte[0] : bytes)); - } - - public static ByteArrayOutputStream output(IOConsumer writer) throws IOException { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - DataOutputStream os = new DataOutputStream(bos); - writer.accept(os); - return bos; - } -} diff --git a/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java b/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java deleted file mode 100644 index f0963ed6..00000000 --- a/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/client/ClientConnectionEvents.java +++ /dev/null @@ -1,70 +0,0 @@ -package net.ornithemc.osl.networking.api.client; - -import java.util.function.Consumer; - -import net.minecraft.client.Minecraft; - -import net.ornithemc.osl.core.api.events.Event; - -/** - * Events related to the client side of a client-server connection. - */ -public class ClientConnectionEvents { - - /** - * This event is fired after a successful login occurs. - * - *

- * Note that channel registration happens after login, - * and until then data cannot safely be sent to the server. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ClientConnectionEvents.LOGIN.register(minecraft -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> LOGIN = Event.consumer(); - /** - * This event is fired after login, once channel registration is complete. - * - *

- * This marks the moment data can safely be sent to the server. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ClientConnectionEvents.PLAY_READY.register(minecraft -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> PLAY_READY = Event.consumer(); - /** - * This event is fired when the client disconnects from the server. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ClientConnectionEvents.DISCONNECT.register(minecraft -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> DISCONNECT = Event.consumer(); - -} diff --git a/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java b/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java deleted file mode 100644 index e1594802..00000000 --- a/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java +++ /dev/null @@ -1,158 +0,0 @@ -package net.ornithemc.osl.networking.api.client; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.function.Supplier; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.network.handler.ClientNetworkHandler; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; - -public final class ClientPlayNetworking { - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - ClientPlayNetworkingImpl.registerListener(channel, initializer, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListener(String channel, StreamListener listener) { - ClientPlayNetworkingImpl.registerListener(channel, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - ClientPlayNetworkingImpl.registerListenerRaw(channel, listener); - } - - /** - * Remove the listener registered to the given channel. - */ - public static void unregisterListener(String channel) { - ClientPlayNetworkingImpl.unregisterListener(channel); - } - - /** - * Check whether the connection is ready for data to be sent to the server. - */ - public static boolean isPlayReady() { - return ClientPlayNetworkingImpl.isPlayReady(); - } - - /** - * Check whether the given channel is open for data to be sent through it. - * This method will return {@code false} if the client is not connected to a - * server, or if the server has no listeners for the given channel. - */ - public static boolean canSend(String channel) { - return ClientPlayNetworkingImpl.canSend(channel); - } - - /** - * Send a packet to the server through the given channel. The payload will - * only be written if the channel is open. - */ - public static void send(String channel, CustomPayload payload) { - ClientPlayNetworkingImpl.send(channel, payload); - } - - /** - * Send a packet to the server through the given channel. The writer will - * only be called if the channel is open. - */ - public static void send(String channel, IOConsumer writer) { - ClientPlayNetworkingImpl.send(channel, writer); - } - - /** - * Send a packet to the server through the given channel. - */ - public static void send(String channel, byte[] data) { - ClientPlayNetworkingImpl.send(channel, data); - } - - /** - * Send a packet to the server through the given channel, without checking - * whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the server. - */ - public static void doSend(String channel, CustomPayload payload) { - ClientPlayNetworkingImpl.doSend(channel, payload); - } - - /** - * Send a packet to the server through the given channel, without checking - * whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the server. - */ - public static void doSend(String channel, IOConsumer writer) { - ClientPlayNetworkingImpl.doSend(channel, writer); - } - - /** - * Send a packet to the server through the given channel, without checking - * whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the server. - */ - public static void doSend(String channel, byte[] data) { - ClientPlayNetworkingImpl.doSend(channel, data); - } - - public interface PayloadListener { - - /** - * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(Minecraft minecraft, ClientNetworkHandler handler, T payload) throws IOException; - - } - - public interface StreamListener { - - /** - * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(Minecraft minecraft, ClientNetworkHandler handler, DataInputStream data) throws IOException; - - } - - public interface ByteArrayListener { - - /** - * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(Minecraft minecraft, ClientNetworkHandler handler, byte[] data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java b/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java deleted file mode 100644 index dbe85275..00000000 --- a/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java +++ /dev/null @@ -1,71 +0,0 @@ -package net.ornithemc.osl.networking.api.server; - -import java.util.function.BiConsumer; - -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.entity.mob.player.ServerPlayerEntity; - -import net.ornithemc.osl.core.api.events.Event; - -/** - * Events related to the server side of a client-server connection. - */ -public class ServerConnectionEvents { - - /** - * This event is fired after a successful login occurs. - * - *

- * Note that channel registration happens after login, - * and until then data cannot safely be sent to the client. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ServerConnectionEvents.LOGIN.register((server, player) -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> LOGIN = Event.biConsumer(); - /** - * This event is fired after login, once channel registration is complete. - * - *

- * This marks the moment data can safely be sent to the client. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ServerConnectionEvents.PLAY_READY.register((server, player) -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> PLAY_READY = Event.biConsumer(); - /** - * This event is fired when a client disconnects from the server. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ServerConnectionEvents.DISCONNECT.register((server, player) -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> DISCONNECT = Event.biConsumer(); - -} diff --git a/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java b/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java deleted file mode 100644 index 7eda8cca..00000000 --- a/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java +++ /dev/null @@ -1,321 +0,0 @@ -package net.ornithemc.osl.networking.api.server; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.function.Supplier; - -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.entity.mob.player.ServerPlayerEntity; -import net.minecraft.server.network.handler.ServerPlayNetworkHandler; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -public final class ServerPlayNetworking { - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - ServerPlayNetworkingImpl.registerListener(channel, initializer, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListener(String channel, StreamListener listener) { - ServerPlayNetworkingImpl.registerListener(channel, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - ServerPlayNetworkingImpl.registerListenerRaw(channel, listener); - } - - /** - * Remove the listener registered to the given channel. - */ - public static void unregisterListener(String channel) { - ServerPlayNetworkingImpl.unregisterListener(channel); - } - - /** - * Check whether the connection is ready for data to be sent to the client. - */ - public static boolean isPlayReady(ServerPlayerEntity player) { - return ServerPlayNetworkingImpl.isPlayReady(player); - } - - /** - * Check whether the given channel is open for data to be sent through it. - * This method will return {@code false} if the client has no listeners for - * the given channel. - */ - public static boolean canSend(ServerPlayerEntity player, String channel) { - return ServerPlayNetworkingImpl.canSend(player, channel); - } - - /** - * Send a packet to the given player through the given channel. The payload - * will only be written if the channel is open. - */ - public static void send(ServerPlayerEntity player, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.send(player, channel, payload); - } - - /** - * Send a packet to the given player through the given channel. The writer - * will only be called if the channel is open. - */ - public static void send(ServerPlayerEntity player, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.send(player, channel, writer); - } - - /** - * Send a packet to the given player through the given channel. - */ - public static void send(ServerPlayerEntity player, String channel, byte[] data) { - ServerPlayNetworkingImpl.send(player, channel, data); - } - - /** - * Send a packet to the given players through the given channel. The payload - * will only be written if the channel is open for at least one player. - */ - public static void send(Iterable players, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.send(players, channel, payload); - } - - /** - * Send a packet to the given players through the given channel. The writer - * will only be called if the channel is open for at least one player. - */ - public static void send(Iterable players, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.send(players, channel, writer); - } - - /** - * Send a packet to the given players through the given channel. - */ - public static void send(Iterable players, String channel, byte[] data) { - ServerPlayNetworkingImpl.send(players, channel, data); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel. The payload will only be written if the channel is open for at - * least one player. - */ - public static void send(int dimension, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.send(dimension, channel, payload); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel. The writer will only be called if the channel is open for at - * least one player. - */ - public static void send(int dimension, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.send(dimension, channel, writer); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel. - */ - public static void send(int dimension, String channel, byte[] data) { - ServerPlayNetworkingImpl.send(dimension, channel, data); - } - - /** - * Send a packet to all players through the given channel. The payload will - * only be written if the channel is open for at least one player. - */ - public static void send(String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.send(channel, payload); - } - - /** - * Send a packet to all players through the given channel. The writer will - * only be called if the channel is open for at least one player. - */ - public static void send(String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.send(channel, writer); - } - - /** - * Send a packet to all players through the given channel. - */ - public static void send(String channel, byte[] data) { - ServerPlayNetworkingImpl.send(channel, data); - } - - /** - * Send a packet to the given player through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(ServerPlayerEntity player, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(player, channel, payload); - } - - /** - * Send a packet to the given player through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(ServerPlayerEntity player, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(player, channel, writer); - } - - /** - * Send a packet to the given player through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(ServerPlayerEntity player, String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(player, channel, data); - } - - /** - * Send a packet to the given players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(Iterable players, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(players, channel, payload); - } - - /** - * Send a packet to the given players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(Iterable players, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(players, channel, writer); - } - - /** - * Send a packet to the given players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(Iterable players, String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(players, channel, data); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel, without checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(int dimension, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(dimension, channel, payload); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel, without checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(int dimension, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(dimension, channel, writer); - } - - /** - * Send a packet to the players in the given dimension through the given - * channel, without checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(int dimension, String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(dimension, channel, data); - } - - /** - * Send a packet to all players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(channel, payload); - } - - /** - * Send a packet to all players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(channel, writer); - } - - /** - * Send a packet to all players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(channel, data); - } - - public interface PayloadListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, T payload) throws IOException; - - } - - public interface StreamListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, DataInputStream data) throws IOException; - - } - - public interface ByteArrayListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java b/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java deleted file mode 100644 index 18cff165..00000000 --- a/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java +++ /dev/null @@ -1,57 +0,0 @@ -package net.ornithemc.osl.networking.impl; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.LinkedHashSet; -import java.util.Set; - -import net.minecraft.network.packet.Packet; - -import net.ornithemc.osl.networking.api.Channels; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -public class HandshakePayload implements CustomPayload { - - public static final String CHANNEL = "OSL|Handshake"; - - public Set channels; - - public HandshakePayload() { - } - - public HandshakePayload(Set channels) { - this.channels = channels; - } - - public static HandshakePayload client() { - return new HandshakePayload(ClientPlayNetworkingImpl.LISTENERS.keySet()); - } - - public static HandshakePayload server() { - return new HandshakePayload(ServerPlayNetworkingImpl.LISTENERS.keySet()); - } - - @Override - public void read(DataInputStream input) throws IOException { - channels = new LinkedHashSet<>(); - int channelCount = input.readInt(); - - if (channelCount > 0) { - for (int i = 0; i < channelCount; i++) { - channels.add(Packet.readString(input, Channels.MAX_LENGTH)); - } - } - } - - @Override - public void write(DataOutputStream output) throws IOException { - output.writeInt(channels.size()); - - for (String channel : channels) { - Packet.writeString(channel, output); - } - } -} diff --git a/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java deleted file mode 100644 index 682a1906..00000000 --- a/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java +++ /dev/null @@ -1,58 +0,0 @@ -package net.ornithemc.osl.networking.impl; - -import net.ornithemc.osl.entrypoints.api.ModInitializer; -import net.ornithemc.osl.entrypoints.api.client.ClientModInitializer; -import net.ornithemc.osl.entrypoints.api.server.ServerModInitializer; -import net.ornithemc.osl.lifecycle.api.client.MinecraftClientEvents; -import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; -import net.ornithemc.osl.networking.api.client.ClientConnectionEvents; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking; -import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking; -import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; -import net.ornithemc.osl.networking.impl.mixin.common.PacketAccessor; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -public class Networking implements ModInitializer, ClientModInitializer, ServerModInitializer { - - @Override - public void init() { - PacketAccessor.register(Constants.CUSTOM_PAYLOAD_PACKET_ID, true, true, CustomPayloadPacket.class); - } - - @Override - public void initClient() { - MinecraftClientEvents.START.register(minecraft -> { - ClientPlayNetworkingImpl.setUp(minecraft); - }); - MinecraftClientEvents.STOP.register(minecraft -> { - ClientPlayNetworkingImpl.destroy(minecraft); - }); - ClientPlayNetworking.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { - // send channel registration data as a response to receiving server channel registration data - ClientPlayNetworking.doSend(HandshakePayload.CHANNEL, HandshakePayload.client()); - - ((INetworkHandler)handler).osl$networking$registerChannels(payload.channels); - ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); - - return true; - }); - } - - @Override - public void initServer() { - MinecraftServerEvents.START.register(server -> { - ServerPlayNetworkingImpl.setUp(server); - }); - MinecraftServerEvents.STOP.register(server -> { - ServerPlayNetworkingImpl.destroy(server); - }); - ServerPlayNetworking.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { - ((INetworkHandler)handler).osl$networking$registerChannels(payload.channels); - ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); - - return true; - }); - } -} diff --git a/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java b/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java deleted file mode 100644 index c4eb3d66..00000000 --- a/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java +++ /dev/null @@ -1,168 +0,0 @@ -package net.ornithemc.osl.networking.impl.client; - -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.function.Supplier; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.network.handler.ClientNetworkHandler; -import net.minecraft.network.packet.Packet; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.Channels; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.api.DataStreams; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.ByteArrayListener; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.PayloadListener; -import net.ornithemc.osl.networking.api.client.ClientPlayNetworking.StreamListener; -import net.ornithemc.osl.networking.impl.CustomPayloadPacket; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; - -public final class ClientPlayNetworkingImpl { - - private static final Logger LOGGER = LogManager.getLogger("OSL|Client Play Networking"); - - private static Minecraft minecraft; - - public static void setUp(Minecraft minecraft) { - if (ClientPlayNetworkingImpl.minecraft == minecraft) { - throw new IllegalStateException("tried to set up client networking when it was already set up!"); - } - - ClientPlayNetworkingImpl.minecraft = minecraft; - } - - public static void destroy(Minecraft minecraft) { - if (ClientPlayNetworkingImpl.minecraft != minecraft) { - throw new IllegalStateException("tried to destroy client networking when it was not set up!"); - } - - ClientPlayNetworkingImpl.minecraft = null; - } - - public static final Map LISTENERS = new LinkedHashMap<>(); - - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - registerListenerImpl(channel, (minecraft, handler, data) -> { - T payload = initializer.get(); - payload.read(DataStreams.input(data)); - - return listener.handle(minecraft, handler, payload); - }); - } - - public static void registerListener(String channel, StreamListener listener) { - registerListenerImpl(channel, (minecraft, handler, data) -> { - return listener.handle(minecraft, handler, DataStreams.input(data)); - }); - } - - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - registerListenerImpl(channel, listener::handle); - } - - private static void registerListenerImpl(String channel, Listener listener) { - LISTENERS.compute(channel, (key, value) -> { - Channels.validate(channel); - - if (value != null) { - throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); - } - - return listener; - }); - } - - public static void unregisterListener(String channel) { - LISTENERS.remove(channel); - } - - public static boolean handle(Minecraft minecraft, ClientNetworkHandler handler, CustomPayloadPacket packet) { - Listener listener = LISTENERS.get(packet.channel); - - if (listener != null) { - try { - return listener.handle(minecraft, handler, packet.data); - } catch (IOException e) { - LOGGER.warn("error handling custom payload on channel \'" + packet.channel + "\'", e); - return true; - } - } - - return false; - } - - public static boolean isPlayReady() { - INetworkHandler handler = (INetworkHandler)minecraft.getNetworkHandler(); - return handler != null && handler.osl$networking$isPlayReady(); - } - - public static boolean canSend(String channel) { - INetworkHandler handler = (INetworkHandler)minecraft.getNetworkHandler(); - return handler != null && handler.osl$networking$isRegisteredChannel(channel); - } - - public static void send(String channel, CustomPayload payload) { - if (canSend(channel)) { - doSend(channel, payload); - } - } - - public static void send(String channel, IOConsumer writer) { - if (canSend(channel)) { - doSend(channel, writer); - } - } - - public static void send(String channel, byte[] data) { - if (canSend(channel)) { - doSend(channel, data); - } - } - - public static void doSend(String channel, CustomPayload payload) { - sendPacket(makePacket(channel, payload)); - } - - public static void doSend(String channel, IOConsumer writer) { - sendPacket(makePacket(channel, writer)); - } - - public static void doSend(String channel, byte[] data) { - sendPacket(makePacket(channel, data)); - } - - private static Packet makePacket(String channel, CustomPayload payload) { - return makePacket(channel, payload::write); - } - - private static Packet makePacket(String channel, IOConsumer writer) { - try { - return new CustomPayloadPacket(channel, DataStreams.output(writer).toByteArray()); - } catch (IOException e) { - LOGGER.warn("error writing custom payload to channel \'" + channel + "\'", e); - return null; - } - } - - private static Packet makePacket(String channel, byte[] data) { - return new CustomPayloadPacket(channel, data); - } - - private static void sendPacket(Packet packet) { - if (packet != null) { - minecraft.getNetworkHandler().sendPacket(packet); - } - } - - private interface Listener { - - boolean handle(Minecraft minecraft, ClientNetworkHandler handler, byte[] data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java b/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java deleted file mode 100644 index 711978a2..00000000 --- a/libraries/networking/networking-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java +++ /dev/null @@ -1,269 +0,0 @@ -package net.ornithemc.osl.networking.impl.server; - -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.function.Supplier; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import net.minecraft.network.packet.Packet; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.entity.mob.player.ServerPlayerEntity; -import net.minecraft.server.network.handler.ServerPlayNetworkHandler; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.Channels; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.api.DataStreams; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.ByteArrayListener; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.PayloadListener; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.StreamListener; -import net.ornithemc.osl.networking.impl.CustomPayloadPacket; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; - -public final class ServerPlayNetworkingImpl { - - private static final Logger LOGGER = LogManager.getLogger("OSL|Server Play Networking"); - - private static MinecraftServer server; - - public static void setUp(MinecraftServer server) { - if (ServerPlayNetworkingImpl.server == server) { - throw new IllegalStateException("tried to set up server networking when it was already set up!"); - } - - ServerPlayNetworkingImpl.server = server; - } - - public static void destroy(MinecraftServer server) { - if (ServerPlayNetworkingImpl.server != server) { - throw new IllegalStateException("tried to destroy server networking when it was not set up!"); - } - - ServerPlayNetworkingImpl.server = null; - } - - public static final Map LISTENERS = new LinkedHashMap<>(); - - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - registerListenerImpl(channel, (server, handler, player, data) -> { - T payload = initializer.get(); - payload.read(DataStreams.input(data)); - - return listener.handle(server, handler, player, payload); - }); - } - - public static void registerListener(String channel, StreamListener listener) { - registerListenerImpl(channel, (server, handler, player, data) -> { - return listener.handle(server, handler, player, DataStreams.input(data)); - }); - } - - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - registerListenerImpl(channel, listener::handle); - } - - private static void registerListenerImpl(String channel, Listener listener) { - LISTENERS.compute(channel, (key, value) -> { - Channels.validate(channel); - - if (value != null) { - throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); - } - - return listener; - }); - } - - public static void unregisterListener(String channel) { - LISTENERS.remove(channel); - } - - public static boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, CustomPayloadPacket packet) { - Listener listener = LISTENERS.get(packet.channel); - - if (listener != null) { - try { - return listener.handle(server, handler, player, packet.data); - } catch (IOException e) { - LOGGER.warn("error handling custom payload on channel \'" + packet.channel + "\'", e); - return true; - } - } - - return false; - } - - public static boolean isPlayReady(ServerPlayerEntity player) { - INetworkHandler handler = (INetworkHandler)player.networkHandler; - return handler != null && handler.osl$networking$isPlayReady(); - } - - public static boolean canSend(ServerPlayerEntity player, String channel) { - INetworkHandler handler = (INetworkHandler)player.networkHandler; - return handler != null && handler.osl$networking$isRegisteredChannel(channel); - } - - public static void send(ServerPlayerEntity player, String channel, CustomPayload payload) { - if (canSend(player, channel)) { - doSend(player, channel, payload); - } - } - - public static void send(ServerPlayerEntity player, String channel, IOConsumer writer) { - if (canSend(player, channel)) { - doSend(player, channel, writer); - } - } - - public static void send(ServerPlayerEntity player, String channel, byte[] data) { - if (canSend(player, channel)) { - doSend(player, channel, data); - } - } - - public static void send(Iterable players, String channel, CustomPayload payload) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, payload)); - } - - public static void send(Iterable players, String channel, IOConsumer writer) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, writer)); - } - - public static void send(Iterable players, String channel, byte[] data) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, data)); - } - - public static void send(int dimension, String channel, CustomPayload payload) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)), channel, payload); - } - - public static void send(int dimension, String channel, IOConsumer writer) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)), channel, writer); - } - - public static void send(int dimension, String channel, byte[] data) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)),channel, data); - } - - public static void send(String channel, CustomPayload payload) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, payload); - } - - public static void send(String channel, IOConsumer writer) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, writer); - } - - public static void send(String channel, byte[] data) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, data); - } - - public static void doSend(ServerPlayerEntity player, String channel, CustomPayload payload) { - sendPacket(player, makePacket(channel, payload)); - } - - public static void doSend(ServerPlayerEntity player, String channel, IOConsumer writer) { - sendPacket(player, makePacket(channel, writer)); - } - - public static void doSend(ServerPlayerEntity player, String channel, byte[] data) { - sendPacket(player, makePacket(channel, data)); - } - - public static void doSend(Iterable players, String channel, CustomPayload payload) { - sendPacket(players, makePacket(channel, payload)); - } - - public static void doSend(Iterable players, String channel, IOConsumer writer) { - sendPacket(players, makePacket(channel, writer)); - } - - public static void doSend(Iterable players, String channel, byte[] data) { - sendPacket(players, makePacket(channel, data)); - } - - public static void doSend(int dimension, String channel, CustomPayload payload) { - doSend(collectPlayers(p -> p.dimension == dimension), channel, payload); - } - - public static void doSend(int dimension, String channel, IOConsumer writer) { - doSend(collectPlayers(p -> p.dimension == dimension), channel, writer); - } - - public static void doSend(int dimension, String channel, byte[] data) { - doSend(collectPlayers(p -> p.dimension == dimension),channel, data); - } - - public static void doSend(String channel, CustomPayload payload) { - doSend(collectPlayers(p -> true), channel, payload); - } - - public static void doSend(String channel, IOConsumer writer) { - doSend(collectPlayers(p -> true), channel, writer); - } - - public static void doSend(String channel, byte[] data) { - doSend(collectPlayers(p -> true), channel, data); - } - - @SuppressWarnings("unchecked") // thanks proguard - private static Iterable collectPlayers(Predicate filter) { - return collectPlayers(server.playerManager.players, filter); - } - - private static Iterable collectPlayers(Iterable src, Predicate filter) { - List players = new ArrayList<>(); - - for (ServerPlayerEntity player : src) { - if (filter.test(player)) { - players.add(player); - } - } - - return players; - } - - private static Packet makePacket(String channel, CustomPayload payload) { - return makePacket(channel, payload::write); - } - - private static Packet makePacket(String channel, IOConsumer writer) { - try { - return new CustomPayloadPacket(channel, DataStreams.output(writer).toByteArray()); - } catch (IOException e) { - LOGGER.warn("error writing custom payload to channel \'" + channel + "\'", e); - return null; - } - } - - private static Packet makePacket(String channel, byte[] data) { - return new CustomPayloadPacket(channel, data); - } - - private static void sendPacket(ServerPlayerEntity player, Packet packet) { - if (packet != null) { - player.networkHandler.sendPacket(packet); - } - } - - private static void sendPacket(Iterable players, Packet packet) { - if (packet != null) { - for (ServerPlayerEntity player : players) { - sendPacket(player, packet); - } - } - } - - private interface Listener { - - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/build.gradle b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/build.gradle similarity index 100% rename from libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/build.gradle rename to libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/build.gradle diff --git a/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/gradle.properties b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/gradle.properties similarity index 63% rename from libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/gradle.properties rename to libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/gradle.properties index ba01cbea..cf5879ed 100644 --- a/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/gradle.properties +++ b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/gradle.properties @@ -1,7 +1,7 @@ environment = server -min_mc_version = server-a0.1.2_01 +min_mc_version = server-a0.1.0 max_mc_version = server-a0.2.1 -mc_version_range = >=1.0.0-alpha.1.2.1 <=1.0.0-alpha.2.1 +mc_version_range = >=1.0.0-alpha.1.0 <=1.0.0-alpha.2.1 minecraft_version = server-a0.2.1 feather_build = 1 diff --git a/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/PacketBuffer.java b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/PacketBuffer.java new file mode 100644 index 00000000..332c2370 --- /dev/null +++ b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/PacketBuffer.java @@ -0,0 +1,1217 @@ +package net.ornithemc.osl.networking.api; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.channels.FileChannel; +import java.nio.channels.GatheringByteChannel; +import java.nio.channels.ScatteringByteChannel; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.UUID; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufInputStream; +import io.netty.buffer.ByteBufOutputStream; +import io.netty.util.ByteProcessor; + +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtIo; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.NamespacedIdentifiers; + +public class PacketBuffer extends ByteBuf { + + private static final int VAR_VALUE_BITS = 7; + private static final int VAR_VALUE_MASK = 1 << VAR_VALUE_BITS - 1; + private static final int VAR_PARITY_VALUE = 1 << VAR_VALUE_BITS; + private static final int VAR_INT_MAX_BYTES = 5; + private static final int VAR_LONG_MAX_BYTES = 10; + + final ByteBuf delegate; + + public PacketBuffer(ByteBuf delegate) { + this.delegate = delegate; + } + + public int readVarInt() { + int value = 0; + + byte bytes = 0; + byte nextByte = 0; + + do { + nextByte = this.readByte(); + value |= (nextByte & VAR_VALUE_MASK) << bytes++ * VAR_VALUE_BITS; + + if (bytes > VAR_INT_MAX_BYTES) { + throw new RuntimeException("VarInt too big"); + } + } while ((nextByte & VAR_PARITY_VALUE) == VAR_PARITY_VALUE); + + return value; + } + + public long readVarLong() { + long value = 0; + + byte bytes = 0; + byte nextByte = 0; + + do { + nextByte = this.readByte(); + value |= (nextByte & VAR_VALUE_MASK) << bytes++ * VAR_VALUE_BITS; + + if (bytes > VAR_LONG_MAX_BYTES) { + throw new RuntimeException("VarLong too big"); + } + } while ((nextByte & VAR_PARITY_VALUE) == VAR_PARITY_VALUE); + + return value; + } + + public byte[] readByteArray() { + return this.readByteArray(this.readableBytes()); + } + + public byte[] readByteArray(int maxLength) { + int length = this.readVarInt(); + + if (length > maxLength) { + throw new RuntimeException("ByteArray with size " + length + " is bigger than allowed " + maxLength); + } + + byte[] values = new byte[length]; + + for (int i = 0; i < length; i++) { + values[i] = this.readByte(); + } + + return values; + } + + public int[] readIntArray() { + return this.readIntArray(this.readableBytes()); + } + + public int[] readIntArray(int maxLength) { + int length = this.readVarInt(); + + if (length > maxLength) { + throw new RuntimeException("IntArray with size " + length + " is bigger than allowed " + maxLength); + } + + int[] values = new int[length]; + + for (int i = 0; i < length; i++) { + values[i] = this.readVarInt(); + } + + return values; + } + + public long[] readLongArray() { + return this.readLongArray(this.readableBytes() / 8); + } + + public long[] readLongArray(int maxLength) { + int length = this.readVarInt(); + + if (length > maxLength) { + throw new IllegalStateException("LongArray with size " + length + " is bigger than allowed " + maxLength); + } + + long[] values = new long[length]; + + for (int i = 0; i < length; i++) { + values[i] = this.readVarLong(); + } + + return values; + } + + public String readString() { + return this.readString(Short.MAX_VALUE); + } + + public String readString(int maxLength) { + int length = this.readVarInt(); + + if (length > maxLength * 4) { + throw new RuntimeException("The received encoded string buffer length is longer than maximum allowed (" + length + " > " + maxLength * 4 + ")"); + } + if (length < 0) { + throw new RuntimeException("The received encoded string buffer length is less than zero! Weird string!"); + } + + String s = this.toString(this.readerIndex(), length, StandardCharsets.UTF_8); + this.readerIndex(this.readerIndex() + length); + + if (s.length() > maxLength) { + throw new RuntimeException("The received string length is longer than maximum allowed (" + length + " > " + maxLength + ")"); + } + + return s; + } + + public > T readEnum(Class type) { + return type.getEnumConstants()[this.readVarInt()]; + } + + public Date readDate() { + return new Date(this.readLong()); + } + + public UUID readUuid() { + return new UUID( + this.readLong(), + this.readLong() + ); + } + + public NamespacedIdentifier readNamespacedIdentifier() { + return NamespacedIdentifiers.parse(this.readString()); + } + + public NbtCompound readNbtCompound() { + int readerIndex = this.readerIndex(); + byte firstByte = this.readByte(); + + if (firstByte == 0) { + return null; + } else { + this.readerIndex(readerIndex); + + try { + return NbtIo.read(new ByteBufInputStream(this)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + public ByteBuf writeVarInt(int value) { + while ((value & -128) != 0) { + this.writeByte(value & VAR_VALUE_MASK | VAR_PARITY_VALUE); + value >>>= VAR_VALUE_BITS; + } + + this.writeByte(value); + + return this; + } + + public ByteBuf writeVarLong(long value) { + while ((value & -128) != 0) { + this.writeByte((int) (value & VAR_VALUE_MASK) | VAR_PARITY_VALUE); + value >>>= VAR_VALUE_BITS; + } + + this.writeByte((int) value); + + return this; + } + + public ByteBuf writeByteArray(byte[] values) { + this.writeVarInt(values.length); + + for (byte value : values) { + this.writeByte(value); + } + + return this; + } + + public ByteBuf writeIntArray(int[] values) { + this.writeVarInt(values.length); + + for (int value : values) { + this.writeVarInt(value); + } + + return this; + } + + public ByteBuf writeLongArray(long[] values) { + this.writeVarInt(values.length); + + for (long value : values) { + this.writeVarLong(value); + } + + return this; + } + + public ByteBuf writeString(String s) { + return this.writeString(s, Short.MAX_VALUE); + } + + public ByteBuf writeString(String s, int maxLength) { + byte[] bytes = s.getBytes(StandardCharsets.UTF_8); + + if (bytes.length > maxLength) { + throw new RuntimeException("String too big (was " + bytes.length + " bytes encoded, max " + maxLength + ")"); + } + + this.writeByteArray(bytes); + + return this; + } + + public ByteBuf writeEnum(Enum value) { + this.writeVarInt(value.ordinal()); + + return this; + } + + public ByteBuf writeDate(Date date) { + this.writeLong(date.getTime()); + + return this; + } + + public ByteBuf writeUuid(UUID uuid) { + this.writeLong(uuid.getMostSignificantBits()); + this.writeLong(uuid.getLeastSignificantBits()); + + return this; + } + + public ByteBuf writeNamespacedIdentifier(NamespacedIdentifier id) { + return this.writeString(id.toString()); + } + + public ByteBuf writeNbtCompound(NbtCompound nbt) { + if (nbt == null) { + this.writeByte(0); + } else { + try { + NbtIo.write(nbt, new ByteBufOutputStream(this)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + return this; + } + + @Override + public int capacity() { + return this.delegate.capacity(); + } + + @Override + public ByteBuf capacity(int newCapacity) { + return this.delegate.capacity(newCapacity); + } + + @Override + public int maxCapacity() { + return this.delegate.maxCapacity(); + } + + @Override + public ByteBufAllocator alloc() { + return this.delegate.alloc(); + } + + @Override + public ByteOrder order() { + return this.delegate.order(); + } + + @Override + public ByteBuf order(ByteOrder order) { + return this.delegate.order(order); + } + + @Override + public ByteBuf unwrap() { + return this.delegate.unwrap(); + } + + @Override + public boolean isDirect() { + return this.delegate.isDirect(); + } + + @Override + public boolean isReadOnly() { + return this.delegate.isReadOnly(); + } + + @Override + public ByteBuf asReadOnly() { + return this.delegate.asReadOnly(); + } + + @Override + public int readerIndex() { + return this.delegate.readerIndex(); + } + + @Override + public ByteBuf readerIndex(int readerIndex) { + return this.delegate.readerIndex(readerIndex); + } + + @Override + public int writerIndex() { + return this.delegate.writerIndex(); + } + + @Override + public ByteBuf writerIndex(int writerIndex) { + return this.delegate.writerIndex(writerIndex); + } + + @Override + public ByteBuf setIndex(int readerIndex, int writerIndex) { + return this.delegate.setIndex(readerIndex, writerIndex); + } + + @Override + public int readableBytes() { + return this.delegate.readableBytes(); + } + + @Override + public int writableBytes() { + return this.delegate.writableBytes(); + } + + @Override + public int maxWritableBytes() { + return this.delegate.maxWritableBytes(); + } + + @Override + public boolean isReadable() { + return this.delegate.isReadable(); + } + + @Override + public boolean isReadable(int size) { + return this.delegate.isReadable(size); + } + + @Override + public boolean isWritable() { + return this.delegate.isWritable(); + } + + @Override + public boolean isWritable(int size) { + return this.delegate.isWritable(size); + } + + @Override + public ByteBuf clear() { + return this.delegate.clear(); + } + + @Override + public ByteBuf markReaderIndex() { + return this.delegate.markReaderIndex(); + } + + @Override + public ByteBuf resetReaderIndex() { + return this.delegate.resetReaderIndex(); + } + + @Override + public ByteBuf markWriterIndex() { + return this.delegate.markWriterIndex(); + } + + @Override + public ByteBuf resetWriterIndex() { + return this.delegate.resetWriterIndex(); + } + + @Override + public ByteBuf discardReadBytes() { + return this.delegate.discardReadBytes(); + } + + @Override + public ByteBuf discardSomeReadBytes() { + return this.delegate.discardSomeReadBytes(); + } + + @Override + public ByteBuf ensureWritable(int minWritableBytes) { + return this.delegate.ensureWritable(minWritableBytes); + } + + @Override + public int ensureWritable(int minWritableBytes, boolean force) { + return this.delegate.ensureWritable(minWritableBytes, force); + } + + @Override + public boolean getBoolean(int index) { + return this.delegate.getBoolean(index); + } + + @Override + public byte getByte(int index) { + return this.delegate.getByte(index); + } + + @Override + public short getUnsignedByte(int index) { + return this.delegate.getUnsignedByte(index); + } + + @Override + public short getShort(int index) { + return this.delegate.getShort(index); + } + + @Override + public short getShortLE(int index) { + return this.delegate.getShortLE(index); + } + + @Override + public int getUnsignedShort(int index) { + return this.delegate.getUnsignedShort(index); + } + + @Override + public int getUnsignedShortLE(int index) { + return this.delegate.getUnsignedShortLE(index); + } + + @Override + public int getMedium(int index) { + return this.delegate.getMedium(index); + } + + @Override + public int getMediumLE(int index) { + return this.delegate.getMediumLE(index); + } + + @Override + public int getUnsignedMedium(int index) { + return this.delegate.getUnsignedMedium(index); + } + + @Override + public int getUnsignedMediumLE(int index) { + return this.delegate.getUnsignedMediumLE(index); + } + + @Override + public int getInt(int index) { + return this.delegate.getInt(index); + } + + @Override + public int getIntLE(int index) { + return this.delegate.getIntLE(index); + } + + @Override + public long getUnsignedInt(int index) { + return this.delegate.getUnsignedInt(index); + } + + @Override + public long getUnsignedIntLE(int index) { + return this.delegate.getUnsignedIntLE(index); + } + + @Override + public long getLong(int index) { + return this.delegate.getLong(index); + } + + @Override + public long getLongLE(int index) { + return this.delegate.getLongLE(index); + } + + @Override + public char getChar(int index) { + return this.delegate.getChar(index); + } + + @Override + public float getFloat(int index) { + return this.delegate.getFloat(index); + } + + @Override + public double getDouble(int index) { + return this.delegate.getDouble(index); + } + + @Override + public ByteBuf getBytes(int index, ByteBuf dst) { + return this.delegate.getBytes(index, dst); + } + + @Override + public ByteBuf getBytes(int index, ByteBuf dst, int length) { + return this.delegate.getBytes(index, dst, length); + } + + @Override + public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) { + return this.delegate.getBytes(index, dst, dstIndex, length); + } + + @Override + public ByteBuf getBytes(int index, byte[] dst) { + return this.delegate.getBytes(index, dst); + } + + @Override + public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) { + return this.delegate.getBytes(index, dst, dstIndex, length); + } + + @Override + public ByteBuf getBytes(int index, ByteBuffer dst) { + return this.delegate.getBytes(index, dst); + } + + @Override + public ByteBuf getBytes(int index, OutputStream out, int length) throws IOException { + return this.delegate.getBytes(index, out, length); + } + + @Override + public int getBytes(int index, GatheringByteChannel out, int length) throws IOException { + return this.delegate.getBytes(index, out, length); + } + + @Override + public int getBytes(int index, FileChannel out, long position, int length) throws IOException { + return this.delegate.getBytes(index, out, position, length); + } + + @Override + public CharSequence getCharSequence(int index, int length, Charset charset) { + return this.delegate.getCharSequence(index, length, charset); + } + + @Override + public ByteBuf setBoolean(int index, boolean value) { + return this.delegate.setBoolean(index, value); + } + + @Override + public ByteBuf setByte(int index, int value) { + return this.delegate.setByte(index, value); + } + + @Override + public ByteBuf setShort(int index, int value) { + return this.delegate.setShort(index, value); + } + + @Override + public ByteBuf setShortLE(int index, int value) { + return this.delegate.setShortLE(index, value); + } + + @Override + public ByteBuf setMedium(int index, int value) { + return this.delegate.setMedium(index, value); + } + + @Override + public ByteBuf setMediumLE(int index, int value) { + return this.delegate.setMediumLE(index, value); + } + + @Override + public ByteBuf setInt(int index, int value) { + return this.delegate.setInt(index, value); + } + + @Override + public ByteBuf setIntLE(int index, int value) { + return this.delegate.setIntLE(index, value); + } + + @Override + public ByteBuf setLong(int index, long value) { + return this.delegate.setLong(index, value); + } + + @Override + public ByteBuf setLongLE(int index, long value) { + return this.delegate.setLongLE(index, value); + } + + @Override + public ByteBuf setChar(int index, int value) { + return this.delegate.setChar(index, value); + } + + @Override + public ByteBuf setFloat(int index, float value) { + return this.delegate.setFloat(index, value); + } + + @Override + public ByteBuf setDouble(int index, double value) { + return this.delegate.setDouble(index, value); + } + + @Override + public ByteBuf setBytes(int index, ByteBuf src) { + return this.delegate.setBytes(index, src); + } + + @Override + public ByteBuf setBytes(int index, ByteBuf src, int length) { + return this.delegate.setBytes(index, src, length); + } + + @Override + public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) { + return this.delegate.setBytes(index, src, srcIndex, length); + } + + @Override + public ByteBuf setBytes(int index, byte[] src) { + return this.delegate.setBytes(index, src); + } + + @Override + public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) { + return this.delegate.setBytes(index, src, srcIndex, length); + } + + @Override + public ByteBuf setBytes(int index, ByteBuffer src) { + return this.delegate.setBytes(index, src); + } + + @Override + public int setBytes(int index, InputStream in, int length) throws IOException { + return this.delegate.setBytes(index, in, length); + } + + @Override + public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException { + return this.delegate.setBytes(index, in, length); + } + + @Override + public int setBytes(int index, FileChannel in, long position, int length) throws IOException { + return this.delegate.setBytes(index, in, position, length); + } + + @Override + public ByteBuf setZero(int index, int length) { + return this.delegate.setZero(index, length); + } + + @Override + public int setCharSequence(int index, CharSequence sequence, Charset charset) { + return this.delegate.setCharSequence(index, sequence, charset); + } + + @Override + public boolean readBoolean() { + return this.delegate.readBoolean(); + } + + @Override + public byte readByte() { + return this.delegate.readByte(); + } + + @Override + public short readUnsignedByte() { + return this.delegate.readUnsignedByte(); + } + + @Override + public short readShort() { + return this.delegate.readShort(); + } + + @Override + public short readShortLE() { + return this.delegate.readShortLE(); + } + + @Override + public int readUnsignedShort() { + return this.delegate.readUnsignedShort(); + } + + @Override + public int readUnsignedShortLE() { + return this.delegate.readUnsignedShortLE(); + } + + @Override + public int readMedium() { + return this.delegate.readMedium(); + } + + @Override + public int readMediumLE() { + return this.delegate.readMediumLE(); + } + + @Override + public int readUnsignedMedium() { + return this.delegate.readUnsignedMedium(); + } + + @Override + public int readUnsignedMediumLE() { + return this.delegate.readUnsignedMediumLE(); + } + + @Override + public int readInt() { + return this.delegate.readInt(); + } + + @Override + public int readIntLE() { + return this.delegate.readIntLE(); + } + + @Override + public long readUnsignedInt() { + return this.delegate.readUnsignedInt(); + } + + @Override + public long readUnsignedIntLE() { + return this.delegate.readUnsignedIntLE(); + } + + @Override + public long readLong() { + return this.delegate.readLong(); + } + + @Override + public long readLongLE() { + return this.delegate.readLongLE(); + } + + @Override + public char readChar() { + return this.delegate.readChar(); + } + + @Override + public float readFloat() { + return this.delegate.readFloat(); + } + + @Override + public double readDouble() { + return this.delegate.readDouble(); + } + + @Override + public ByteBuf readBytes(int length) { + return this.delegate.readBytes(length); + } + + @Override + public ByteBuf readSlice(int length) { + return this.delegate.readSlice(length); + } + + @Override + public ByteBuf readRetainedSlice(int length) { + return this.delegate.readRetainedSlice(length); + } + + @Override + public ByteBuf readBytes(ByteBuf dst) { + return this.delegate.readBytes(dst); + } + + @Override + public ByteBuf readBytes(ByteBuf dst, int length) { + return this.delegate.readBytes(dst, length); + } + + @Override + public ByteBuf readBytes(ByteBuf dst, int dstIndex, int length) { + return this.delegate.readBytes(dst, dstIndex, length); + } + + @Override + public ByteBuf readBytes(byte[] dst) { + return this.delegate.readBytes(dst); + } + + @Override + public ByteBuf readBytes(byte[] dst, int dstIndex, int length) { + return this.delegate.readBytes(dst, dstIndex, length); + } + + @Override + public ByteBuf readBytes(ByteBuffer dst) { + return this.delegate.readBytes(dst); + } + + @Override + public ByteBuf readBytes(OutputStream out, int length) throws IOException { + return this.delegate.readBytes(out, length); + } + + @Override + public int readBytes(GatheringByteChannel out, int length) throws IOException { + return this.delegate.readBytes(out, length); + } + + @Override + public CharSequence readCharSequence(int length, Charset charset) { + return this.delegate.readCharSequence(length, charset); + } + + @Override + public int readBytes(FileChannel out, long position, int length) throws IOException { + return this.delegate.readBytes(out, position, length); + } + + @Override + public ByteBuf skipBytes(int length) { + return this.delegate.skipBytes(length); + } + + @Override + public ByteBuf writeBoolean(boolean value) { + return this.delegate.writeBoolean(value); + } + + @Override + public ByteBuf writeByte(int value) { + return this.delegate.writeByte(value); + } + + @Override + public ByteBuf writeShort(int value) { + return this.delegate.writeShort(value); + } + + @Override + public ByteBuf writeShortLE(int value) { + return this.delegate.writeShortLE(value); + } + + @Override + public ByteBuf writeMedium(int value) { + return this.delegate.writeMedium(value); + } + + @Override + public ByteBuf writeMediumLE(int value) { + return this.delegate.writeMediumLE(value); + } + + @Override + public ByteBuf writeInt(int value) { + return this.delegate.writeInt(value); + } + + @Override + public ByteBuf writeIntLE(int value) { + return this.delegate.writeIntLE(value); + } + + @Override + public ByteBuf writeLong(long value) { + return this.delegate.writeLong(value); + } + + @Override + public ByteBuf writeLongLE(long value) { + return this.delegate.writeLongLE(value); + } + + @Override + public ByteBuf writeChar(int value) { + return this.delegate.writeChar(value); + } + + @Override + public ByteBuf writeFloat(float value) { + return this.delegate.writeFloat(value); + } + + @Override + public ByteBuf writeDouble(double value) { + return this.delegate.writeDouble(value); + } + + @Override + public ByteBuf writeBytes(ByteBuf src) { + return this.delegate.writeBytes(src); + } + + @Override + public ByteBuf writeBytes(ByteBuf src, int length) { + return this.delegate.writeBytes(src, length); + } + + @Override + public ByteBuf writeBytes(ByteBuf src, int srcIndex, int length) { + return this.delegate.writeBytes(src, srcIndex, length); + } + + @Override + public ByteBuf writeBytes(byte[] src) { + return this.delegate.writeBytes(src); + } + + @Override + public ByteBuf writeBytes(byte[] src, int srcIndex, int length) { + return this.delegate.writeBytes(src, srcIndex, length); + } + + @Override + public ByteBuf writeBytes(ByteBuffer src) { + return this.delegate.writeBytes(src); + } + + @Override + public int writeBytes(InputStream in, int length) throws IOException { + return this.delegate.writeBytes(in, length); + } + + @Override + public int writeBytes(ScatteringByteChannel in, int length) throws IOException { + return this.delegate.writeBytes(in, length); + } + + @Override + public int writeBytes(FileChannel in, long position, int length) throws IOException { + return this.delegate.writeBytes(in, position, length); + } + + @Override + public ByteBuf writeZero(int length) { + return this.delegate.writeZero(length); + } + + @Override + public int writeCharSequence(CharSequence sequence, Charset charset) { + return this.delegate.writeCharSequence(sequence, charset); + } + + @Override + public int indexOf(int fromIndex, int toIndex, byte value) { + return this.delegate.indexOf(fromIndex, toIndex, value); + } + + @Override + public int bytesBefore(byte value) { + return this.delegate.bytesBefore(value); + } + + @Override + public int bytesBefore(int length, byte value) { + return this.delegate.bytesBefore(length, value); + } + + @Override + public int bytesBefore(int index, int length, byte value) { + return this.delegate.bytesBefore(index, length, value); + } + + @Override + public int forEachByte(ByteProcessor processor) { + return this.delegate.forEachByte(processor); + } + + @Override + public int forEachByte(int index, int length, ByteProcessor processor) { + return this.delegate.forEachByte(index, length, processor); + } + + @Override + public int forEachByteDesc(ByteProcessor processor) { + return this.delegate.forEachByteDesc(processor); + } + + @Override + public int forEachByteDesc(int index, int length, ByteProcessor processor) { + return this.delegate.forEachByteDesc(index, length, processor); + } + + @Override + public ByteBuf copy() { + return this.delegate.copy(); + } + + @Override + public ByteBuf copy(int index, int length) { + return this.delegate.copy(index, length); + } + + @Override + public ByteBuf slice() { + return this.delegate.slice(); + } + + @Override + public ByteBuf retainedSlice() { + return this.delegate.retainedSlice(); + } + + @Override + public ByteBuf slice(int index, int length) { + return this.delegate.slice(index, length); + } + + @Override + public ByteBuf retainedSlice(int index, int length) { + return this.delegate.retainedSlice(index, length); + } + + @Override + public ByteBuf duplicate() { + return this.delegate.duplicate(); + } + + @Override + public ByteBuf retainedDuplicate() { + return this.delegate.retainedDuplicate(); + } + + @Override + public int nioBufferCount() { + return this.delegate.nioBufferCount(); + } + + @Override + public ByteBuffer nioBuffer() { + return this.delegate.nioBuffer(); + } + + @Override + public ByteBuffer nioBuffer(int index, int length) { + return this.delegate.nioBuffer(index, length); + } + + @Override + public ByteBuffer internalNioBuffer(int index, int length) { + return this.delegate.internalNioBuffer(index, length); + } + + @Override + public ByteBuffer[] nioBuffers() { + return this.delegate.nioBuffers(); + } + + @Override + public ByteBuffer[] nioBuffers(int index, int length) { + return this.delegate.nioBuffers(index, length); + } + + @Override + public boolean hasArray() { + return this.delegate.hasArray(); + } + + @Override + public byte[] array() { + return this.delegate.array(); + } + + @Override + public int arrayOffset() { + return this.delegate.arrayOffset(); + } + + @Override + public boolean hasMemoryAddress() { + return this.delegate.hasMemoryAddress(); + } + + @Override + public long memoryAddress() { + return this.delegate.memoryAddress(); + } + + @Override + public String toString(Charset charset) { + return this.delegate.toString(charset); + } + + @Override + public String toString(int index, int length, Charset charset) { + return this.delegate.toString(index, length, charset); + } + + @Override + public int hashCode() { + return this.delegate.hashCode(); + } + + @Override + public boolean equals(Object o) { + return this.delegate.equals(o); + } + + @Override + public int compareTo(ByteBuf o) { + return this.delegate.compareTo(o); + } + + @Override + public String toString() { + return this.delegate.toString(); + } + + @Override + public ByteBuf retain(int increment) { + return this.delegate.retain(increment); + } + + @Override + public ByteBuf retain() { + return this.delegate.retain(); + } + + @Override + public ByteBuf touch() { + return this.delegate.touch(); + } + + @Override + public ByteBuf touch(Object hint) { + return this.delegate.touch(hint); + } + + @Override + public int refCnt() { + return this.delegate.refCnt(); + } + + @Override + public boolean release() { + return this.delegate.release(); + } + + @Override + public boolean release(int decrement) { + return this.delegate.release(decrement); + } +} diff --git a/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/PacketBuffers.java b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/PacketBuffers.java new file mode 100644 index 00000000..a9e6ccc8 --- /dev/null +++ b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/PacketBuffers.java @@ -0,0 +1,35 @@ +package net.ornithemc.osl.networking.api; + +import java.io.IOException; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; + +import net.ornithemc.osl.core.api.util.function.IOConsumer; + +public final class PacketBuffers { + + public static PacketBuffer make() { + return wrapped(Unpooled.buffer()); + } + + public static PacketBuffer make(IOConsumer writer) throws IOException { + PacketBuffer buffer = make(); + writer.accept(buffer); + return buffer; + } + + public static PacketBuffer wrap(byte[] bytes) { + return wrapped(Unpooled.wrappedBuffer(bytes)); + } + + public static byte[] unwrap(PacketBuffer buffer) { + byte[] bytes = new byte[buffer.writerIndex()]; + buffer.getBytes(0, bytes); + return bytes; + } + + public static PacketBuffer wrapped(ByteBuf buffer) { + return new PacketBuffer(buffer); + } +} diff --git a/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/PacketPayload.java b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/PacketPayload.java new file mode 100644 index 00000000..7f7835e7 --- /dev/null +++ b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/PacketPayload.java @@ -0,0 +1,11 @@ +package net.ornithemc.osl.networking.api; + +import java.io.IOException; + +public interface PacketPayload { + + void read(PacketBuffer buffer) throws IOException; + + void write(PacketBuffer buffer) throws IOException; + +} diff --git a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java similarity index 96% rename from libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java rename to libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java index e248c524..9d33bccf 100644 --- a/libraries/networking/networking-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java +++ b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java @@ -3,7 +3,7 @@ import java.util.function.BiConsumer; import net.minecraft.server.MinecraftServer; -import net.minecraft.server.entity.living.player.ServerPlayerEntity; +import net.minecraft.server.entity.mob.player.ServerPlayerEntity; import net.ornithemc.osl.core.api.events.Event; diff --git a/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java new file mode 100644 index 00000000..1ec5a4f0 --- /dev/null +++ b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java @@ -0,0 +1,32 @@ +package net.ornithemc.osl.networking.api.server; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.entity.mob.player.ServerPlayerEntity; +import net.minecraft.server.network.handler.ServerPlayNetworkHandler; + +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketPayload; + +public interface ServerPacketListener { + + /** + * Receive incoming data from the client. + * + * @return + * Whether the data is consumed. Should only return {@code false} if the + * data is completely ignored. + */ + boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, T data); + + @FunctionalInterface + public interface Payload extends ServerPacketListener { + } + + @FunctionalInterface + public interface Buffer extends ServerPacketListener { + } + + @FunctionalInterface + public interface Bytes extends ServerPacketListener { + } +} diff --git a/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java new file mode 100644 index 00000000..23ee3976 --- /dev/null +++ b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java @@ -0,0 +1,295 @@ +package net.ornithemc.osl.networking.api.server; + +import java.util.function.Supplier; + +import net.minecraft.server.entity.mob.player.ServerPlayerEntity; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.function.IOConsumer; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketPayload; +import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; + +public final class ServerPlayNetworking { + + /** + * Register a listener to receive data from the server through the given channel. + * This listener will only be called from the main thread. + */ + public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { + ServerPlayNetworkingImpl.registerListener(channel, initializer, listener); + } + + /** + * Register a listener to receive data from the server through the given channel. + * This listener may be called off the main thread. + */ + public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { + ServerPlayNetworkingImpl.registerListenerAsync(channel, initializer, listener); + } + + /** + * Register a listener to receive data from the server through the given channel. + * This listener will only be called from the main thread. + */ + public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { + ServerPlayNetworkingImpl.registerListener(channel, listener); + } + + /** + * Register a listener to receive data from the server through the given channel. + * This listener may be called off the main thread. + */ + public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { + ServerPlayNetworkingImpl.registerListenerAsync(channel, listener); + } + + /** + * Register a listener to receive data from the server through the given channel. + * This listener will only be called from the main thread. + */ + public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { + ServerPlayNetworkingImpl.registerListener(channel, listener); + } + + /** + * Register a listener to receive data from the server through the given channel. + * This listener may be called off the main thread. + */ + public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { + ServerPlayNetworkingImpl.registerListenerAsync(channel, listener); + } + + /** + * Remove the listener registered to the given channel. + */ + public static void unregisterListener(NamespacedIdentifier channel) { + ServerPlayNetworkingImpl.unregisterListener(channel); + } + + /** + * Check whether the connection is ready for data to be sent to the client. + */ + public static boolean isPlayReady(ServerPlayerEntity player) { + return ServerPlayNetworkingImpl.isPlayReady(player); + } + + /** + * Check whether the given channel is ready for data to be sent through it. + * This method will return {@code false} if the client has no listeners for + * the given channel. + */ + public static boolean isPlayReady(ServerPlayerEntity player, NamespacedIdentifier channel) { + return ServerPlayNetworkingImpl.isPlayReady(player, channel); + } + + /** + * Send a packet to the given player through the given channel. The payload + * will only be written if the channel is open. + */ + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, PacketPayload payload) { + ServerPlayNetworkingImpl.send(player, channel, payload); + } + + /** + * Send a packet to the given player through the given channel. The writer + * will only be called if the channel is open. + */ + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, IOConsumer writer) { + ServerPlayNetworkingImpl.send(player, channel, writer); + } + + /** + * Send a packet to the given player through the given channel. + */ + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, PacketBuffer buffer) { + ServerPlayNetworkingImpl.send(player, channel, buffer); + } + + /** + * Send a packet to the given player through the given channel. + */ + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, byte[] bytes) { + ServerPlayNetworkingImpl.send(player, channel, bytes); + } + + /** + * Send a packet to the given players through the given channel. The payload + * will only be written if the channel is open for at least one player. + */ + public static void send(Iterable players, NamespacedIdentifier channel, PacketPayload payload) { + ServerPlayNetworkingImpl.send(players, channel, payload); + } + + /** + * Send a packet to the given players through the given channel. The writer + * will only be called if the channel is open for at least one player. + */ + public static void send(Iterable players, NamespacedIdentifier channel, IOConsumer writer) { + ServerPlayNetworkingImpl.send(players, channel, writer); + } + + /** + * Send a packet to the given players through the given channel. + */ + public static void send(Iterable players, NamespacedIdentifier channel, PacketBuffer buffer) { + ServerPlayNetworkingImpl.send(players, channel, buffer); + } + + /** + * Send a packet to the given players through the given channel. + */ + public static void send(Iterable players, NamespacedIdentifier channel, byte[] bytes) { + ServerPlayNetworkingImpl.send(players, channel, bytes); + } + + /** + * Send a packet to all players through the given channel. The payload will + * only be written if the channel is open for at least one player. + */ + public static void send(NamespacedIdentifier channel, PacketPayload payload) { + ServerPlayNetworkingImpl.send(channel, payload); + } + + /** + * Send a packet to all players through the given channel. The writer will + * only be called if the channel is open for at least one player. + */ + public static void send(NamespacedIdentifier channel, IOConsumer writer) { + ServerPlayNetworkingImpl.send(channel, writer); + } + + /** + * Send a packet to all players through the given channel. + */ + public static void send(NamespacedIdentifier channel, PacketBuffer buffer) { + ServerPlayNetworkingImpl.send(channel, buffer); + } + + /** + * Send a packet to all players through the given channel. + */ + public static void send(NamespacedIdentifier channel, byte[] bytes) { + ServerPlayNetworkingImpl.send(channel, bytes); + } + + /** + * Send a packet to the given player through the given channel, without + * checking whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the client. + */ + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, PacketPayload payload) { + ServerPlayNetworkingImpl.sendNoCheck(player, channel, payload); + } + + /** + * Send a packet to the given player through the given channel, without + * checking whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the client. + */ + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, IOConsumer writer) { + ServerPlayNetworkingImpl.sendNoCheck(player, channel, writer); + } + + /** + * Send a packet to the given player through the given channel, without + * checking whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the client. + */ + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, PacketBuffer buffer) { + ServerPlayNetworkingImpl.sendNoCheck(player, channel, buffer); + } + + /** + * Send a packet to the given player through the given channel, without + * checking whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the client. + */ + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, byte[] bytes) { + ServerPlayNetworkingImpl.sendNoCheck(player, channel, bytes); + } + + /** + * Send a packet to the given players through the given channel, without + * checking whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the client. + */ + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, PacketPayload payload) { + ServerPlayNetworkingImpl.sendNoCheck(players, channel, payload); + } + + /** + * Send a packet to the given players through the given channel, without + * checking whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the client. + */ + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, IOConsumer writer) { + ServerPlayNetworkingImpl.sendNoCheck(players, channel, writer); + } + + /** + * Send a packet to the given players through the given channel, without + * checking whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the client. + */ + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, PacketBuffer buffer) { + ServerPlayNetworkingImpl.sendNoCheck(players, channel, buffer); + } + + /** + * Send a packet to the given players through the given channel, without + * checking whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the client. + */ + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, byte[] bytes) { + ServerPlayNetworkingImpl.sendNoCheck(players, channel, bytes); + } + + /** + * Send a packet to all players through the given channel, without + * checking whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the client. + */ + public static void sendNoCheck(NamespacedIdentifier channel, PacketPayload payload) { + ServerPlayNetworkingImpl.sendNoCheck(channel, payload); + } + + /** + * Send a packet to all players through the given channel, without + * checking whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the client. + */ + public static void sendNoCheck(NamespacedIdentifier channel, IOConsumer writer) { + ServerPlayNetworkingImpl.sendNoCheck(channel, writer); + } + + /** + * Send a packet to all players through the given channel, without + * checking whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the client. + */ + public static void sendNoCheck(NamespacedIdentifier channel, PacketBuffer buffer) { + ServerPlayNetworkingImpl.sendNoCheck(channel, buffer); + } + + /** + * Send a packet to all players through the given channel, without + * checking whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the client. + */ + public static void sendNoCheck(NamespacedIdentifier channel, byte[] bytes) { + ServerPlayNetworkingImpl.sendNoCheck(channel, bytes); + } +} diff --git a/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/Connections.java b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/Connections.java new file mode 100644 index 00000000..836dd8ed --- /dev/null +++ b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/Connections.java @@ -0,0 +1,22 @@ +package net.ornithemc.osl.networking.impl; + +import net.minecraft.network.PacketHandler; +import net.minecraft.network.packet.Packet; + +import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; + +public final class Connections { + + public static boolean checkAsyncHandling(Packet packet, PacketHandler listener) { + boolean handleAsync = packet instanceof CustomPayloadPacketAccess + && listener instanceof NetworkHandlerAccess + && ((NetworkHandlerAccess) listener).osl$networking$canRunOffMainThread(); + + if (handleAsync) { + packet.handle(listener); + } + + return handleAsync; + } +} diff --git a/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java new file mode 100644 index 00000000..1c65baa7 --- /dev/null +++ b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java @@ -0,0 +1,56 @@ +package net.ornithemc.osl.networking.impl; + +import java.io.IOException; +import java.util.LinkedHashSet; +import java.util.Set; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.api.ChannelIdentifiers; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketPayload; +import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; + +public class HandshakePayload implements PacketPayload { + + public static final NamespacedIdentifier CHANNEL = Constants.OSL_HANDSHAKE_CHANNEL; + + public byte protocol; + public Set channels; + + public HandshakePayload() { + } + + public HandshakePayload(Set channels) { + this.protocol = Constants.OSL_HANDSHAKE_PROTOCOL; + // we allow registering listeners on channels that do not conform to OSL spec + // but payloads sent over these channels aren't sent via OSL so we can ignore + // them for the OSL handshake. + this.channels = ChannelIdentifiers.dropInvalid(channels); + } + + public static HandshakePayload server() { + return new HandshakePayload(ServerPlayNetworkingImpl.CHANNEL_LISTENERS.keySet()); + } + + @Override + public void read(PacketBuffer buffer) throws IOException { + protocol = buffer.readByte(); + channels = new LinkedHashSet<>(); + + int channelCount = buffer.readInt(); + + for (int i = 0; i < channelCount; i++) { + channels.add(buffer.readNamespacedIdentifier()); + } + } + + @Override + public void write(PacketBuffer buffer) throws IOException { + buffer.writeByte(protocol); + buffer.writeInt(channels.size()); + + for (NamespacedIdentifier channel : channels) { + buffer.writeNamespacedIdentifier(channel); + } + } +} diff --git a/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/PacketFactory.java b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/PacketFactory.java new file mode 100644 index 00000000..2a4f77aa --- /dev/null +++ b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/PacketFactory.java @@ -0,0 +1,11 @@ +package net.ornithemc.osl.networking.impl; + +import net.minecraft.network.packet.Packet; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; + +public interface PacketFactory { + + Packet create(NamespacedIdentifier channel, byte[] data); + +} diff --git a/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/access/CustomPayloadPacketAccess.java b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/access/CustomPayloadPacketAccess.java new file mode 100644 index 00000000..9c17038b --- /dev/null +++ b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/access/CustomPayloadPacketAccess.java @@ -0,0 +1,11 @@ +package net.ornithemc.osl.networking.impl.access; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; + +public interface CustomPayloadPacketAccess { + + NamespacedIdentifier osl$networking$getChannel(); + + byte[] osl$networking$getData(); + +} diff --git a/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/access/NetworkHandlerAccess.java b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/access/NetworkHandlerAccess.java new file mode 100644 index 00000000..81b86b1f --- /dev/null +++ b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/access/NetworkHandlerAccess.java @@ -0,0 +1,17 @@ +package net.ornithemc.osl.networking.impl.access; + +import java.util.Set; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; + +public interface NetworkHandlerAccess { + + boolean osl$networking$canRunOffMainThread(); + + boolean osl$networking$isPlayReady(); + + boolean osl$networking$isPlayReady(NamespacedIdentifier channel); + + void osl$networking$registerChannels(Set channels); + +} diff --git a/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/access/TaskRunnerAccess.java b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/access/TaskRunnerAccess.java new file mode 100644 index 00000000..bff1ba39 --- /dev/null +++ b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/access/TaskRunnerAccess.java @@ -0,0 +1,7 @@ +package net.ornithemc.osl.networking.impl.access; + +public interface TaskRunnerAccess { + + boolean osl$networking$submit(Runnable task); + +} diff --git a/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java new file mode 100644 index 00000000..528a6e03 --- /dev/null +++ b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java @@ -0,0 +1,385 @@ +package net.ornithemc.osl.networking.impl.server; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Predicate; +import java.util.function.Supplier; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import net.minecraft.network.packet.Packet; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.entity.mob.player.ServerPlayerEntity; +import net.minecraft.server.network.handler.ServerPlayNetworkHandler; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.function.IOConsumer; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketBuffers; +import net.ornithemc.osl.networking.api.PacketPayload; +import net.ornithemc.osl.networking.api.server.ServerPacketListener; +import net.ornithemc.osl.networking.impl.PacketFactory; +import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; +import net.ornithemc.osl.networking.impl.access.TaskRunnerAccess; + +public final class ServerPlayNetworkingImpl { + + private static final Logger LOGGER = LogManager.getLogger("OSL|Server Play Networking"); + + private static PacketFactory packetFactory; + private static MinecraftServer server; + private static Thread thread; + + public static void setUpPacketFactory(PacketFactory factory) { + if (ServerPlayNetworkingImpl.packetFactory != null) { + throw new IllegalStateException("tried to set up server custom payload packet factory when it was already set up!"); + } + + ServerPlayNetworkingImpl.packetFactory = factory; + } + + public static void setUp(MinecraftServer server) { + if (ServerPlayNetworkingImpl.server == server) { + throw new IllegalStateException("tried to set up server play networking when it was already set up!"); + } + if (ServerPlayNetworkingImpl.packetFactory == null) { + throw new IllegalStateException("tried to set up server play networking when no custom payload packet factory was set up!"); + } + + ServerPlayNetworkingImpl.server = server; + ServerPlayNetworkingImpl.thread = Thread.currentThread(); + } + + public static void destroy(MinecraftServer server) { + if (ServerPlayNetworkingImpl.server != server) { + throw new IllegalStateException("tried to destroy server play networking when it was not set up!"); + } + + ServerPlayNetworkingImpl.server = null; + ServerPlayNetworkingImpl.thread = null; + } + + public static final Map CHANNEL_LISTENERS = new LinkedHashMap<>(); + + public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { + ServerPlayNetworkingImpl.registerListener(channel, initializer, listener, false); + } + + public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { + ServerPlayNetworkingImpl.registerListener(channel, initializer, listener, true); + } + + private static void registerListener(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener, boolean async) { + registerListenerImpl(channel, new ChannelListener() { + + @Override + public boolean isAsync() { + return async; + } + + @Override + public boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] bytes) throws IOException { + T payload = initializer.get(); + payload.read(PacketBuffers.wrap(bytes)); + + return listener.handle(server, handler, player, payload); + } + }); + } + + public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { + ServerPlayNetworkingImpl.registerListener(channel, listener, false); + } + + public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { + ServerPlayNetworkingImpl.registerListener(channel, listener, true); + } + + private static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Buffer listener, boolean async) { + registerListenerImpl(channel, new ChannelListener() { + + @Override + public boolean isAsync() { + return async; + } + + @Override + public boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] bytes) throws IOException { + return listener.handle(server, handler, player, PacketBuffers.wrap(bytes)); + } + }); + } + + public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { + ServerPlayNetworkingImpl.registerListener(channel, listener, false); + } + + public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { + ServerPlayNetworkingImpl.registerListener(channel, listener, true); + } + + private static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener, boolean async) { + registerListenerImpl(channel, new ChannelListener() { + + @Override + public boolean isAsync() { + return async; + } + + @Override + public boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] bytes) throws IOException { + return listener.handle(server, handler, player, bytes); + } + }); + } + + private static void registerListenerImpl(NamespacedIdentifier channel, ChannelListener listener) { + CHANNEL_LISTENERS.compute(channel, (key, value) -> { + if (value != null) { + throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); + } + + return listener; + }); + } + + public static void unregisterListener(NamespacedIdentifier channel) { + CHANNEL_LISTENERS.remove(channel); + } + + public static boolean handlePacket(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, Packet packet) { + CustomPayloadPacketAccess p = (CustomPayloadPacketAccess)packet; + + NamespacedIdentifier channel = p.osl$networking$getChannel(); + ChannelListener listener = CHANNEL_LISTENERS.get(channel); + + if (listener != null) { + byte[] data = p.osl$networking$getData(); + + if (Thread.currentThread() == thread || listener.isAsync()) { + return handlePayload(server, handler, player, listener, channel, data); + } else { + return ((TaskRunnerAccess) server).osl$networking$submit(() -> handlePayload(server, handler, player, listener, channel, data)); + } + } + + return false; + } + + private static boolean handlePayload(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, ChannelListener listener, NamespacedIdentifier channel, byte[] data) { + try { + return listener.handle(server, handler, player, data); + } catch (IOException e) { + LOGGER.warn("error handling custom payload on channel \'" + channel + "\'", e); + } + + return true; + } + + public static boolean isPlayReady(ServerPlayerEntity player) { + NetworkHandlerAccess handler = (NetworkHandlerAccess)player.networkHandler; + return handler != null && handler.osl$networking$isPlayReady(); + } + + public static boolean isPlayReady(ServerPlayerEntity player, NamespacedIdentifier channel) { + NetworkHandlerAccess handler = (NetworkHandlerAccess)player.networkHandler; + return handler != null && handler.osl$networking$isPlayReady(channel); + } + + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, PacketPayload payload) { + if (isPlayReady(player, channel)) { + sendInternal(player, channel, payload); + } + } + + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, IOConsumer writer) { + if (isPlayReady(player, channel)) { + sendInternal(player, channel, writer); + } + } + + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, PacketBuffer buffer) { + if (isPlayReady(player, channel)) { + sendInternal(player, channel, buffer); + } + } + + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, byte[] bytes) { + if (isPlayReady(player, channel)) { + sendInternal(player, channel, bytes); + } + } + + public static void send(Iterable players, NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(collectPlayers(players, p -> isPlayReady(p, channel)), channel, payload); + } + + public static void send(Iterable players, NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(collectPlayers(players, p -> isPlayReady(p, channel)), channel, writer); + } + + public static void send(Iterable players, NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(collectPlayers(players, p -> isPlayReady(p, channel)), channel, buffer); + } + + public static void send(Iterable players, NamespacedIdentifier channel, byte[] bytes) { + sendInternal(collectPlayers(players, p -> isPlayReady(p, channel)), channel, bytes); + } + + public static void send(NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(collectPlayers(p -> isPlayReady(p, channel)), channel, payload); + } + + public static void send(NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(collectPlayers(p -> isPlayReady(p, channel)), channel, writer); + } + + public static void send(NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(collectPlayers(p -> isPlayReady(p, channel)), channel, buffer); + } + + public static void send(NamespacedIdentifier channel, byte[] bytes) { + sendInternal(collectPlayers(p -> isPlayReady(p, channel)), channel, bytes); + } + + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(player, channel, payload); + } + + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(player, channel, writer); + } + + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(player, channel, buffer); + } + + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, byte[] bytes) { + sendInternal(player, channel, bytes); + } + + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(players, channel, payload); + } + + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(players, channel, writer); + } + + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(players, channel, buffer); + } + + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, byte[] bytes) { + sendInternal(players, channel, bytes); + } + + public static void sendNoCheck(NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(allPlayers(), channel, payload); + } + + public static void sendNoCheck(NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(allPlayers(), channel, writer); + } + + public static void sendNoCheck(NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(allPlayers(), channel, buffer); + } + + public static void sendNoCheck(NamespacedIdentifier channel, byte[] bytes) { + sendInternal(allPlayers(), channel, bytes); + } + + private static void sendInternal(ServerPlayerEntity player, NamespacedIdentifier channel, PacketPayload payload) { + try { + sendPacket(player, channel, PacketBuffers.unwrap(PacketBuffers.make(payload::write))); + } catch (IOException e) { + LOGGER.warn("error writing packet payload to channel \'" + channel + "\'", e); + } + } + + private static void sendInternal(ServerPlayerEntity player, NamespacedIdentifier channel, IOConsumer writer) { + try { + sendPacket(player, channel, PacketBuffers.unwrap(PacketBuffers.make(writer))); + } catch (IOException e) { + LOGGER.warn("error writing buffer to channel \'" + channel + "\'", e); + } + } + + private static void sendInternal(ServerPlayerEntity player, NamespacedIdentifier channel, PacketBuffer buffer) { + sendPacket(player, channel, PacketBuffers.unwrap(buffer)); + } + + private static void sendInternal(ServerPlayerEntity player, NamespacedIdentifier channel, byte[] bytes) { + sendPacket(player, channel, bytes); + } + + private static void sendInternal(Iterable players, NamespacedIdentifier channel, PacketPayload payload) { + try { + sendPacket(players, channel, PacketBuffers.unwrap(PacketBuffers.make(payload::write))); + } catch (IOException e) { + LOGGER.warn("error writing packet payload to channel \'" + channel + "\'", e); + } + } + + private static void sendInternal(Iterable players, NamespacedIdentifier channel, IOConsumer writer) { + try { + sendPacket(players, channel, PacketBuffers.unwrap(PacketBuffers.make(writer))); + } catch (IOException e) { + LOGGER.warn("error writing buffer to channel \'" + channel + "\'", e); + } + } + + private static void sendInternal(Iterable players, NamespacedIdentifier channel, PacketBuffer buffer) { + sendPacket(players, channel, PacketBuffers.unwrap(buffer)); + } + + private static void sendInternal(Iterable players, NamespacedIdentifier channel, byte[] bytes) { + sendPacket(players, channel, bytes); + } + + private static Iterable allPlayers() { + return server.playerManager.players; + } + + private static Iterable collectPlayers(Predicate filter) { + return collectPlayers(allPlayers(), filter); + } + + private static Iterable collectPlayers(Iterable src, Predicate filter) { + List players = new ArrayList<>(); + + for (ServerPlayerEntity player : src) { + if (filter.test(player)) { + players.add(player); + } + } + + return players; + } + + private static void sendPacket(ServerPlayerEntity player, NamespacedIdentifier channel, byte[] data) { + player.networkHandler.sendPacket(packetFactory.create(channel, data)); + } + + private static void sendPacket(Iterable players, NamespacedIdentifier channel, byte[] data) { + Packet packet = packetFactory.create(channel, data); + + for (ServerPlayerEntity player : players) { + player.networkHandler.sendPacket(packet); + } + } + + private interface ChannelListener { + + boolean isAsync(); + + boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] bytes) throws IOException; + + } +} diff --git a/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/resources/osl.networking.mixins.json b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/resources/osl.networking.mixins.json similarity index 76% rename from libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/resources/osl.networking.mixins.json rename to libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/resources/osl.networking.mixins.json index e2526e75..f1faf16d 100644 --- a/libraries/networking/networking-mcb1.0-mcb1.4_01/src/main/resources/osl.networking.mixins.json +++ b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/resources/osl.networking.mixins.json @@ -4,13 +4,13 @@ "package": "net.ornithemc.osl.networking.impl.mixin", "compatibilityLevel": "JAVA_8", "mixins": [ - "common.PacketAccessor" + "common.PacketAccessor", + "common.PacketMixin" ], "client": [ - "client.ClientNetworkHandlerMixin", - "client.HandshakePacketMixin" ], "server": [ + "server.MinecraftServerMixin", "server.ServerLoginNetworkHandlerMixin", "server.ServerPlayNetworkHandlerMixin" ], diff --git a/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java b/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java deleted file mode 100644 index 237d7e67..00000000 --- a/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java +++ /dev/null @@ -1,13 +0,0 @@ -package net.ornithemc.osl.networking.api; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; - -public interface CustomPayload { - - void read(DataInputStream input) throws IOException; - - void write(DataOutputStream output) throws IOException; - -} diff --git a/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java b/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java deleted file mode 100644 index f68e894c..00000000 --- a/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java +++ /dev/null @@ -1,23 +0,0 @@ -package net.ornithemc.osl.networking.api; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; - -public final class DataStreams { - - public static DataInputStream input(byte[] bytes) { - return new DataInputStream(new ByteArrayInputStream(bytes == null ? new byte[0] : bytes)); - } - - public static ByteArrayOutputStream output(IOConsumer writer) throws IOException { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - DataOutputStream os = new DataOutputStream(bos); - writer.accept(os); - return bos; - } -} diff --git a/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java b/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java deleted file mode 100644 index dbe85275..00000000 --- a/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java +++ /dev/null @@ -1,71 +0,0 @@ -package net.ornithemc.osl.networking.api.server; - -import java.util.function.BiConsumer; - -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.entity.mob.player.ServerPlayerEntity; - -import net.ornithemc.osl.core.api.events.Event; - -/** - * Events related to the server side of a client-server connection. - */ -public class ServerConnectionEvents { - - /** - * This event is fired after a successful login occurs. - * - *

- * Note that channel registration happens after login, - * and until then data cannot safely be sent to the client. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ServerConnectionEvents.LOGIN.register((server, player) -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> LOGIN = Event.biConsumer(); - /** - * This event is fired after login, once channel registration is complete. - * - *

- * This marks the moment data can safely be sent to the client. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ServerConnectionEvents.PLAY_READY.register((server, player) -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> PLAY_READY = Event.biConsumer(); - /** - * This event is fired when a client disconnects from the server. - * - *

- * Callbacks to this event should be registered in your mod's entrypoint, - * and can be done as follows: - * - *

-	 * {@code
-	 * ServerConnectionEvents.DISCONNECT.register((server, player) -> {
-	 * 	...
-	 * });
-	 * }
-	 * 
- */ - public static final Event> DISCONNECT = Event.biConsumer(); - -} diff --git a/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java b/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java deleted file mode 100644 index f32f6e17..00000000 --- a/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java +++ /dev/null @@ -1,265 +0,0 @@ -package net.ornithemc.osl.networking.api.server; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.function.Supplier; - -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.entity.mob.player.ServerPlayerEntity; -import net.minecraft.server.network.handler.ServerPlayNetworkHandler; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -public final class ServerPlayNetworking { - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - ServerPlayNetworkingImpl.registerListener(channel, initializer, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListener(String channel, StreamListener listener) { - ServerPlayNetworkingImpl.registerListener(channel, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. - */ - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - ServerPlayNetworkingImpl.registerListenerRaw(channel, listener); - } - - /** - * Remove the listener registered to the given channel. - */ - public static void unregisterListener(String channel) { - ServerPlayNetworkingImpl.unregisterListener(channel); - } - - /** - * Check whether the connection is ready for data to be sent to the client. - */ - public static boolean isPlayReady(ServerPlayerEntity player) { - return ServerPlayNetworkingImpl.isPlayReady(player); - } - - /** - * Check whether the given channel is open for data to be sent through it. - * This method will return {@code false} if the client has no listeners for - * the given channel. - */ - public static boolean canSend(ServerPlayerEntity player, String channel) { - return ServerPlayNetworkingImpl.canSend(player, channel); - } - - /** - * Send a packet to the given player through the given channel. The payload - * will only be written if the channel is open. - */ - public static void send(ServerPlayerEntity player, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.send(player, channel, payload); - } - - /** - * Send a packet to the given player through the given channel. The writer - * will only be called if the channel is open. - */ - public static void send(ServerPlayerEntity player, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.send(player, channel, writer); - } - - /** - * Send a packet to the given player through the given channel. - */ - public static void send(ServerPlayerEntity player, String channel, byte[] data) { - ServerPlayNetworkingImpl.send(player, channel, data); - } - - /** - * Send a packet to the given players through the given channel. The payload - * will only be written if the channel is open for at least one player. - */ - public static void send(Iterable players, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.send(players, channel, payload); - } - - /** - * Send a packet to the given players through the given channel. The writer - * will only be called if the channel is open for at least one player. - */ - public static void send(Iterable players, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.send(players, channel, writer); - } - - /** - * Send a packet to the given players through the given channel. - */ - public static void send(Iterable players, String channel, byte[] data) { - ServerPlayNetworkingImpl.send(players, channel, data); - } - - /** - * Send a packet to all players through the given channel. The payload will - * only be written if the channel is open for at least one player. - */ - public static void send(String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.send(channel, payload); - } - - /** - * Send a packet to all players through the given channel. The writer will - * only be called if the channel is open for at least one player. - */ - public static void send(String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.send(channel, writer); - } - - /** - * Send a packet to all players through the given channel. - */ - public static void send(String channel, byte[] data) { - ServerPlayNetworkingImpl.send(channel, data); - } - - /** - * Send a packet to the given player through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(ServerPlayerEntity player, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(player, channel, payload); - } - - /** - * Send a packet to the given player through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(ServerPlayerEntity player, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(player, channel, writer); - } - - /** - * Send a packet to the given player through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(ServerPlayerEntity player, String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(player, channel, data); - } - - /** - * Send a packet to the given players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(Iterable players, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(players, channel, payload); - } - - /** - * Send a packet to the given players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(Iterable players, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(players, channel, writer); - } - - /** - * Send a packet to the given players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(Iterable players, String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(players, channel, data); - } - - /** - * Send a packet to all players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(channel, payload); - } - - /** - * Send a packet to all players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(channel, writer); - } - - /** - * Send a packet to all players through the given channel, without - * checking whether it is open. - * USE WITH CAUTION. Careless use of this method could lead to packet and log - * spam on the client. - */ - public static void doSend(String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(channel, data); - } - - public interface PayloadListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, T payload) throws IOException; - - } - - public interface StreamListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, DataInputStream data) throws IOException; - - } - - public interface ByteArrayListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java b/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java deleted file mode 100644 index 76c2850d..00000000 --- a/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java +++ /dev/null @@ -1,75 +0,0 @@ -package net.ornithemc.osl.networking.impl; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.UncheckedIOException; - -import net.minecraft.network.PacketHandler; -import net.minecraft.network.packet.Packet; - -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; - -public class CustomPayloadPacket extends Packet { - - public String channel; - public int size; - public byte[] data; - - public CustomPayloadPacket() { - } - - public CustomPayloadPacket(String channel, byte[] data) { - this.channel = channel; - this.data = data; - if (data != null) { - this.size = data.length; - if (this.size > Short.MAX_VALUE) { - throw new IllegalArgumentException("Payload may not be larger than 32k"); - } - } - } - - // the IOException has been stripped from the read/write methods - // by the obfuscator, thus we catch it and re-throw it as a - // runtime exception - it will be caught in Connection#read anyhow - - @Override - public void read(DataInputStream input) { - try { - this.channel = input.readUTF(); - this.size = input.readShort(); - if (this.size > 0 && this.size < Short.MAX_VALUE) { - this.data = new byte[this.size]; - input.readFully(this.data); - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - @Override - public void write(DataOutputStream output) { - try { - output.writeUTF(this.channel); - output.writeShort(this.size); - if (this.data != null) { - output.write(this.data); - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - @Override - public void handle(PacketHandler handler) { - if (handler instanceof INetworkHandler) { - ((INetworkHandler)handler).osl$networking$handleCustomPayload(this); - } - } - - @Override - public int getSize() { - return 2 + this.channel.length() * 2 + 2 + this.size; - } -} diff --git a/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java b/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java deleted file mode 100644 index 8fc8931f..00000000 --- a/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java +++ /dev/null @@ -1,53 +0,0 @@ -package net.ornithemc.osl.networking.impl; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.LinkedHashSet; -import java.util.Set; - -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -public class HandshakePayload implements CustomPayload { - - public static final String CHANNEL = "OSL|Handshake"; - - public Set channels; - - public HandshakePayload() { - } - - public HandshakePayload(Set channels) { - this.channels = channels; - } - - public static HandshakePayload client() { - throw new UnsupportedOperationException(); - } - - public static HandshakePayload server() { - return new HandshakePayload(ServerPlayNetworkingImpl.LISTENERS.keySet()); - } - - @Override - public void read(DataInputStream input) throws IOException { - channels = new LinkedHashSet<>(); - int channelCount = input.readInt(); - - if (channelCount > 0) { - for (int i = 0; i < channelCount; i++) { - channels.add(input.readUTF()); - } - } - } - - @Override - public void write(DataOutputStream output) throws IOException { - output.writeInt(channels.size()); - - for (String channel : channels) { - output.writeUTF(channel); - } - } -} diff --git a/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/Networking.java deleted file mode 100644 index d3c0e85d..00000000 --- a/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/Networking.java +++ /dev/null @@ -1,34 +0,0 @@ -package net.ornithemc.osl.networking.impl; - -import net.ornithemc.osl.entrypoints.api.ModInitializer; -import net.ornithemc.osl.entrypoints.api.server.ServerModInitializer; -import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; -import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; -import net.ornithemc.osl.networking.impl.mixin.common.PacketAccessor; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -public class Networking implements ModInitializer, ServerModInitializer { - - @Override - public void init() { - PacketAccessor.register(Constants.CUSTOM_PAYLOAD_PACKET_ID, CustomPayloadPacket.class); - } - - @Override - public void initServer() { - MinecraftServerEvents.START.register(server -> { - ServerPlayNetworkingImpl.setUp(server); - }); - MinecraftServerEvents.STOP.register(server -> { - ServerPlayNetworkingImpl.destroy(server); - }); - ServerPlayNetworking.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { - ((INetworkHandler)handler).osl$networking$registerChannels(payload.channels); - ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); - - return true; - }); - } -} diff --git a/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java b/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java deleted file mode 100644 index 295ead13..00000000 --- a/libraries/networking/networking-mcserver-a0.1.2_01-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java +++ /dev/null @@ -1,245 +0,0 @@ -package net.ornithemc.osl.networking.impl.server; - -import java.io.DataOutputStream; -import java.io.IOException; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.function.Predicate; -import java.util.function.Supplier; - -import org.apache.logging.log4j.LogManager; -import org.apache.logging.log4j.Logger; - -import net.minecraft.network.packet.Packet; -import net.minecraft.server.MinecraftServer; -import net.minecraft.server.entity.mob.player.ServerPlayerEntity; -import net.minecraft.server.network.handler.ServerPlayNetworkHandler; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.Channels; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.api.DataStreams; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.ByteArrayListener; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.PayloadListener; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.StreamListener; -import net.ornithemc.osl.networking.impl.CustomPayloadPacket; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; - -public final class ServerPlayNetworkingImpl { - - private static final Logger LOGGER = LogManager.getLogger("OSL|Server Play Networking"); - - private static MinecraftServer server; - - public static void setUp(MinecraftServer server) { - if (ServerPlayNetworkingImpl.server == server) { - throw new IllegalStateException("tried to set up server networking when it was already set up!"); - } - - ServerPlayNetworkingImpl.server = server; - } - - public static void destroy(MinecraftServer server) { - if (ServerPlayNetworkingImpl.server != server) { - throw new IllegalStateException("tried to destroy server networking when it was not set up!"); - } - - ServerPlayNetworkingImpl.server = null; - } - - public static final Map LISTENERS = new LinkedHashMap<>(); - - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - registerListenerImpl(channel, (server, handler, player, data) -> { - T payload = initializer.get(); - payload.read(DataStreams.input(data)); - - return listener.handle(server, handler, player, payload); - }); - } - - public static void registerListener(String channel, StreamListener listener) { - registerListenerImpl(channel, (server, handler, player, data) -> { - return listener.handle(server, handler, player, DataStreams.input(data)); - }); - } - - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - registerListenerImpl(channel, listener::handle); - } - - private static void registerListenerImpl(String channel, Listener listener) { - LISTENERS.compute(channel, (key, value) -> { - Channels.validate(channel); - - if (value != null) { - throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); - } - - return listener; - }); - } - - public static void unregisterListener(String channel) { - LISTENERS.remove(channel); - } - - public static boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, CustomPayloadPacket packet) { - Listener listener = LISTENERS.get(packet.channel); - - if (listener != null) { - try { - return listener.handle(server, handler, player, packet.data); - } catch (IOException e) { - LOGGER.warn("error handling custom payload on channel \'" + packet.channel + "\'", e); - return true; - } - } - - return false; - } - - public static boolean isPlayReady(ServerPlayerEntity player) { - INetworkHandler handler = (INetworkHandler)player.networkHandler; - return handler != null && handler.osl$networking$isPlayReady(); - } - - public static boolean canSend(ServerPlayerEntity player, String channel) { - INetworkHandler handler = (INetworkHandler)player.networkHandler; - return handler != null && handler.osl$networking$isRegisteredChannel(channel); - } - - public static void send(ServerPlayerEntity player, String channel, CustomPayload payload) { - if (canSend(player, channel)) { - doSend(player, channel, payload); - } - } - - public static void send(ServerPlayerEntity player, String channel, IOConsumer writer) { - if (canSend(player, channel)) { - doSend(player, channel, writer); - } - } - - public static void send(ServerPlayerEntity player, String channel, byte[] data) { - if (canSend(player, channel)) { - doSend(player, channel, data); - } - } - - public static void send(Iterable players, String channel, CustomPayload payload) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, payload)); - } - - public static void send(Iterable players, String channel, IOConsumer writer) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, writer)); - } - - public static void send(Iterable players, String channel, byte[] data) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, data)); - } - - public static void send(String channel, CustomPayload payload) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, payload); - } - - public static void send(String channel, IOConsumer writer) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, writer); - } - - public static void send(String channel, byte[] data) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, data); - } - - public static void doSend(ServerPlayerEntity player, String channel, CustomPayload payload) { - sendPacket(player, makePacket(channel, payload)); - } - - public static void doSend(ServerPlayerEntity player, String channel, IOConsumer writer) { - sendPacket(player, makePacket(channel, writer)); - } - - public static void doSend(ServerPlayerEntity player, String channel, byte[] data) { - sendPacket(player, makePacket(channel, data)); - } - - public static void doSend(Iterable players, String channel, CustomPayload payload) { - sendPacket(players, makePacket(channel, payload)); - } - - public static void doSend(Iterable players, String channel, IOConsumer writer) { - sendPacket(players, makePacket(channel, writer)); - } - - public static void doSend(Iterable players, String channel, byte[] data) { - sendPacket(players, makePacket(channel, data)); - } - - public static void doSend(String channel, CustomPayload payload) { - doSend(collectPlayers(p -> true), channel, payload); - } - - public static void doSend(String channel, IOConsumer writer) { - doSend(collectPlayers(p -> true), channel, writer); - } - - public static void doSend(String channel, byte[] data) { - doSend(collectPlayers(p -> true), channel, data); - } - - @SuppressWarnings("unchecked") // thanks proguard - private static Iterable collectPlayers(Predicate filter) { - return collectPlayers(server.playerManager.players, filter); - } - - private static Iterable collectPlayers(Iterable src, Predicate filter) { - List players = new ArrayList<>(); - - for (ServerPlayerEntity player : src) { - if (filter.test(player)) { - players.add(player); - } - } - - return players; - } - - private static Packet makePacket(String channel, CustomPayload payload) { - return makePacket(channel, payload::write); - } - - private static Packet makePacket(String channel, IOConsumer writer) { - try { - return new CustomPayloadPacket(channel, DataStreams.output(writer).toByteArray()); - } catch (IOException e) { - LOGGER.warn("error writing custom payload to channel \'" + channel + "\'", e); - return null; - } - } - - private static Packet makePacket(String channel, byte[] data) { - return new CustomPayloadPacket(channel, data); - } - - private static void sendPacket(ServerPlayerEntity player, Packet packet) { - if (packet != null) { - player.networkHandler.sendPacket(packet); - } - } - - private static void sendPacket(Iterable players, Packet packet) { - if (packet != null) { - for (ServerPlayerEntity player : players) { - sendPacket(player, packet); - } - } - } - - private interface Listener { - - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] data) throws IOException; - - } -} diff --git a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java deleted file mode 100644 index 237d7e67..00000000 --- a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/CustomPayload.java +++ /dev/null @@ -1,13 +0,0 @@ -package net.ornithemc.osl.networking.api; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; - -public interface CustomPayload { - - void read(DataInputStream input) throws IOException; - - void write(DataOutputStream output) throws IOException; - -} diff --git a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java deleted file mode 100644 index f68e894c..00000000 --- a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/DataStreams.java +++ /dev/null @@ -1,23 +0,0 @@ -package net.ornithemc.osl.networking.api; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; - -import net.ornithemc.osl.core.api.util.function.IOConsumer; - -public final class DataStreams { - - public static DataInputStream input(byte[] bytes) { - return new DataInputStream(new ByteArrayInputStream(bytes == null ? new byte[0] : bytes)); - } - - public static ByteArrayOutputStream output(IOConsumer writer) throws IOException { - ByteArrayOutputStream bos = new ByteArrayOutputStream(); - DataOutputStream os = new DataOutputStream(bos); - writer.accept(os); - return bos; - } -} diff --git a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/PacketBuffer.java b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/PacketBuffer.java new file mode 100644 index 00000000..332c2370 --- /dev/null +++ b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/PacketBuffer.java @@ -0,0 +1,1217 @@ +package net.ornithemc.osl.networking.api; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.channels.FileChannel; +import java.nio.channels.GatheringByteChannel; +import java.nio.channels.ScatteringByteChannel; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.Date; +import java.util.UUID; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.ByteBufAllocator; +import io.netty.buffer.ByteBufInputStream; +import io.netty.buffer.ByteBufOutputStream; +import io.netty.util.ByteProcessor; + +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtIo; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.NamespacedIdentifiers; + +public class PacketBuffer extends ByteBuf { + + private static final int VAR_VALUE_BITS = 7; + private static final int VAR_VALUE_MASK = 1 << VAR_VALUE_BITS - 1; + private static final int VAR_PARITY_VALUE = 1 << VAR_VALUE_BITS; + private static final int VAR_INT_MAX_BYTES = 5; + private static final int VAR_LONG_MAX_BYTES = 10; + + final ByteBuf delegate; + + public PacketBuffer(ByteBuf delegate) { + this.delegate = delegate; + } + + public int readVarInt() { + int value = 0; + + byte bytes = 0; + byte nextByte = 0; + + do { + nextByte = this.readByte(); + value |= (nextByte & VAR_VALUE_MASK) << bytes++ * VAR_VALUE_BITS; + + if (bytes > VAR_INT_MAX_BYTES) { + throw new RuntimeException("VarInt too big"); + } + } while ((nextByte & VAR_PARITY_VALUE) == VAR_PARITY_VALUE); + + return value; + } + + public long readVarLong() { + long value = 0; + + byte bytes = 0; + byte nextByte = 0; + + do { + nextByte = this.readByte(); + value |= (nextByte & VAR_VALUE_MASK) << bytes++ * VAR_VALUE_BITS; + + if (bytes > VAR_LONG_MAX_BYTES) { + throw new RuntimeException("VarLong too big"); + } + } while ((nextByte & VAR_PARITY_VALUE) == VAR_PARITY_VALUE); + + return value; + } + + public byte[] readByteArray() { + return this.readByteArray(this.readableBytes()); + } + + public byte[] readByteArray(int maxLength) { + int length = this.readVarInt(); + + if (length > maxLength) { + throw new RuntimeException("ByteArray with size " + length + " is bigger than allowed " + maxLength); + } + + byte[] values = new byte[length]; + + for (int i = 0; i < length; i++) { + values[i] = this.readByte(); + } + + return values; + } + + public int[] readIntArray() { + return this.readIntArray(this.readableBytes()); + } + + public int[] readIntArray(int maxLength) { + int length = this.readVarInt(); + + if (length > maxLength) { + throw new RuntimeException("IntArray with size " + length + " is bigger than allowed " + maxLength); + } + + int[] values = new int[length]; + + for (int i = 0; i < length; i++) { + values[i] = this.readVarInt(); + } + + return values; + } + + public long[] readLongArray() { + return this.readLongArray(this.readableBytes() / 8); + } + + public long[] readLongArray(int maxLength) { + int length = this.readVarInt(); + + if (length > maxLength) { + throw new IllegalStateException("LongArray with size " + length + " is bigger than allowed " + maxLength); + } + + long[] values = new long[length]; + + for (int i = 0; i < length; i++) { + values[i] = this.readVarLong(); + } + + return values; + } + + public String readString() { + return this.readString(Short.MAX_VALUE); + } + + public String readString(int maxLength) { + int length = this.readVarInt(); + + if (length > maxLength * 4) { + throw new RuntimeException("The received encoded string buffer length is longer than maximum allowed (" + length + " > " + maxLength * 4 + ")"); + } + if (length < 0) { + throw new RuntimeException("The received encoded string buffer length is less than zero! Weird string!"); + } + + String s = this.toString(this.readerIndex(), length, StandardCharsets.UTF_8); + this.readerIndex(this.readerIndex() + length); + + if (s.length() > maxLength) { + throw new RuntimeException("The received string length is longer than maximum allowed (" + length + " > " + maxLength + ")"); + } + + return s; + } + + public > T readEnum(Class type) { + return type.getEnumConstants()[this.readVarInt()]; + } + + public Date readDate() { + return new Date(this.readLong()); + } + + public UUID readUuid() { + return new UUID( + this.readLong(), + this.readLong() + ); + } + + public NamespacedIdentifier readNamespacedIdentifier() { + return NamespacedIdentifiers.parse(this.readString()); + } + + public NbtCompound readNbtCompound() { + int readerIndex = this.readerIndex(); + byte firstByte = this.readByte(); + + if (firstByte == 0) { + return null; + } else { + this.readerIndex(readerIndex); + + try { + return NbtIo.read(new ByteBufInputStream(this)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + } + + public ByteBuf writeVarInt(int value) { + while ((value & -128) != 0) { + this.writeByte(value & VAR_VALUE_MASK | VAR_PARITY_VALUE); + value >>>= VAR_VALUE_BITS; + } + + this.writeByte(value); + + return this; + } + + public ByteBuf writeVarLong(long value) { + while ((value & -128) != 0) { + this.writeByte((int) (value & VAR_VALUE_MASK) | VAR_PARITY_VALUE); + value >>>= VAR_VALUE_BITS; + } + + this.writeByte((int) value); + + return this; + } + + public ByteBuf writeByteArray(byte[] values) { + this.writeVarInt(values.length); + + for (byte value : values) { + this.writeByte(value); + } + + return this; + } + + public ByteBuf writeIntArray(int[] values) { + this.writeVarInt(values.length); + + for (int value : values) { + this.writeVarInt(value); + } + + return this; + } + + public ByteBuf writeLongArray(long[] values) { + this.writeVarInt(values.length); + + for (long value : values) { + this.writeVarLong(value); + } + + return this; + } + + public ByteBuf writeString(String s) { + return this.writeString(s, Short.MAX_VALUE); + } + + public ByteBuf writeString(String s, int maxLength) { + byte[] bytes = s.getBytes(StandardCharsets.UTF_8); + + if (bytes.length > maxLength) { + throw new RuntimeException("String too big (was " + bytes.length + " bytes encoded, max " + maxLength + ")"); + } + + this.writeByteArray(bytes); + + return this; + } + + public ByteBuf writeEnum(Enum value) { + this.writeVarInt(value.ordinal()); + + return this; + } + + public ByteBuf writeDate(Date date) { + this.writeLong(date.getTime()); + + return this; + } + + public ByteBuf writeUuid(UUID uuid) { + this.writeLong(uuid.getMostSignificantBits()); + this.writeLong(uuid.getLeastSignificantBits()); + + return this; + } + + public ByteBuf writeNamespacedIdentifier(NamespacedIdentifier id) { + return this.writeString(id.toString()); + } + + public ByteBuf writeNbtCompound(NbtCompound nbt) { + if (nbt == null) { + this.writeByte(0); + } else { + try { + NbtIo.write(nbt, new ByteBufOutputStream(this)); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + return this; + } + + @Override + public int capacity() { + return this.delegate.capacity(); + } + + @Override + public ByteBuf capacity(int newCapacity) { + return this.delegate.capacity(newCapacity); + } + + @Override + public int maxCapacity() { + return this.delegate.maxCapacity(); + } + + @Override + public ByteBufAllocator alloc() { + return this.delegate.alloc(); + } + + @Override + public ByteOrder order() { + return this.delegate.order(); + } + + @Override + public ByteBuf order(ByteOrder order) { + return this.delegate.order(order); + } + + @Override + public ByteBuf unwrap() { + return this.delegate.unwrap(); + } + + @Override + public boolean isDirect() { + return this.delegate.isDirect(); + } + + @Override + public boolean isReadOnly() { + return this.delegate.isReadOnly(); + } + + @Override + public ByteBuf asReadOnly() { + return this.delegate.asReadOnly(); + } + + @Override + public int readerIndex() { + return this.delegate.readerIndex(); + } + + @Override + public ByteBuf readerIndex(int readerIndex) { + return this.delegate.readerIndex(readerIndex); + } + + @Override + public int writerIndex() { + return this.delegate.writerIndex(); + } + + @Override + public ByteBuf writerIndex(int writerIndex) { + return this.delegate.writerIndex(writerIndex); + } + + @Override + public ByteBuf setIndex(int readerIndex, int writerIndex) { + return this.delegate.setIndex(readerIndex, writerIndex); + } + + @Override + public int readableBytes() { + return this.delegate.readableBytes(); + } + + @Override + public int writableBytes() { + return this.delegate.writableBytes(); + } + + @Override + public int maxWritableBytes() { + return this.delegate.maxWritableBytes(); + } + + @Override + public boolean isReadable() { + return this.delegate.isReadable(); + } + + @Override + public boolean isReadable(int size) { + return this.delegate.isReadable(size); + } + + @Override + public boolean isWritable() { + return this.delegate.isWritable(); + } + + @Override + public boolean isWritable(int size) { + return this.delegate.isWritable(size); + } + + @Override + public ByteBuf clear() { + return this.delegate.clear(); + } + + @Override + public ByteBuf markReaderIndex() { + return this.delegate.markReaderIndex(); + } + + @Override + public ByteBuf resetReaderIndex() { + return this.delegate.resetReaderIndex(); + } + + @Override + public ByteBuf markWriterIndex() { + return this.delegate.markWriterIndex(); + } + + @Override + public ByteBuf resetWriterIndex() { + return this.delegate.resetWriterIndex(); + } + + @Override + public ByteBuf discardReadBytes() { + return this.delegate.discardReadBytes(); + } + + @Override + public ByteBuf discardSomeReadBytes() { + return this.delegate.discardSomeReadBytes(); + } + + @Override + public ByteBuf ensureWritable(int minWritableBytes) { + return this.delegate.ensureWritable(minWritableBytes); + } + + @Override + public int ensureWritable(int minWritableBytes, boolean force) { + return this.delegate.ensureWritable(minWritableBytes, force); + } + + @Override + public boolean getBoolean(int index) { + return this.delegate.getBoolean(index); + } + + @Override + public byte getByte(int index) { + return this.delegate.getByte(index); + } + + @Override + public short getUnsignedByte(int index) { + return this.delegate.getUnsignedByte(index); + } + + @Override + public short getShort(int index) { + return this.delegate.getShort(index); + } + + @Override + public short getShortLE(int index) { + return this.delegate.getShortLE(index); + } + + @Override + public int getUnsignedShort(int index) { + return this.delegate.getUnsignedShort(index); + } + + @Override + public int getUnsignedShortLE(int index) { + return this.delegate.getUnsignedShortLE(index); + } + + @Override + public int getMedium(int index) { + return this.delegate.getMedium(index); + } + + @Override + public int getMediumLE(int index) { + return this.delegate.getMediumLE(index); + } + + @Override + public int getUnsignedMedium(int index) { + return this.delegate.getUnsignedMedium(index); + } + + @Override + public int getUnsignedMediumLE(int index) { + return this.delegate.getUnsignedMediumLE(index); + } + + @Override + public int getInt(int index) { + return this.delegate.getInt(index); + } + + @Override + public int getIntLE(int index) { + return this.delegate.getIntLE(index); + } + + @Override + public long getUnsignedInt(int index) { + return this.delegate.getUnsignedInt(index); + } + + @Override + public long getUnsignedIntLE(int index) { + return this.delegate.getUnsignedIntLE(index); + } + + @Override + public long getLong(int index) { + return this.delegate.getLong(index); + } + + @Override + public long getLongLE(int index) { + return this.delegate.getLongLE(index); + } + + @Override + public char getChar(int index) { + return this.delegate.getChar(index); + } + + @Override + public float getFloat(int index) { + return this.delegate.getFloat(index); + } + + @Override + public double getDouble(int index) { + return this.delegate.getDouble(index); + } + + @Override + public ByteBuf getBytes(int index, ByteBuf dst) { + return this.delegate.getBytes(index, dst); + } + + @Override + public ByteBuf getBytes(int index, ByteBuf dst, int length) { + return this.delegate.getBytes(index, dst, length); + } + + @Override + public ByteBuf getBytes(int index, ByteBuf dst, int dstIndex, int length) { + return this.delegate.getBytes(index, dst, dstIndex, length); + } + + @Override + public ByteBuf getBytes(int index, byte[] dst) { + return this.delegate.getBytes(index, dst); + } + + @Override + public ByteBuf getBytes(int index, byte[] dst, int dstIndex, int length) { + return this.delegate.getBytes(index, dst, dstIndex, length); + } + + @Override + public ByteBuf getBytes(int index, ByteBuffer dst) { + return this.delegate.getBytes(index, dst); + } + + @Override + public ByteBuf getBytes(int index, OutputStream out, int length) throws IOException { + return this.delegate.getBytes(index, out, length); + } + + @Override + public int getBytes(int index, GatheringByteChannel out, int length) throws IOException { + return this.delegate.getBytes(index, out, length); + } + + @Override + public int getBytes(int index, FileChannel out, long position, int length) throws IOException { + return this.delegate.getBytes(index, out, position, length); + } + + @Override + public CharSequence getCharSequence(int index, int length, Charset charset) { + return this.delegate.getCharSequence(index, length, charset); + } + + @Override + public ByteBuf setBoolean(int index, boolean value) { + return this.delegate.setBoolean(index, value); + } + + @Override + public ByteBuf setByte(int index, int value) { + return this.delegate.setByte(index, value); + } + + @Override + public ByteBuf setShort(int index, int value) { + return this.delegate.setShort(index, value); + } + + @Override + public ByteBuf setShortLE(int index, int value) { + return this.delegate.setShortLE(index, value); + } + + @Override + public ByteBuf setMedium(int index, int value) { + return this.delegate.setMedium(index, value); + } + + @Override + public ByteBuf setMediumLE(int index, int value) { + return this.delegate.setMediumLE(index, value); + } + + @Override + public ByteBuf setInt(int index, int value) { + return this.delegate.setInt(index, value); + } + + @Override + public ByteBuf setIntLE(int index, int value) { + return this.delegate.setIntLE(index, value); + } + + @Override + public ByteBuf setLong(int index, long value) { + return this.delegate.setLong(index, value); + } + + @Override + public ByteBuf setLongLE(int index, long value) { + return this.delegate.setLongLE(index, value); + } + + @Override + public ByteBuf setChar(int index, int value) { + return this.delegate.setChar(index, value); + } + + @Override + public ByteBuf setFloat(int index, float value) { + return this.delegate.setFloat(index, value); + } + + @Override + public ByteBuf setDouble(int index, double value) { + return this.delegate.setDouble(index, value); + } + + @Override + public ByteBuf setBytes(int index, ByteBuf src) { + return this.delegate.setBytes(index, src); + } + + @Override + public ByteBuf setBytes(int index, ByteBuf src, int length) { + return this.delegate.setBytes(index, src, length); + } + + @Override + public ByteBuf setBytes(int index, ByteBuf src, int srcIndex, int length) { + return this.delegate.setBytes(index, src, srcIndex, length); + } + + @Override + public ByteBuf setBytes(int index, byte[] src) { + return this.delegate.setBytes(index, src); + } + + @Override + public ByteBuf setBytes(int index, byte[] src, int srcIndex, int length) { + return this.delegate.setBytes(index, src, srcIndex, length); + } + + @Override + public ByteBuf setBytes(int index, ByteBuffer src) { + return this.delegate.setBytes(index, src); + } + + @Override + public int setBytes(int index, InputStream in, int length) throws IOException { + return this.delegate.setBytes(index, in, length); + } + + @Override + public int setBytes(int index, ScatteringByteChannel in, int length) throws IOException { + return this.delegate.setBytes(index, in, length); + } + + @Override + public int setBytes(int index, FileChannel in, long position, int length) throws IOException { + return this.delegate.setBytes(index, in, position, length); + } + + @Override + public ByteBuf setZero(int index, int length) { + return this.delegate.setZero(index, length); + } + + @Override + public int setCharSequence(int index, CharSequence sequence, Charset charset) { + return this.delegate.setCharSequence(index, sequence, charset); + } + + @Override + public boolean readBoolean() { + return this.delegate.readBoolean(); + } + + @Override + public byte readByte() { + return this.delegate.readByte(); + } + + @Override + public short readUnsignedByte() { + return this.delegate.readUnsignedByte(); + } + + @Override + public short readShort() { + return this.delegate.readShort(); + } + + @Override + public short readShortLE() { + return this.delegate.readShortLE(); + } + + @Override + public int readUnsignedShort() { + return this.delegate.readUnsignedShort(); + } + + @Override + public int readUnsignedShortLE() { + return this.delegate.readUnsignedShortLE(); + } + + @Override + public int readMedium() { + return this.delegate.readMedium(); + } + + @Override + public int readMediumLE() { + return this.delegate.readMediumLE(); + } + + @Override + public int readUnsignedMedium() { + return this.delegate.readUnsignedMedium(); + } + + @Override + public int readUnsignedMediumLE() { + return this.delegate.readUnsignedMediumLE(); + } + + @Override + public int readInt() { + return this.delegate.readInt(); + } + + @Override + public int readIntLE() { + return this.delegate.readIntLE(); + } + + @Override + public long readUnsignedInt() { + return this.delegate.readUnsignedInt(); + } + + @Override + public long readUnsignedIntLE() { + return this.delegate.readUnsignedIntLE(); + } + + @Override + public long readLong() { + return this.delegate.readLong(); + } + + @Override + public long readLongLE() { + return this.delegate.readLongLE(); + } + + @Override + public char readChar() { + return this.delegate.readChar(); + } + + @Override + public float readFloat() { + return this.delegate.readFloat(); + } + + @Override + public double readDouble() { + return this.delegate.readDouble(); + } + + @Override + public ByteBuf readBytes(int length) { + return this.delegate.readBytes(length); + } + + @Override + public ByteBuf readSlice(int length) { + return this.delegate.readSlice(length); + } + + @Override + public ByteBuf readRetainedSlice(int length) { + return this.delegate.readRetainedSlice(length); + } + + @Override + public ByteBuf readBytes(ByteBuf dst) { + return this.delegate.readBytes(dst); + } + + @Override + public ByteBuf readBytes(ByteBuf dst, int length) { + return this.delegate.readBytes(dst, length); + } + + @Override + public ByteBuf readBytes(ByteBuf dst, int dstIndex, int length) { + return this.delegate.readBytes(dst, dstIndex, length); + } + + @Override + public ByteBuf readBytes(byte[] dst) { + return this.delegate.readBytes(dst); + } + + @Override + public ByteBuf readBytes(byte[] dst, int dstIndex, int length) { + return this.delegate.readBytes(dst, dstIndex, length); + } + + @Override + public ByteBuf readBytes(ByteBuffer dst) { + return this.delegate.readBytes(dst); + } + + @Override + public ByteBuf readBytes(OutputStream out, int length) throws IOException { + return this.delegate.readBytes(out, length); + } + + @Override + public int readBytes(GatheringByteChannel out, int length) throws IOException { + return this.delegate.readBytes(out, length); + } + + @Override + public CharSequence readCharSequence(int length, Charset charset) { + return this.delegate.readCharSequence(length, charset); + } + + @Override + public int readBytes(FileChannel out, long position, int length) throws IOException { + return this.delegate.readBytes(out, position, length); + } + + @Override + public ByteBuf skipBytes(int length) { + return this.delegate.skipBytes(length); + } + + @Override + public ByteBuf writeBoolean(boolean value) { + return this.delegate.writeBoolean(value); + } + + @Override + public ByteBuf writeByte(int value) { + return this.delegate.writeByte(value); + } + + @Override + public ByteBuf writeShort(int value) { + return this.delegate.writeShort(value); + } + + @Override + public ByteBuf writeShortLE(int value) { + return this.delegate.writeShortLE(value); + } + + @Override + public ByteBuf writeMedium(int value) { + return this.delegate.writeMedium(value); + } + + @Override + public ByteBuf writeMediumLE(int value) { + return this.delegate.writeMediumLE(value); + } + + @Override + public ByteBuf writeInt(int value) { + return this.delegate.writeInt(value); + } + + @Override + public ByteBuf writeIntLE(int value) { + return this.delegate.writeIntLE(value); + } + + @Override + public ByteBuf writeLong(long value) { + return this.delegate.writeLong(value); + } + + @Override + public ByteBuf writeLongLE(long value) { + return this.delegate.writeLongLE(value); + } + + @Override + public ByteBuf writeChar(int value) { + return this.delegate.writeChar(value); + } + + @Override + public ByteBuf writeFloat(float value) { + return this.delegate.writeFloat(value); + } + + @Override + public ByteBuf writeDouble(double value) { + return this.delegate.writeDouble(value); + } + + @Override + public ByteBuf writeBytes(ByteBuf src) { + return this.delegate.writeBytes(src); + } + + @Override + public ByteBuf writeBytes(ByteBuf src, int length) { + return this.delegate.writeBytes(src, length); + } + + @Override + public ByteBuf writeBytes(ByteBuf src, int srcIndex, int length) { + return this.delegate.writeBytes(src, srcIndex, length); + } + + @Override + public ByteBuf writeBytes(byte[] src) { + return this.delegate.writeBytes(src); + } + + @Override + public ByteBuf writeBytes(byte[] src, int srcIndex, int length) { + return this.delegate.writeBytes(src, srcIndex, length); + } + + @Override + public ByteBuf writeBytes(ByteBuffer src) { + return this.delegate.writeBytes(src); + } + + @Override + public int writeBytes(InputStream in, int length) throws IOException { + return this.delegate.writeBytes(in, length); + } + + @Override + public int writeBytes(ScatteringByteChannel in, int length) throws IOException { + return this.delegate.writeBytes(in, length); + } + + @Override + public int writeBytes(FileChannel in, long position, int length) throws IOException { + return this.delegate.writeBytes(in, position, length); + } + + @Override + public ByteBuf writeZero(int length) { + return this.delegate.writeZero(length); + } + + @Override + public int writeCharSequence(CharSequence sequence, Charset charset) { + return this.delegate.writeCharSequence(sequence, charset); + } + + @Override + public int indexOf(int fromIndex, int toIndex, byte value) { + return this.delegate.indexOf(fromIndex, toIndex, value); + } + + @Override + public int bytesBefore(byte value) { + return this.delegate.bytesBefore(value); + } + + @Override + public int bytesBefore(int length, byte value) { + return this.delegate.bytesBefore(length, value); + } + + @Override + public int bytesBefore(int index, int length, byte value) { + return this.delegate.bytesBefore(index, length, value); + } + + @Override + public int forEachByte(ByteProcessor processor) { + return this.delegate.forEachByte(processor); + } + + @Override + public int forEachByte(int index, int length, ByteProcessor processor) { + return this.delegate.forEachByte(index, length, processor); + } + + @Override + public int forEachByteDesc(ByteProcessor processor) { + return this.delegate.forEachByteDesc(processor); + } + + @Override + public int forEachByteDesc(int index, int length, ByteProcessor processor) { + return this.delegate.forEachByteDesc(index, length, processor); + } + + @Override + public ByteBuf copy() { + return this.delegate.copy(); + } + + @Override + public ByteBuf copy(int index, int length) { + return this.delegate.copy(index, length); + } + + @Override + public ByteBuf slice() { + return this.delegate.slice(); + } + + @Override + public ByteBuf retainedSlice() { + return this.delegate.retainedSlice(); + } + + @Override + public ByteBuf slice(int index, int length) { + return this.delegate.slice(index, length); + } + + @Override + public ByteBuf retainedSlice(int index, int length) { + return this.delegate.retainedSlice(index, length); + } + + @Override + public ByteBuf duplicate() { + return this.delegate.duplicate(); + } + + @Override + public ByteBuf retainedDuplicate() { + return this.delegate.retainedDuplicate(); + } + + @Override + public int nioBufferCount() { + return this.delegate.nioBufferCount(); + } + + @Override + public ByteBuffer nioBuffer() { + return this.delegate.nioBuffer(); + } + + @Override + public ByteBuffer nioBuffer(int index, int length) { + return this.delegate.nioBuffer(index, length); + } + + @Override + public ByteBuffer internalNioBuffer(int index, int length) { + return this.delegate.internalNioBuffer(index, length); + } + + @Override + public ByteBuffer[] nioBuffers() { + return this.delegate.nioBuffers(); + } + + @Override + public ByteBuffer[] nioBuffers(int index, int length) { + return this.delegate.nioBuffers(index, length); + } + + @Override + public boolean hasArray() { + return this.delegate.hasArray(); + } + + @Override + public byte[] array() { + return this.delegate.array(); + } + + @Override + public int arrayOffset() { + return this.delegate.arrayOffset(); + } + + @Override + public boolean hasMemoryAddress() { + return this.delegate.hasMemoryAddress(); + } + + @Override + public long memoryAddress() { + return this.delegate.memoryAddress(); + } + + @Override + public String toString(Charset charset) { + return this.delegate.toString(charset); + } + + @Override + public String toString(int index, int length, Charset charset) { + return this.delegate.toString(index, length, charset); + } + + @Override + public int hashCode() { + return this.delegate.hashCode(); + } + + @Override + public boolean equals(Object o) { + return this.delegate.equals(o); + } + + @Override + public int compareTo(ByteBuf o) { + return this.delegate.compareTo(o); + } + + @Override + public String toString() { + return this.delegate.toString(); + } + + @Override + public ByteBuf retain(int increment) { + return this.delegate.retain(increment); + } + + @Override + public ByteBuf retain() { + return this.delegate.retain(); + } + + @Override + public ByteBuf touch() { + return this.delegate.touch(); + } + + @Override + public ByteBuf touch(Object hint) { + return this.delegate.touch(hint); + } + + @Override + public int refCnt() { + return this.delegate.refCnt(); + } + + @Override + public boolean release() { + return this.delegate.release(); + } + + @Override + public boolean release(int decrement) { + return this.delegate.release(decrement); + } +} diff --git a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/PacketBuffers.java b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/PacketBuffers.java new file mode 100644 index 00000000..a9e6ccc8 --- /dev/null +++ b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/PacketBuffers.java @@ -0,0 +1,35 @@ +package net.ornithemc.osl.networking.api; + +import java.io.IOException; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; + +import net.ornithemc.osl.core.api.util.function.IOConsumer; + +public final class PacketBuffers { + + public static PacketBuffer make() { + return wrapped(Unpooled.buffer()); + } + + public static PacketBuffer make(IOConsumer writer) throws IOException { + PacketBuffer buffer = make(); + writer.accept(buffer); + return buffer; + } + + public static PacketBuffer wrap(byte[] bytes) { + return wrapped(Unpooled.wrappedBuffer(bytes)); + } + + public static byte[] unwrap(PacketBuffer buffer) { + byte[] bytes = new byte[buffer.writerIndex()]; + buffer.getBytes(0, bytes); + return bytes; + } + + public static PacketBuffer wrapped(ByteBuf buffer) { + return new PacketBuffer(buffer); + } +} diff --git a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/PacketPayload.java b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/PacketPayload.java new file mode 100644 index 00000000..7f7835e7 --- /dev/null +++ b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/PacketPayload.java @@ -0,0 +1,11 @@ +package net.ornithemc.osl.networking.api; + +import java.io.IOException; + +public interface PacketPayload { + + void read(PacketBuffer buffer) throws IOException; + + void write(PacketBuffer buffer) throws IOException; + +} diff --git a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java index dbe85275..9d33bccf 100644 --- a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java +++ b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/server/ServerConnectionEvents.java @@ -20,6 +20,10 @@ public class ServerConnectionEvents { * and until then data cannot safely be sent to the client. * *

+ * This applies to connections to dedicated servers as + * well as connections to integrated servers. + * + *

* Callbacks to this event should be registered in your mod's entrypoint, * and can be done as follows: * @@ -39,6 +43,10 @@ public class ServerConnectionEvents { * This marks the moment data can safely be sent to the client. * *

+ * This applies to connections to dedicated servers as + * well as connections to integrated servers. + * + *

* Callbacks to this event should be registered in your mod's entrypoint, * and can be done as follows: * @@ -55,6 +63,10 @@ public class ServerConnectionEvents { * This event is fired when a client disconnects from the server. * *

+ * This applies to connections to dedicated servers as + * well as connections to integrated servers. + * + *

* Callbacks to this event should be registered in your mod's entrypoint, * and can be done as follows: * diff --git a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java new file mode 100644 index 00000000..1ec5a4f0 --- /dev/null +++ b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java @@ -0,0 +1,32 @@ +package net.ornithemc.osl.networking.api.server; + +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.entity.mob.player.ServerPlayerEntity; +import net.minecraft.server.network.handler.ServerPlayNetworkHandler; + +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketPayload; + +public interface ServerPacketListener { + + /** + * Receive incoming data from the client. + * + * @return + * Whether the data is consumed. Should only return {@code false} if the + * data is completely ignored. + */ + boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, T data); + + @FunctionalInterface + public interface Payload extends ServerPacketListener { + } + + @FunctionalInterface + public interface Buffer extends ServerPacketListener { + } + + @FunctionalInterface + public interface Bytes extends ServerPacketListener { + } +} diff --git a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java index 7eda8cca..c46df829 100644 --- a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java +++ b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java @@ -1,16 +1,13 @@ package net.ornithemc.osl.networking.api.server; -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; import java.util.function.Supplier; -import net.minecraft.server.MinecraftServer; import net.minecraft.server.entity.mob.player.ServerPlayerEntity; -import net.minecraft.server.network.handler.ServerPlayNetworkHandler; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.CustomPayload; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketPayload; import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; public final class ServerPlayNetworking { @@ -18,34 +15,55 @@ public final class ServerPlayNetworking { /** * Register a listener to receive data from the server through the given channel. * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. */ - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { + public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { ServerPlayNetworkingImpl.registerListener(channel, initializer, listener); } + /** + * Register a listener to receive data from the server through the given channel. + * This listener may be called off the main thread. + */ + public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { + ServerPlayNetworkingImpl.registerListenerAsync(channel, initializer, listener); + } + /** * Register a listener to receive data from the server through the given channel. * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. */ - public static void registerListener(String channel, StreamListener listener) { + public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { ServerPlayNetworkingImpl.registerListener(channel, listener); } + /** + * Register a listener to receive data from the server through the given channel. + * This listener may be called off the main thread. + */ + public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { + ServerPlayNetworkingImpl.registerListenerAsync(channel, listener); + } + /** * Register a listener to receive data from the server through the given channel. * This listener will only be called from the main thread. - * A channel can be any String of length {@value net.ornithemc.osl.networking.api.Channels#MAX_LENGTH} or less. */ - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - ServerPlayNetworkingImpl.registerListenerRaw(channel, listener); + public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { + ServerPlayNetworkingImpl.registerListener(channel, listener); + } + + /** + * Register a listener to receive data from the server through the given channel. + * This listener may be called off the main thread. + */ + public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { + ServerPlayNetworkingImpl.registerListenerAsync(channel, listener); } /** * Remove the listener registered to the given channel. */ - public static void unregisterListener(String channel) { + public static void unregisterListener(NamespacedIdentifier channel) { ServerPlayNetworkingImpl.unregisterListener(channel); } @@ -57,19 +75,19 @@ public static boolean isPlayReady(ServerPlayerEntity player) { } /** - * Check whether the given channel is open for data to be sent through it. + * Check whether the given channel is ready for data to be sent through it. * This method will return {@code false} if the client has no listeners for * the given channel. */ - public static boolean canSend(ServerPlayerEntity player, String channel) { - return ServerPlayNetworkingImpl.canSend(player, channel); + public static boolean isPlayReady(ServerPlayerEntity player, NamespacedIdentifier channel) { + return ServerPlayNetworkingImpl.isPlayReady(player, channel); } /** * Send a packet to the given player through the given channel. The payload * will only be written if the channel is open. */ - public static void send(ServerPlayerEntity player, String channel, CustomPayload payload) { + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, PacketPayload payload) { ServerPlayNetworkingImpl.send(player, channel, payload); } @@ -77,22 +95,29 @@ public static void send(ServerPlayerEntity player, String channel, CustomPayload * Send a packet to the given player through the given channel. The writer * will only be called if the channel is open. */ - public static void send(ServerPlayerEntity player, String channel, IOConsumer writer) { + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, IOConsumer writer) { ServerPlayNetworkingImpl.send(player, channel, writer); } /** * Send a packet to the given player through the given channel. */ - public static void send(ServerPlayerEntity player, String channel, byte[] data) { - ServerPlayNetworkingImpl.send(player, channel, data); + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, PacketBuffer buffer) { + ServerPlayNetworkingImpl.send(player, channel, buffer); + } + + /** + * Send a packet to the given player through the given channel. + */ + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, byte[] bytes) { + ServerPlayNetworkingImpl.send(player, channel, bytes); } /** * Send a packet to the given players through the given channel. The payload * will only be written if the channel is open for at least one player. */ - public static void send(Iterable players, String channel, CustomPayload payload) { + public static void send(Iterable players, NamespacedIdentifier channel, PacketPayload payload) { ServerPlayNetworkingImpl.send(players, channel, payload); } @@ -100,15 +125,22 @@ public static void send(Iterable players, String channel, Cu * Send a packet to the given players through the given channel. The writer * will only be called if the channel is open for at least one player. */ - public static void send(Iterable players, String channel, IOConsumer writer) { + public static void send(Iterable players, NamespacedIdentifier channel, IOConsumer writer) { ServerPlayNetworkingImpl.send(players, channel, writer); } /** * Send a packet to the given players through the given channel. */ - public static void send(Iterable players, String channel, byte[] data) { - ServerPlayNetworkingImpl.send(players, channel, data); + public static void send(Iterable players, NamespacedIdentifier channel, PacketBuffer buffer) { + ServerPlayNetworkingImpl.send(players, channel, buffer); + } + + /** + * Send a packet to the given players through the given channel. + */ + public static void send(Iterable players, NamespacedIdentifier channel, byte[] bytes) { + ServerPlayNetworkingImpl.send(players, channel, bytes); } /** @@ -116,7 +148,7 @@ public static void send(Iterable players, String channel, by * channel. The payload will only be written if the channel is open for at * least one player. */ - public static void send(int dimension, String channel, CustomPayload payload) { + public static void send(int dimension, NamespacedIdentifier channel, PacketPayload payload) { ServerPlayNetworkingImpl.send(dimension, channel, payload); } @@ -125,7 +157,7 @@ public static void send(int dimension, String channel, CustomPayload payload) { * channel. The writer will only be called if the channel is open for at * least one player. */ - public static void send(int dimension, String channel, IOConsumer writer) { + public static void send(int dimension, NamespacedIdentifier channel, IOConsumer writer) { ServerPlayNetworkingImpl.send(dimension, channel, writer); } @@ -133,15 +165,23 @@ public static void send(int dimension, String channel, IOConsumer writer) { + public static void send(NamespacedIdentifier channel, IOConsumer writer) { ServerPlayNetworkingImpl.send(channel, writer); } /** * Send a packet to all players through the given channel. */ - public static void send(String channel, byte[] data) { - ServerPlayNetworkingImpl.send(channel, data); + public static void send(NamespacedIdentifier channel, PacketBuffer buffer) { + ServerPlayNetworkingImpl.send(channel, buffer); + } + + /** + * Send a packet to all players through the given channel. + */ + public static void send(NamespacedIdentifier channel, byte[] bytes) { + ServerPlayNetworkingImpl.send(channel, bytes); } /** @@ -166,8 +213,8 @@ public static void send(String channel, byte[] data) { * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(ServerPlayerEntity player, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(player, channel, payload); + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, PacketPayload payload) { + ServerPlayNetworkingImpl.sendNoCheck(player, channel, payload); } /** @@ -176,8 +223,8 @@ public static void doSend(ServerPlayerEntity player, String channel, CustomPaylo * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(ServerPlayerEntity player, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(player, channel, writer); + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, IOConsumer writer) { + ServerPlayNetworkingImpl.sendNoCheck(player, channel, writer); } /** @@ -186,8 +233,18 @@ public static void doSend(ServerPlayerEntity player, String channel, IOConsumer< * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(ServerPlayerEntity player, String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(player, channel, data); + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, PacketBuffer buffer) { + ServerPlayNetworkingImpl.sendNoCheck(player, channel, buffer); + } + + /** + * Send a packet to the given player through the given channel, without + * checking whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the client. + */ + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, byte[] bytes) { + ServerPlayNetworkingImpl.sendNoCheck(player, channel, bytes); } /** @@ -196,8 +253,8 @@ public static void doSend(ServerPlayerEntity player, String channel, byte[] data * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(Iterable players, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(players, channel, payload); + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, PacketPayload payload) { + ServerPlayNetworkingImpl.sendNoCheck(players, channel, payload); } /** @@ -206,8 +263,8 @@ public static void doSend(Iterable players, String channel, * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(Iterable players, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(players, channel, writer); + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, IOConsumer writer) { + ServerPlayNetworkingImpl.sendNoCheck(players, channel, writer); } /** @@ -216,8 +273,18 @@ public static void doSend(Iterable players, String channel, * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(Iterable players, String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(players, channel, data); + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, PacketBuffer buffer) { + ServerPlayNetworkingImpl.sendNoCheck(players, channel, buffer); + } + + /** + * Send a packet to the given players through the given channel, without + * checking whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the client. + */ + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, byte[] bytes) { + ServerPlayNetworkingImpl.sendNoCheck(players, channel, bytes); } /** @@ -226,8 +293,8 @@ public static void doSend(Iterable players, String channel, * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(int dimension, String channel, CustomPayload payload) { - ServerPlayNetworkingImpl.doSend(dimension, channel, payload); + public static void sendNoCheck(int dimension, NamespacedIdentifier channel, PacketPayload payload) { + ServerPlayNetworkingImpl.sendNoCheck(dimension, channel, payload); } /** @@ -236,8 +303,8 @@ public static void doSend(int dimension, String channel, CustomPayload payload) * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(int dimension, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(dimension, channel, writer); + public static void sendNoCheck(int dimension, NamespacedIdentifier channel, IOConsumer writer) { + ServerPlayNetworkingImpl.sendNoCheck(dimension, channel, writer); } /** @@ -246,18 +313,18 @@ public static void doSend(int dimension, String channel, IOConsumer writer) { - ServerPlayNetworkingImpl.doSend(channel, writer); + public static void sendNoCheck(NamespacedIdentifier channel, PacketPayload payload) { + ServerPlayNetworkingImpl.sendNoCheck(channel, payload); } /** @@ -276,46 +343,27 @@ public static void doSend(String channel, IOConsumer writer) { * USE WITH CAUTION. Careless use of this method could lead to packet and log * spam on the client. */ - public static void doSend(String channel, byte[] data) { - ServerPlayNetworkingImpl.doSend(channel, data); - } - - public interface PayloadListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, T payload) throws IOException; - + public static void sendNoCheck(NamespacedIdentifier channel, IOConsumer writer) { + ServerPlayNetworkingImpl.sendNoCheck(channel, writer); } - public interface StreamListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, DataInputStream data) throws IOException; - + /** + * Send a packet to all players through the given channel, without + * checking whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the client. + */ + public static void sendNoCheck(NamespacedIdentifier channel, PacketBuffer buffer) { + ServerPlayNetworkingImpl.sendNoCheck(channel, buffer); } - public interface ByteArrayListener { - - /** - * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. - */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] data) throws IOException; - + /** + * Send a packet to all players through the given channel, without + * checking whether it is open. + * USE WITH CAUTION. Careless use of this method could lead to packet and log + * spam on the client. + */ + public static void sendNoCheck(NamespacedIdentifier channel, byte[] bytes) { + ServerPlayNetworkingImpl.sendNoCheck(channel, bytes); } } diff --git a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/Connections.java b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/Connections.java new file mode 100644 index 00000000..836dd8ed --- /dev/null +++ b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/Connections.java @@ -0,0 +1,22 @@ +package net.ornithemc.osl.networking.impl; + +import net.minecraft.network.PacketHandler; +import net.minecraft.network.packet.Packet; + +import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; + +public final class Connections { + + public static boolean checkAsyncHandling(Packet packet, PacketHandler listener) { + boolean handleAsync = packet instanceof CustomPayloadPacketAccess + && listener instanceof NetworkHandlerAccess + && ((NetworkHandlerAccess) listener).osl$networking$canRunOffMainThread(); + + if (handleAsync) { + packet.handle(listener); + } + + return handleAsync; + } +} diff --git a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java deleted file mode 100644 index 76c2850d..00000000 --- a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/CustomPayloadPacket.java +++ /dev/null @@ -1,75 +0,0 @@ -package net.ornithemc.osl.networking.impl; - -import java.io.DataInputStream; -import java.io.DataOutputStream; -import java.io.IOException; -import java.io.UncheckedIOException; - -import net.minecraft.network.PacketHandler; -import net.minecraft.network.packet.Packet; - -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; - -public class CustomPayloadPacket extends Packet { - - public String channel; - public int size; - public byte[] data; - - public CustomPayloadPacket() { - } - - public CustomPayloadPacket(String channel, byte[] data) { - this.channel = channel; - this.data = data; - if (data != null) { - this.size = data.length; - if (this.size > Short.MAX_VALUE) { - throw new IllegalArgumentException("Payload may not be larger than 32k"); - } - } - } - - // the IOException has been stripped from the read/write methods - // by the obfuscator, thus we catch it and re-throw it as a - // runtime exception - it will be caught in Connection#read anyhow - - @Override - public void read(DataInputStream input) { - try { - this.channel = input.readUTF(); - this.size = input.readShort(); - if (this.size > 0 && this.size < Short.MAX_VALUE) { - this.data = new byte[this.size]; - input.readFully(this.data); - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - @Override - public void write(DataOutputStream output) { - try { - output.writeUTF(this.channel); - output.writeShort(this.size); - if (this.data != null) { - output.write(this.data); - } - } catch (IOException e) { - throw new UncheckedIOException(e); - } - } - - @Override - public void handle(PacketHandler handler) { - if (handler instanceof INetworkHandler) { - ((INetworkHandler)handler).osl$networking$handleCustomPayload(this); - } - } - - @Override - public int getSize() { - return 2 + this.channel.length() * 2 + 2 + this.size; - } -} diff --git a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java index 8fc8931f..1c65baa7 100644 --- a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java +++ b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java @@ -1,53 +1,56 @@ package net.ornithemc.osl.networking.impl; -import java.io.DataInputStream; -import java.io.DataOutputStream; import java.io.IOException; import java.util.LinkedHashSet; import java.util.Set; -import net.ornithemc.osl.networking.api.CustomPayload; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.api.ChannelIdentifiers; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketPayload; import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; -public class HandshakePayload implements CustomPayload { +public class HandshakePayload implements PacketPayload { - public static final String CHANNEL = "OSL|Handshake"; + public static final NamespacedIdentifier CHANNEL = Constants.OSL_HANDSHAKE_CHANNEL; - public Set channels; + public byte protocol; + public Set channels; public HandshakePayload() { } - public HandshakePayload(Set channels) { - this.channels = channels; - } - - public static HandshakePayload client() { - throw new UnsupportedOperationException(); + public HandshakePayload(Set channels) { + this.protocol = Constants.OSL_HANDSHAKE_PROTOCOL; + // we allow registering listeners on channels that do not conform to OSL spec + // but payloads sent over these channels aren't sent via OSL so we can ignore + // them for the OSL handshake. + this.channels = ChannelIdentifiers.dropInvalid(channels); } public static HandshakePayload server() { - return new HandshakePayload(ServerPlayNetworkingImpl.LISTENERS.keySet()); + return new HandshakePayload(ServerPlayNetworkingImpl.CHANNEL_LISTENERS.keySet()); } @Override - public void read(DataInputStream input) throws IOException { + public void read(PacketBuffer buffer) throws IOException { + protocol = buffer.readByte(); channels = new LinkedHashSet<>(); - int channelCount = input.readInt(); - if (channelCount > 0) { - for (int i = 0; i < channelCount; i++) { - channels.add(input.readUTF()); - } + int channelCount = buffer.readInt(); + + for (int i = 0; i < channelCount; i++) { + channels.add(buffer.readNamespacedIdentifier()); } } @Override - public void write(DataOutputStream output) throws IOException { - output.writeInt(channels.size()); + public void write(PacketBuffer buffer) throws IOException { + buffer.writeByte(protocol); + buffer.writeInt(channels.size()); - for (String channel : channels) { - output.writeUTF(channel); + for (NamespacedIdentifier channel : channels) { + buffer.writeNamespacedIdentifier(channel); } } } diff --git a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/Networking.java deleted file mode 100644 index d3c0e85d..00000000 --- a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/Networking.java +++ /dev/null @@ -1,34 +0,0 @@ -package net.ornithemc.osl.networking.impl; - -import net.ornithemc.osl.entrypoints.api.ModInitializer; -import net.ornithemc.osl.entrypoints.api.server.ServerModInitializer; -import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; -import net.ornithemc.osl.networking.api.server.ServerConnectionEvents; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; -import net.ornithemc.osl.networking.impl.mixin.common.PacketAccessor; -import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; - -public class Networking implements ModInitializer, ServerModInitializer { - - @Override - public void init() { - PacketAccessor.register(Constants.CUSTOM_PAYLOAD_PACKET_ID, CustomPayloadPacket.class); - } - - @Override - public void initServer() { - MinecraftServerEvents.START.register(server -> { - ServerPlayNetworkingImpl.setUp(server); - }); - MinecraftServerEvents.STOP.register(server -> { - ServerPlayNetworkingImpl.destroy(server); - }); - ServerPlayNetworking.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { - ((INetworkHandler)handler).osl$networking$registerChannels(payload.channels); - ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); - - return true; - }); - } -} diff --git a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/PacketFactory.java b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/PacketFactory.java new file mode 100644 index 00000000..2a4f77aa --- /dev/null +++ b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/PacketFactory.java @@ -0,0 +1,11 @@ +package net.ornithemc.osl.networking.impl; + +import net.minecraft.network.packet.Packet; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; + +public interface PacketFactory { + + Packet create(NamespacedIdentifier channel, byte[] data); + +} diff --git a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/access/CustomPayloadPacketAccess.java b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/access/CustomPayloadPacketAccess.java new file mode 100644 index 00000000..9c17038b --- /dev/null +++ b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/access/CustomPayloadPacketAccess.java @@ -0,0 +1,11 @@ +package net.ornithemc.osl.networking.impl.access; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; + +public interface CustomPayloadPacketAccess { + + NamespacedIdentifier osl$networking$getChannel(); + + byte[] osl$networking$getData(); + +} diff --git a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/access/NetworkHandlerAccess.java b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/access/NetworkHandlerAccess.java new file mode 100644 index 00000000..81b86b1f --- /dev/null +++ b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/access/NetworkHandlerAccess.java @@ -0,0 +1,17 @@ +package net.ornithemc.osl.networking.impl.access; + +import java.util.Set; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; + +public interface NetworkHandlerAccess { + + boolean osl$networking$canRunOffMainThread(); + + boolean osl$networking$isPlayReady(); + + boolean osl$networking$isPlayReady(NamespacedIdentifier channel); + + void osl$networking$registerChannels(Set channels); + +} diff --git a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/access/TaskRunnerAccess.java b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/access/TaskRunnerAccess.java new file mode 100644 index 00000000..bff1ba39 --- /dev/null +++ b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/access/TaskRunnerAccess.java @@ -0,0 +1,7 @@ +package net.ornithemc.osl.networking.impl.access; + +public interface TaskRunnerAccess { + + boolean osl$networking$submit(Runnable task); + +} diff --git a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java deleted file mode 100644 index 420bdcda..00000000 --- a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/interfaces/mixin/INetworkHandler.java +++ /dev/null @@ -1,17 +0,0 @@ -package net.ornithemc.osl.networking.impl.interfaces.mixin; - -import java.util.Set; - -import net.ornithemc.osl.networking.impl.CustomPayloadPacket; - -public interface INetworkHandler { - - boolean osl$networking$handleCustomPayload(CustomPayloadPacket packet); - - boolean osl$networking$isPlayReady(); - - void osl$networking$registerChannels(Set channels); - - boolean osl$networking$isRegisteredChannel(String channel); - -} diff --git a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java deleted file mode 100644 index ccc94437..00000000 --- a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/mixin/common/PacketAccessor.java +++ /dev/null @@ -1,15 +0,0 @@ -package net.ornithemc.osl.networking.impl.mixin.common; - -import org.spongepowered.asm.mixin.Mixin; -import org.spongepowered.asm.mixin.gen.Invoker; - -import net.minecraft.network.packet.Packet; - -@Mixin(Packet.class) -public interface PacketAccessor { - - @Invoker("register") - public static void register(int id, Class type) { - throw new AssertionError(); - } -} diff --git a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java index 711978a2..042f3fbd 100644 --- a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java +++ b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java @@ -1,6 +1,5 @@ package net.ornithemc.osl.networking.impl.server; -import java.io.DataOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.LinkedHashMap; @@ -17,63 +16,130 @@ import net.minecraft.server.entity.mob.player.ServerPlayerEntity; import net.minecraft.server.network.handler.ServerPlayNetworkHandler; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.core.api.util.function.IOConsumer; -import net.ornithemc.osl.networking.api.Channels; -import net.ornithemc.osl.networking.api.CustomPayload; -import net.ornithemc.osl.networking.api.DataStreams; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.ByteArrayListener; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.PayloadListener; -import net.ornithemc.osl.networking.api.server.ServerPlayNetworking.StreamListener; -import net.ornithemc.osl.networking.impl.CustomPayloadPacket; -import net.ornithemc.osl.networking.impl.interfaces.mixin.INetworkHandler; +import net.ornithemc.osl.networking.api.PacketBuffer; +import net.ornithemc.osl.networking.api.PacketBuffers; +import net.ornithemc.osl.networking.api.PacketPayload; +import net.ornithemc.osl.networking.api.server.ServerPacketListener; +import net.ornithemc.osl.networking.impl.PacketFactory; +import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; +import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; +import net.ornithemc.osl.networking.impl.access.TaskRunnerAccess; public final class ServerPlayNetworkingImpl { private static final Logger LOGGER = LogManager.getLogger("OSL|Server Play Networking"); + private static PacketFactory packetFactory; private static MinecraftServer server; + private static Thread thread; + + public static void setUpPacketFactory(PacketFactory factory) { + if (ServerPlayNetworkingImpl.packetFactory != null) { + throw new IllegalStateException("tried to set up server custom payload packet factory when it was already set up!"); + } + + ServerPlayNetworkingImpl.packetFactory = factory; + } public static void setUp(MinecraftServer server) { if (ServerPlayNetworkingImpl.server == server) { - throw new IllegalStateException("tried to set up server networking when it was already set up!"); + throw new IllegalStateException("tried to set up server play networking when it was already set up!"); + } + if (ServerPlayNetworkingImpl.packetFactory == null) { + throw new IllegalStateException("tried to set up server play networking when no custom payload packet factory was set up!"); } ServerPlayNetworkingImpl.server = server; + ServerPlayNetworkingImpl.thread = Thread.currentThread(); } public static void destroy(MinecraftServer server) { if (ServerPlayNetworkingImpl.server != server) { - throw new IllegalStateException("tried to destroy server networking when it was not set up!"); + throw new IllegalStateException("tried to destroy server play networking when it was not set up!"); } ServerPlayNetworkingImpl.server = null; + ServerPlayNetworkingImpl.thread = null; + } + + public static final Map CHANNEL_LISTENERS = new LinkedHashMap<>(); + + public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { + ServerPlayNetworkingImpl.registerListener(channel, initializer, listener, false); + } + + public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { + ServerPlayNetworkingImpl.registerListener(channel, initializer, listener, true); } - public static final Map LISTENERS = new LinkedHashMap<>(); + private static void registerListener(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener, boolean async) { + registerListenerImpl(channel, new ChannelListener() { + + @Override + public boolean isAsync() { + return async; + } - public static void registerListener(String channel, Supplier initializer, PayloadListener listener) { - registerListenerImpl(channel, (server, handler, player, data) -> { - T payload = initializer.get(); - payload.read(DataStreams.input(data)); + @Override + public boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] bytes) throws IOException { + T payload = initializer.get(); + payload.read(PacketBuffers.wrap(bytes)); - return listener.handle(server, handler, player, payload); + return listener.handle(server, handler, player, payload); + } }); } - public static void registerListener(String channel, StreamListener listener) { - registerListenerImpl(channel, (server, handler, player, data) -> { - return listener.handle(server, handler, player, DataStreams.input(data)); + public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { + ServerPlayNetworkingImpl.registerListener(channel, listener, false); + } + + public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { + ServerPlayNetworkingImpl.registerListener(channel, listener, true); + } + + private static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Buffer listener, boolean async) { + registerListenerImpl(channel, new ChannelListener() { + + @Override + public boolean isAsync() { + return async; + } + + @Override + public boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] bytes) throws IOException { + return listener.handle(server, handler, player, PacketBuffers.wrap(bytes)); + } }); } - public static void registerListenerRaw(String channel, ByteArrayListener listener) { - registerListenerImpl(channel, listener::handle); + public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { + ServerPlayNetworkingImpl.registerListener(channel, listener, false); + } + + public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { + ServerPlayNetworkingImpl.registerListener(channel, listener, true); } - private static void registerListenerImpl(String channel, Listener listener) { - LISTENERS.compute(channel, (key, value) -> { - Channels.validate(channel); + private static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener, boolean async) { + registerListenerImpl(channel, new ChannelListener() { + @Override + public boolean isAsync() { + return async; + } + + @Override + public boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] bytes) throws IOException { + return listener.handle(server, handler, player, bytes); + } + }); + } + + private static void registerListenerImpl(NamespacedIdentifier channel, ChannelListener listener) { + CHANNEL_LISTENERS.compute(channel, (key, value) -> { if (value != null) { throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); } @@ -82,140 +148,239 @@ private static void registerListenerImpl(String channel, Listener listener) { }); } - public static void unregisterListener(String channel) { - LISTENERS.remove(channel); + public static void unregisterListener(NamespacedIdentifier channel) { + CHANNEL_LISTENERS.remove(channel); } - public static boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, CustomPayloadPacket packet) { - Listener listener = LISTENERS.get(packet.channel); + public static boolean handlePacket(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, Packet packet) { + CustomPayloadPacketAccess p = (CustomPayloadPacketAccess)packet; + + NamespacedIdentifier channel = p.osl$networking$getChannel(); + ChannelListener listener = CHANNEL_LISTENERS.get(channel); if (listener != null) { - try { - return listener.handle(server, handler, player, packet.data); - } catch (IOException e) { - LOGGER.warn("error handling custom payload on channel \'" + packet.channel + "\'", e); - return true; + byte[] data = p.osl$networking$getData(); + + if (Thread.currentThread() == thread || listener.isAsync()) { + return handlePayload(server, handler, player, listener, channel, data); + } else { + return ((TaskRunnerAccess) server).osl$networking$submit(() -> handlePayload(server, handler, player, listener, channel, data)); } } return false; } + private static boolean handlePayload(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, ChannelListener listener, NamespacedIdentifier channel, byte[] data) { + try { + return listener.handle(server, handler, player, data); + } catch (IOException e) { + LOGGER.warn("error handling custom payload on channel \'" + channel + "\'", e); + } + + return true; + } + public static boolean isPlayReady(ServerPlayerEntity player) { - INetworkHandler handler = (INetworkHandler)player.networkHandler; + NetworkHandlerAccess handler = (NetworkHandlerAccess)player.networkHandler; return handler != null && handler.osl$networking$isPlayReady(); } - public static boolean canSend(ServerPlayerEntity player, String channel) { - INetworkHandler handler = (INetworkHandler)player.networkHandler; - return handler != null && handler.osl$networking$isRegisteredChannel(channel); + public static boolean isPlayReady(ServerPlayerEntity player, NamespacedIdentifier channel) { + NetworkHandlerAccess handler = (NetworkHandlerAccess)player.networkHandler; + return handler != null && handler.osl$networking$isPlayReady(channel); + } + + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, PacketPayload payload) { + if (isPlayReady(player, channel)) { + sendInternal(player, channel, payload); + } } - public static void send(ServerPlayerEntity player, String channel, CustomPayload payload) { - if (canSend(player, channel)) { - doSend(player, channel, payload); + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, IOConsumer writer) { + if (isPlayReady(player, channel)) { + sendInternal(player, channel, writer); } } - public static void send(ServerPlayerEntity player, String channel, IOConsumer writer) { - if (canSend(player, channel)) { - doSend(player, channel, writer); + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, PacketBuffer buffer) { + if (isPlayReady(player, channel)) { + sendInternal(player, channel, buffer); } } - public static void send(ServerPlayerEntity player, String channel, byte[] data) { - if (canSend(player, channel)) { - doSend(player, channel, data); + public static void send(ServerPlayerEntity player, NamespacedIdentifier channel, byte[] bytes) { + if (isPlayReady(player, channel)) { + sendInternal(player, channel, bytes); } } - public static void send(Iterable players, String channel, CustomPayload payload) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, payload)); + public static void send(Iterable players, NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(collectPlayers(players, p -> isPlayReady(p, channel)), channel, payload); + } + + public static void send(Iterable players, NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(collectPlayers(players, p -> isPlayReady(p, channel)), channel, writer); + } + + public static void send(Iterable players, NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(collectPlayers(players, p -> isPlayReady(p, channel)), channel, buffer); + } + + public static void send(Iterable players, NamespacedIdentifier channel, byte[] bytes) { + sendInternal(collectPlayers(players, p -> isPlayReady(p, channel)), channel, bytes); + } + + public static void send(int dimension, NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(collectPlayers(p -> p.dimension == dimension && isPlayReady(p, channel)), channel, payload); + } + + public static void send(int dimension, NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(collectPlayers(p -> p.dimension == dimension && isPlayReady(p, channel)), channel, writer); + } + + public static void send(int dimension, NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(collectPlayers(p -> p.dimension == dimension && isPlayReady(p, channel)),channel, buffer); + } + + public static void send(int dimension, NamespacedIdentifier channel, byte[] bytes) { + sendInternal(collectPlayers(p -> p.dimension == dimension && isPlayReady(p, channel)),channel, bytes); } - public static void send(Iterable players, String channel, IOConsumer writer) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, writer)); + public static void send(NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(collectPlayers(p -> isPlayReady(p, channel)), channel, payload); } - public static void send(Iterable players, String channel, byte[] data) { - sendPacket(collectPlayers(players, p -> canSend(p, channel)), makePacket(channel, data)); + public static void send(NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(collectPlayers(p -> isPlayReady(p, channel)), channel, writer); } - public static void send(int dimension, String channel, CustomPayload payload) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)), channel, payload); + public static void send(NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(collectPlayers(p -> isPlayReady(p, channel)), channel, buffer); } - public static void send(int dimension, String channel, IOConsumer writer) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)), channel, writer); + public static void send(NamespacedIdentifier channel, byte[] bytes) { + sendInternal(collectPlayers(p -> isPlayReady(p, channel)), channel, bytes); } - public static void send(int dimension, String channel, byte[] data) { - doSend(collectPlayers(p -> p.dimension == dimension && canSend(p, channel)),channel, data); + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(player, channel, payload); } - public static void send(String channel, CustomPayload payload) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, payload); + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(player, channel, writer); } - public static void send(String channel, IOConsumer writer) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, writer); + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(player, channel, buffer); } - public static void send(String channel, byte[] data) { - doSend(collectPlayers(p -> canSend(p, channel)), channel, data); + public static void sendNoCheck(ServerPlayerEntity player, NamespacedIdentifier channel, byte[] bytes) { + sendInternal(player, channel, bytes); } - public static void doSend(ServerPlayerEntity player, String channel, CustomPayload payload) { - sendPacket(player, makePacket(channel, payload)); + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(players, channel, payload); } - public static void doSend(ServerPlayerEntity player, String channel, IOConsumer writer) { - sendPacket(player, makePacket(channel, writer)); + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(players, channel, writer); } - public static void doSend(ServerPlayerEntity player, String channel, byte[] data) { - sendPacket(player, makePacket(channel, data)); + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(players, channel, buffer); } - public static void doSend(Iterable players, String channel, CustomPayload payload) { - sendPacket(players, makePacket(channel, payload)); + public static void sendNoCheck(Iterable players, NamespacedIdentifier channel, byte[] bytes) { + sendInternal(players, channel, bytes); } - public static void doSend(Iterable players, String channel, IOConsumer writer) { - sendPacket(players, makePacket(channel, writer)); + public static void sendNoCheck(int dimension, NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(collectPlayers(p -> p.dimension == dimension), channel, payload); } - public static void doSend(Iterable players, String channel, byte[] data) { - sendPacket(players, makePacket(channel, data)); + public static void sendNoCheck(int dimension, NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(collectPlayers(p -> p.dimension == dimension), channel, writer); } - public static void doSend(int dimension, String channel, CustomPayload payload) { - doSend(collectPlayers(p -> p.dimension == dimension), channel, payload); + public static void sendNoCheck(int dimension, NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(collectPlayers(p -> p.dimension == dimension),channel, buffer); } - public static void doSend(int dimension, String channel, IOConsumer writer) { - doSend(collectPlayers(p -> p.dimension == dimension), channel, writer); + public static void sendNoCheck(int dimension, NamespacedIdentifier channel, byte[] bytes) { + sendInternal(collectPlayers(p -> p.dimension == dimension),channel, bytes); } - public static void doSend(int dimension, String channel, byte[] data) { - doSend(collectPlayers(p -> p.dimension == dimension),channel, data); + public static void sendNoCheck(NamespacedIdentifier channel, PacketPayload payload) { + sendInternal(allPlayers(), channel, payload); } - public static void doSend(String channel, CustomPayload payload) { - doSend(collectPlayers(p -> true), channel, payload); + public static void sendNoCheck(NamespacedIdentifier channel, IOConsumer writer) { + sendInternal(allPlayers(), channel, writer); } - public static void doSend(String channel, IOConsumer writer) { - doSend(collectPlayers(p -> true), channel, writer); + public static void sendNoCheck(NamespacedIdentifier channel, PacketBuffer buffer) { + sendInternal(allPlayers(), channel, buffer); } - public static void doSend(String channel, byte[] data) { - doSend(collectPlayers(p -> true), channel, data); + public static void sendNoCheck(NamespacedIdentifier channel, byte[] bytes) { + sendInternal(allPlayers(), channel, bytes); + } + + private static void sendInternal(ServerPlayerEntity player, NamespacedIdentifier channel, PacketPayload payload) { + try { + sendPacket(player, channel, PacketBuffers.unwrap(PacketBuffers.make(payload::write))); + } catch (IOException e) { + LOGGER.warn("error writing packet payload to channel \'" + channel + "\'", e); + } + } + + private static void sendInternal(ServerPlayerEntity player, NamespacedIdentifier channel, IOConsumer writer) { + try { + sendPacket(player, channel, PacketBuffers.unwrap(PacketBuffers.make(writer))); + } catch (IOException e) { + LOGGER.warn("error writing buffer to channel \'" + channel + "\'", e); + } + } + + private static void sendInternal(ServerPlayerEntity player, NamespacedIdentifier channel, PacketBuffer buffer) { + sendPacket(player, channel, PacketBuffers.unwrap(buffer)); + } + + private static void sendInternal(ServerPlayerEntity player, NamespacedIdentifier channel, byte[] bytes) { + sendPacket(player, channel, bytes); + } + + private static void sendInternal(Iterable players, NamespacedIdentifier channel, PacketPayload payload) { + try { + sendPacket(players, channel, PacketBuffers.unwrap(PacketBuffers.make(payload::write))); + } catch (IOException e) { + LOGGER.warn("error writing packet payload to channel \'" + channel + "\'", e); + } + } + + private static void sendInternal(Iterable players, NamespacedIdentifier channel, IOConsumer writer) { + try { + sendPacket(players, channel, PacketBuffers.unwrap(PacketBuffers.make(writer))); + } catch (IOException e) { + LOGGER.warn("error writing buffer to channel \'" + channel + "\'", e); + } + } + + private static void sendInternal(Iterable players, NamespacedIdentifier channel, PacketBuffer buffer) { + sendPacket(players, channel, PacketBuffers.unwrap(buffer)); + } + + private static void sendInternal(Iterable players, NamespacedIdentifier channel, byte[] bytes) { + sendPacket(players, channel, bytes); + } + + private static Iterable allPlayers() { + return server.playerManager.players; } - @SuppressWarnings("unchecked") // thanks proguard private static Iterable collectPlayers(Predicate filter) { - return collectPlayers(server.playerManager.players, filter); + return collectPlayers(allPlayers(), filter); } private static Iterable collectPlayers(Iterable src, Predicate filter) { @@ -230,40 +395,23 @@ private static Iterable collectPlayers(Iterable writer) { - try { - return new CustomPayloadPacket(channel, DataStreams.output(writer).toByteArray()); - } catch (IOException e) { - LOGGER.warn("error writing custom payload to channel \'" + channel + "\'", e); - return null; - } - } + private static void sendPacket(Iterable players, NamespacedIdentifier channel, byte[] data) { + Packet packet = packetFactory.create(channel, data); - private static Packet makePacket(String channel, byte[] data) { - return new CustomPayloadPacket(channel, data); - } - - private static void sendPacket(ServerPlayerEntity player, Packet packet) { - if (packet != null) { + for (ServerPlayerEntity player : players) { player.networkHandler.sendPacket(packet); } } - private static void sendPacket(Iterable players, Packet packet) { - if (packet != null) { - for (ServerPlayerEntity player : players) { - sendPacket(player, packet); - } - } - } + private interface ChannelListener { - private interface Listener { + boolean isAsync(); - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] data) throws IOException; + boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] bytes) throws IOException; } } diff --git a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/resources/osl.networking.mixins.json b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/resources/osl.networking.mixins.json index 2cfc21d4..f1faf16d 100644 --- a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/resources/osl.networking.mixins.json +++ b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/resources/osl.networking.mixins.json @@ -4,11 +4,13 @@ "package": "net.ornithemc.osl.networking.impl.mixin", "compatibilityLevel": "JAVA_8", "mixins": [ - "common.PacketAccessor" + "common.PacketAccessor", + "common.PacketMixin" ], "client": [ ], "server": [ + "server.MinecraftServerMixin", "server.ServerLoginNetworkHandlerMixin", "server.ServerPlayNetworkHandlerMixin" ], diff --git a/libraries/networking/src/main/java/net/ornithemc/osl/networking/api/ChannelIdentifiers.java b/libraries/networking/src/main/java/net/ornithemc/osl/networking/api/ChannelIdentifiers.java new file mode 100644 index 00000000..55358b7d --- /dev/null +++ b/libraries/networking/src/main/java/net/ornithemc/osl/networking/api/ChannelIdentifiers.java @@ -0,0 +1,108 @@ +package net.ornithemc.osl.networking.api; + +import java.util.Set; +import java.util.stream.Collectors; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.api.util.NamespacedIdentifiers; +import net.ornithemc.osl.core.impl.util.NamespacedIdentifierException; +import net.ornithemc.osl.networking.impl.ChannelIdentifierException; + +/** + * Utility methods for creating and validating channel identifiers. + */ +public final class ChannelIdentifiers { + + /** + * The default namespace of channel identifiers. + * It is recommended to use a custom namespace for your own identifiers. + */ + public static final String DEFAULT_NAMESPACE = NamespacedIdentifiers.DEFAULT_NAMESPACE; + + /** + * The maximum length of a channel identifier's namespace string. + */ + public static final int MAX_LENGTH_NAMESPACE = Byte.MAX_VALUE; + /** + * The maximum length of a channel identifier's identifier string. + */ + public static final int MAX_LENGTH_IDENTIFIER = Byte.MAX_VALUE; + + /** + * Construct and validate a channel identifier with the default namespace and the given identifier. + */ + public static NamespacedIdentifier from(String identifier) { + return from(DEFAULT_NAMESPACE, identifier); + } + + /** + * Construct and validate a channel identifier from the given namespace and identifier. + */ + public static NamespacedIdentifier from(String namespace, String identifier) { + return NamespacedIdentifiers.from( + validateNamespace(namespace), + validateIdentifier(identifier) + ); + } + + /** + * Check whether the given channel identifier is valid, or throw an exception. + */ + public static NamespacedIdentifier validate(NamespacedIdentifier id) { + try { + validateNamespace(id.namespace()); + validateIdentifier(id.identifier()); + + return id; + } catch (ChannelIdentifierException e) { + throw ChannelIdentifierException.invalid(id, e); + } + } + + /** + * Check that the given namespace is valid for a channel identifier. + */ + public static String validateNamespace(String namespace) { + if (namespace == null || namespace.isEmpty()) { + throw ChannelIdentifierException.invalidNamespace(namespace, "null or empty"); + } + if (namespace.length() > MAX_LENGTH_NAMESPACE) { + throw ChannelIdentifierException.invalidNamespace(namespace, "length " + namespace.length() + " is greater than maximum allowed " + MAX_LENGTH_NAMESPACE); + } + if (!namespace.chars().allMatch(chr -> chr == '-' || chr == '.' || chr == '_' || (chr >= 'a' && chr <= 'z') || (chr >= '0' && chr <= '9'))) { + throw ChannelIdentifierException.invalidNamespace(namespace, "contains illegal characters - only [a-z0-9-._] are allowed"); + } + + return NamespacedIdentifiers.validateNamespace(namespace); + } + + /** + * Check that the given identifier is valid for a channel identifier. + */ + public static String validateIdentifier(String identifier) { + if (identifier == null || identifier.isEmpty()) { + throw ChannelIdentifierException.invalidIdentifier(identifier, "null or empty"); + } + if (identifier.length() > MAX_LENGTH_IDENTIFIER) { + throw ChannelIdentifierException.invalidIdentifier(identifier, "length " + identifier.length() + " is greater than maximum allowed " + MAX_LENGTH_IDENTIFIER); + } + if (!identifier.chars().allMatch(chr -> chr == '-' || chr == '.' || chr == '_' || chr == '/' || (chr >= 'a' && chr <= 'z') || (chr >= '0' && chr <= '9'))) { + throw ChannelIdentifierException.invalidIdentifier(identifier, "contains illegal characters - only [a-z0-9-._/] are allowed"); + } + + return NamespacedIdentifiers.validateIdentifier(identifier); + } + + public static Set dropInvalid(Set channels) { + return channels + .stream() + .filter(channel -> { + try { + return ChannelIdentifiers.validate(channel) != null; + } catch (ChannelIdentifierException | NamespacedIdentifierException e) { + return false; + } + }) + .collect(Collectors.toSet()); + } +} diff --git a/libraries/networking/src/main/java/net/ornithemc/osl/networking/api/Channels.java b/libraries/networking/src/main/java/net/ornithemc/osl/networking/api/Channels.java deleted file mode 100644 index ec3246a4..00000000 --- a/libraries/networking/src/main/java/net/ornithemc/osl/networking/api/Channels.java +++ /dev/null @@ -1,20 +0,0 @@ -package net.ornithemc.osl.networking.api; - -public class Channels { - - /** - * The maximum String length for a custom payload channel. - */ - public static final int MAX_LENGTH = 20; - - /** - * Check that the given String channel is valid, or throw an exception. - */ - public static String validate(String channel) { - if (channel.length() > MAX_LENGTH) { - throw new RuntimeException("channel \'" + channel + "\' is too long (length " + channel.length() + "/allowed " + MAX_LENGTH + ")"); - } - - return channel; - } -} diff --git a/libraries/networking/src/main/java/net/ornithemc/osl/networking/api/StringChannelIdentifierParser.java b/libraries/networking/src/main/java/net/ornithemc/osl/networking/api/StringChannelIdentifierParser.java new file mode 100644 index 00000000..a795afc5 --- /dev/null +++ b/libraries/networking/src/main/java/net/ornithemc/osl/networking/api/StringChannelIdentifierParser.java @@ -0,0 +1,71 @@ +package net.ornithemc.osl.networking.api; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.core.impl.util.NamespacedIdentifierImpl; +import net.ornithemc.osl.networking.impl.ChannelIdentifierException; +import net.ornithemc.osl.networking.impl.ChannelIdentifierParseException; + +/** + * Utility methods for converting channel identifiers from and to {@link String}s. + */ +public final class StringChannelIdentifierParser { + + /** + * The maximum allowed length for the {@code String} representation of a channel identifier. + */ + public static final int MAX_LENGTH = ChannelIdentifiers.MAX_LENGTH_NAMESPACE + 1 + ChannelIdentifiers.MAX_LENGTH_IDENTIFIER; + + /** + * Convert the given {@code String} to a channel identifier. + * The returned identifier may be invalid. + * + * @return the channel identifier represented by the {@code String}, + * which may or may not be a valid identifier. + */ + public static NamespacedIdentifier fromString(String s) { + int i = s.indexOf('|'); + + if (i < 1) { + // allow null namespaces to support channel ids that do not conform + // to OSL spec - MC did not enforce a strict spec before 1.13 + return new NamespacedIdentifierImpl(null, s); + } else { + return new NamespacedIdentifierImpl(s.substring(0, i), s.substring(i + 1)); + } + } + + /** + * Convert the given {@code String} to a channel identifier. + * The returned channel identifier is always valid. If no valid channel + * identifier can be parsed from the given string, an exception is + * thrown. + * + * @return the channel identifier represented by the {@code String}. + * @throws ChannelIdentifierParseException + * if no valid channel identifier can be parsed from the given {@code String}. + */ + public static NamespacedIdentifier fromStringOrThrow(String s) { + int i = s.indexOf('|'); + + try { + if (i < 0) { + return ChannelIdentifiers.from(s); + } else if (i > 0) { + return ChannelIdentifiers.from(s.substring(0, i), s.substring(i + 1)); + } else { + throw ChannelIdentifierParseException.invalid(s, "badly formatted"); + } + } catch (ChannelIdentifierException e) { + throw ChannelIdentifierParseException.invalid(s, e); + } + } + + /** + * Convert the given {@code NamespacedIdentifier} to its {@code String} representation. + */ + public static String toString(NamespacedIdentifier id) { + return id.namespace() == null + ? id.identifier() + : id.namespace() + "|" + id.identifier(); + } +} diff --git a/libraries/networking/src/main/java/net/ornithemc/osl/networking/impl/ChannelIdentifierException.java b/libraries/networking/src/main/java/net/ornithemc/osl/networking/impl/ChannelIdentifierException.java new file mode 100644 index 00000000..aef3307c --- /dev/null +++ b/libraries/networking/src/main/java/net/ornithemc/osl/networking/impl/ChannelIdentifierException.java @@ -0,0 +1,31 @@ +package net.ornithemc.osl.networking.impl; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; + +@SuppressWarnings("serial") +public class ChannelIdentifierException extends RuntimeException { + + private ChannelIdentifierException(String message) { + super(message); + } + + private ChannelIdentifierException(String message, Throwable cause) { + super(message, cause); + } + + public static ChannelIdentifierException invalid(NamespacedIdentifier id, Throwable cause) { + return new ChannelIdentifierException("\'" + id + "\' is not a valid channel identifier", cause); + } + + public static ChannelIdentifierException invalid(NamespacedIdentifier id, String reason) { + return new ChannelIdentifierException("\'" + id + "\' is not a valid channel identifier: " + reason); + } + + public static ChannelIdentifierException invalidNamespace(String namespace, String reason) { + return new ChannelIdentifierException("\'" + namespace + "\' is not a valid namespace: " + reason); + } + + public static ChannelIdentifierException invalidIdentifier(String identifier, String reason) { + return new ChannelIdentifierException("\'" + identifier + "\' is not a valid identifier: " + reason); + } +} diff --git a/libraries/networking/src/main/java/net/ornithemc/osl/networking/impl/ChannelIdentifierParseException.java b/libraries/networking/src/main/java/net/ornithemc/osl/networking/impl/ChannelIdentifierParseException.java new file mode 100644 index 00000000..4566ca55 --- /dev/null +++ b/libraries/networking/src/main/java/net/ornithemc/osl/networking/impl/ChannelIdentifierParseException.java @@ -0,0 +1,21 @@ +package net.ornithemc.osl.networking.impl; + +@SuppressWarnings("serial") +public class ChannelIdentifierParseException extends RuntimeException { + + private ChannelIdentifierParseException(String message) { + super(message); + } + + private ChannelIdentifierParseException(String message, Throwable cause) { + super(message, cause); + } + + public static ChannelIdentifierParseException invalid(String id, Throwable cause) { + return new ChannelIdentifierParseException("unable to parse channel identifier from \'" + id + "\'", cause); + } + + public static ChannelIdentifierParseException invalid(String id, String reason) { + return new ChannelIdentifierParseException("unable to parse channel identifier from \'" + id + "\': " + reason); + } +} diff --git a/libraries/networking/src/main/java/net/ornithemc/osl/networking/impl/Constants.java b/libraries/networking/src/main/java/net/ornithemc/osl/networking/impl/Constants.java index 7d75b887..5ae8b598 100644 --- a/libraries/networking/src/main/java/net/ornithemc/osl/networking/impl/Constants.java +++ b/libraries/networking/src/main/java/net/ornithemc/osl/networking/impl/Constants.java @@ -1,6 +1,9 @@ package net.ornithemc.osl.networking.impl; -public class Constants { +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.api.ChannelIdentifiers; + +public final class Constants { /** * The packet id for custom payloads, matches that @@ -12,5 +15,14 @@ public class Constants { * It needs to be an invalid Minecraft username. */ public static final String OSL_HANDSHAKE_KEY = "\0OrnitheMC"; + /** + * A number that describes the OSL handshake protocol, in case + * the data that is sent is expanded, reduced, or reorganized. + */ + public static final byte OSL_HANDSHAKE_PROTOCOL = 1; + /** + * The channel identifier for OSL's handshake payload. + */ + public static final NamespacedIdentifier OSL_HANDSHAKE_CHANNEL = ChannelIdentifiers.from("osl", "handshake"); } diff --git a/libraries/networking/src/main/resources/fabric.mod.json b/libraries/networking/src/main/resources/fabric.mod.json index 16417e6f..7652b91d 100644 --- a/libraries/networking/src/main/resources/fabric.mod.json +++ b/libraries/networking/src/main/resources/fabric.mod.json @@ -17,18 +17,8 @@ "icon": "assets/ornithe-standard-libraries/networking/icon.png", "environment": "${environment}", "entrypoints": { - "init": [ - "net.ornithemc.osl.networking.impl.Networking" - ], - "client-init": [ - "net.ornithemc.osl.networking.impl.Networking" - ], - "server-init": [ - "net.ornithemc.osl.networking.impl.Networking" - ] }, "mixins": [ - "osl.networking.mixins.json" ], "depends": { "fabricloader": ">=0.16.0", diff --git a/settings.gradle b/settings.gradle index 41a7d367..f28aa83d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -62,20 +62,28 @@ include ':libraries:lifecycle-events:lifecycle-events-mc19w04a-mc1.14.4' include ':libraries:networking' include ':libraries:networking:networking-mca1.0.16-mca1.2.6' -include ':libraries:networking:networking-mcserver-a0.1.2_01-mcserver-a0.2.1' +include ':libraries:networking:networking-mcserver-a0.1.0-mcserver-a0.2.1' include ':libraries:networking:networking-mcserver-a0.2.2-mcserver-a0.2.8' -include ':libraries:networking:networking-mcb1.0-mcb1.4_01' -include ':libraries:networking:networking-mcb1.5-mc11w48a' -include ':libraries:networking:networking-mc11w49a-mc12w16a' -include ':libraries:networking:networking-mc12w17a-mc12w17a' -include ':libraries:networking:networking-mc12w18a-mc12w19a' -include ':libraries:networking:networking-mc12w21a-mc13w39b' -include ':libraries:networking:networking-mc13w41a-mc14w20b' -include ':libraries:networking:networking-mc14w21a-mc14w30c' -include ':libraries:networking:networking-mc14w31a-mc1.13-pre2' -include ':libraries:networking:networking-mc1.13-pre4-mc18w30b' +include ':libraries:networking:networking-mcb1.0-mc13w39b' +include ':libraries:networking:networking-mc13w41a-mc18w30b' include ':libraries:networking:networking-mc18w31a-mc1.14.4' +include ':libraries:networking-impl' +include ':libraries:networking-impl:networking-impl-mca1.0.16-mca1.2.6' +include ':libraries:networking-impl:networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8' +include ':libraries:networking-impl:networking-impl-mcb1.0-mcb1.4_01' +include ':libraries:networking-impl:networking-impl-mcb1.5-mc11w48a' +include ':libraries:networking-impl:networking-impl-mc11w49a-mc12w16a' +include ':libraries:networking-impl:networking-impl-mc12w17a-mc12w17a' +include ':libraries:networking-impl:networking-impl-mc12w18a-mc12w19a' +include ':libraries:networking-impl:networking-impl-mc12w21a-mc13w39b' +include ':libraries:networking-impl:networking-impl-mc13w41a-mc14w20b' +include ':libraries:networking-impl:networking-impl-mc14w21a-mc14w30c' +include ':libraries:networking-impl:networking-impl-mc14w31a-mc1.13-pre2' +include ':libraries:networking-impl:networking-impl-mc1.13-pre3-mc1.13-pre3' +include ':libraries:networking-impl:networking-impl-mc1.13-pre4-mc1.13.2' +include ':libraries:networking-impl:networking-impl-mc18w43a-mc1.14.4' + include ':libraries:resource-loader' include ':libraries:resource-loader:resource-loader-mca1.2.2-1624-mc11w48a' include ':libraries:resource-loader:resource-loader-mc11w49a-mc1.2.5' From f4d32ece8a8ec8ef070dd2aa9105a70e4023211e Mon Sep 17 00:00:00 2001 From: Space Walker Date: Sun, 7 Dec 2025 16:26:38 +0100 Subject: [PATCH 5/8] implement listener context and simplify listener registration --- .../osl/networking/impl/Networking.java | 18 ++- .../osl/networking/impl/Networking.java | 18 ++- .../osl/networking/impl/Networking.java | 18 ++- .../osl/networking/impl/Networking.java | 18 ++- .../osl/networking/impl/Networking.java | 18 ++- .../osl/networking/impl/Networking.java | 18 ++- .../osl/networking/impl/Networking.java | 18 ++- .../osl/networking/impl/Networking.java | 18 ++- .../osl/networking/impl/Networking.java | 18 ++- .../osl/networking/impl/Networking.java | 18 ++- .../osl/networking/impl/Networking.java | 8 +- .../osl/networking/impl/Networking.java | 16 +-- .../osl/networking/impl/Networking.java | 16 +-- .../osl/networking/impl/Networking.java | 8 +- .../api/client/ClientPacketListener.java | 31 +++-- .../api/client/ClientPlayNetworking.java | 32 +---- .../api/server/ServerPacketListener.java | 36 ++++-- .../api/server/ServerPlayNetworking.java | 32 +---- .../impl/client/ClientPlayNetworkingImpl.java | 107 ++++++---------- .../impl/server/ServerPlayNetworkingImpl.java | 117 +++++++----------- .../api/client/ClientPacketListener.java | 31 +++-- .../api/client/ClientPlayNetworking.java | 32 +---- .../api/server/ServerPacketListener.java | 36 ++++-- .../api/server/ServerPlayNetworking.java | 32 +---- .../impl/client/ClientPlayNetworkingImpl.java | 107 ++++++---------- .../impl/server/ServerPlayNetworkingImpl.java | 117 +++++++----------- .../api/client/ClientPacketListener.java | 31 +++-- .../api/client/ClientPlayNetworking.java | 32 +---- .../impl/client/ClientPlayNetworkingImpl.java | 107 ++++++---------- .../api/client/ClientPacketListener.java | 31 +++-- .../api/client/ClientPlayNetworking.java | 32 +---- .../api/server/ServerPacketListener.java | 36 ++++-- .../api/server/ServerPlayNetworking.java | 32 +---- .../impl/client/ClientPlayNetworkingImpl.java | 107 ++++++---------- .../impl/server/ServerPlayNetworkingImpl.java | 117 +++++++----------- .../api/server/ServerPacketListener.java | 36 ++++-- .../api/server/ServerPlayNetworking.java | 32 +---- .../impl/server/ServerPlayNetworkingImpl.java | 117 +++++++----------- .../api/server/ServerPacketListener.java | 36 ++++-- .../api/server/ServerPlayNetworking.java | 32 +---- .../impl/server/ServerPlayNetworkingImpl.java | 117 +++++++----------- .../impl/NotOnMainThreadException.java | 11 ++ 42 files changed, 741 insertions(+), 1103 deletions(-) create mode 100644 libraries/networking/src/main/java/net/ornithemc/osl/networking/impl/NotOnMainThreadException.java diff --git a/libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/java/net/ornithemc/osl/networking/impl/Networking.java index be65ff90..6748a0b3 100644 --- a/libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/java/net/ornithemc/osl/networking/impl/Networking.java +++ b/libraries/networking-impl/networking-impl-mc1.13-pre3-mc1.13-pre3/src/main/java/net/ornithemc/osl/networking/impl/Networking.java @@ -25,14 +25,12 @@ public void init() { MinecraftServerEvents.STOP.register(ServerPlayNetworkingImpl::destroy); ServerPlayNetworkingImpl.setUpPacketFactory((channel, data) -> new CustomPayloadS2CPacket(IdentifierChannelIdentifierParser.toIdentifier(channel), PacketBuffers.unwrapped(data))); - ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { + ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (context, payload) -> { // send channel registration data as a response to receiving client channel registration data - ServerPlayNetworkingImpl.sendNoCheck(player, HandshakePayload.CHANNEL, HandshakePayload.server()); + ServerPlayNetworkingImpl.sendNoCheck(context.player(), HandshakePayload.CHANNEL, HandshakePayload.server()); - ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); - ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); - - return true; + ((NetworkHandlerAccess)context.networkHandler()).osl$networking$registerChannels(payload.channels); + ServerConnectionEvents.PLAY_READY.invoker().accept(context.server(), context.player()); }); } @@ -42,11 +40,9 @@ public void initClient() { MinecraftClientEvents.STOP.register(ClientPlayNetworkingImpl::destroy); ClientPlayNetworkingImpl.setUpPacketFactory((channel, data) -> new CustomPayloadC2SPacket(StringChannelIdentifierParser.toString(channel), PacketBuffers.unwrapped(data))); - ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { - ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); - ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); - - return true; + ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (context, payload) -> { + ((NetworkHandlerAccess)context.networkHandler()).osl$networking$registerChannels(payload.channels); + ClientConnectionEvents.PLAY_READY.invoker().accept(context.minecraft()); }); } diff --git a/libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/java/net/ornithemc/osl/networking/impl/Networking.java index 431eefe5..2785b5e8 100644 --- a/libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/java/net/ornithemc/osl/networking/impl/Networking.java +++ b/libraries/networking-impl/networking-impl-mc1.13-pre4-mc1.13.2/src/main/java/net/ornithemc/osl/networking/impl/Networking.java @@ -24,14 +24,12 @@ public void init() { MinecraftServerEvents.STOP.register(ServerPlayNetworkingImpl::destroy); ServerPlayNetworkingImpl.setUpPacketFactory((channel, data) -> new CustomPayloadS2CPacket(IdentifierChannelIdentifierParser.toIdentifier(channel), PacketBuffers.unwrapped(data))); - ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { + ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (context, payload) -> { // send channel registration data as a response to receiving client channel registration data - ServerPlayNetworkingImpl.sendNoCheck(player, HandshakePayload.CHANNEL, HandshakePayload.server()); + ServerPlayNetworkingImpl.sendNoCheck(context.player(), HandshakePayload.CHANNEL, HandshakePayload.server()); - ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); - ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); - - return true; + ((NetworkHandlerAccess)context.networkHandler()).osl$networking$registerChannels(payload.channels); + ServerConnectionEvents.PLAY_READY.invoker().accept(context.server(), context.player()); }); } @@ -41,11 +39,9 @@ public void initClient() { MinecraftClientEvents.STOP.register(ClientPlayNetworkingImpl::destroy); ClientPlayNetworkingImpl.setUpPacketFactory((channel, data) -> new CustomPayloadC2SPacket(IdentifierChannelIdentifierParser.toIdentifier(channel), PacketBuffers.unwrapped(data))); - ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { - ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); - ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); - - return true; + ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (context, payload) -> { + ((NetworkHandlerAccess)context.networkHandler()).osl$networking$registerChannels(payload.channels); + ClientConnectionEvents.PLAY_READY.invoker().accept(context.minecraft()); }); } diff --git a/libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java index 265638db..08410b9e 100644 --- a/libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java +++ b/libraries/networking-impl/networking-impl-mc11w49a-mc12w16a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java @@ -26,11 +26,9 @@ public void initClient() { MinecraftClientEvents.START.register(ClientPlayNetworkingImpl::setUp); MinecraftClientEvents.STOP.register(ClientPlayNetworkingImpl::destroy); ClientPlayNetworkingImpl.setUpPacketFactory(Networking::newCustomPayloadPacket); - ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { - ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); - ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); - - return true; + ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (context, payload) -> { + ((NetworkHandlerAccess)context.networkHandler()).osl$networking$registerChannels(payload.channels); + ClientConnectionEvents.PLAY_READY.invoker().accept(context.minecraft()); }); } @@ -39,14 +37,12 @@ public void initServer() { MinecraftServerEvents.START.register(ServerPlayNetworkingImpl::setUp); MinecraftServerEvents.STOP.register(ServerPlayNetworkingImpl::destroy); ServerPlayNetworkingImpl.setUpPacketFactory(Networking::newCustomPayloadPacket); - ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { + ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (context, payload) -> { // send channel registration data as a response to receiving client channel registration data - ServerPlayNetworkingImpl.sendNoCheck(player, HandshakePayload.CHANNEL, HandshakePayload.server()); - - ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); - ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); + ServerPlayNetworkingImpl.sendNoCheck(context.player(), HandshakePayload.CHANNEL, HandshakePayload.server()); - return true; + ((NetworkHandlerAccess)context.networkHandler()).osl$networking$registerChannels(payload.channels); + ServerConnectionEvents.PLAY_READY.invoker().accept(context.server(), context.player()); }); } diff --git a/libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java index 74d7452d..12ba9d51 100644 --- a/libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java +++ b/libraries/networking-impl/networking-impl-mc12w17a-mc12w17a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java @@ -27,11 +27,9 @@ public void initClient() { MinecraftClientEvents.START.register(ClientPlayNetworkingImpl::setUp); MinecraftClientEvents.STOP.register(ClientPlayNetworkingImpl::destroy); ClientPlayNetworkingImpl.setUpPacketFactory(Networking::newCustomPayloadPacket); - ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { - ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); - ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); - - return true; + ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (context, payload) -> { + ((NetworkHandlerAccess)context.networkHandler()).osl$networking$registerChannels(payload.channels); + ClientConnectionEvents.PLAY_READY.invoker().accept(context.minecraft()); }); } @@ -40,14 +38,12 @@ public void initServer() { MinecraftServerEvents.START.register(ServerPlayNetworkingImpl::setUp); MinecraftServerEvents.STOP.register(ServerPlayNetworkingImpl::destroy); ServerPlayNetworkingImpl.setUpPacketFactory(Networking::newCustomPayloadPacket); - ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { + ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (context, payload) -> { // send channel registration data as a response to receiving client channel registration data - ServerPlayNetworkingImpl.sendNoCheck(player, HandshakePayload.CHANNEL, HandshakePayload.server()); - - ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); - ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); + ServerPlayNetworkingImpl.sendNoCheck(context.player(), HandshakePayload.CHANNEL, HandshakePayload.server()); - return true; + ((NetworkHandlerAccess)context.networkHandler()).osl$networking$registerChannels(payload.channels); + ServerConnectionEvents.PLAY_READY.invoker().accept(context.server(), context.player()); }); } diff --git a/libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java index e2f5e0b5..f97e0a06 100644 --- a/libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java +++ b/libraries/networking-impl/networking-impl-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java @@ -22,14 +22,12 @@ public void init() { MinecraftServerEvents.START.register(ServerPlayNetworkingImpl::setUp); MinecraftServerEvents.STOP.register(ServerPlayNetworkingImpl::destroy); ServerPlayNetworkingImpl.setUpPacketFactory(Networking::newCustomPayloadPacket); - ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { + ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (context, payload) -> { // send channel registration data as a response to receiving client channel registration data - ServerPlayNetworkingImpl.sendNoCheck(player, HandshakePayload.CHANNEL, HandshakePayload.server()); + ServerPlayNetworkingImpl.sendNoCheck(context.player(), HandshakePayload.CHANNEL, HandshakePayload.server()); - ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); - ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); - - return true; + ((NetworkHandlerAccess)context.networkHandler()).osl$networking$registerChannels(payload.channels); + ServerConnectionEvents.PLAY_READY.invoker().accept(context.server(), context.player()); }); } @@ -38,11 +36,9 @@ public void initClient() { MinecraftClientEvents.START.register(ClientPlayNetworkingImpl::setUp); MinecraftClientEvents.STOP.register(ClientPlayNetworkingImpl::destroy); ClientPlayNetworkingImpl.setUpPacketFactory(Networking::newCustomPayloadPacket); - ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { - ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); - ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); - - return true; + ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (context, payload) -> { + ((NetworkHandlerAccess)context.networkHandler()).osl$networking$registerChannels(payload.channels); + ClientConnectionEvents.PLAY_READY.invoker().accept(context.minecraft()); }); } diff --git a/libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/Networking.java index e2f5e0b5..f97e0a06 100644 --- a/libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/Networking.java +++ b/libraries/networking-impl/networking-impl-mc12w21a-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/Networking.java @@ -22,14 +22,12 @@ public void init() { MinecraftServerEvents.START.register(ServerPlayNetworkingImpl::setUp); MinecraftServerEvents.STOP.register(ServerPlayNetworkingImpl::destroy); ServerPlayNetworkingImpl.setUpPacketFactory(Networking::newCustomPayloadPacket); - ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { + ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (context, payload) -> { // send channel registration data as a response to receiving client channel registration data - ServerPlayNetworkingImpl.sendNoCheck(player, HandshakePayload.CHANNEL, HandshakePayload.server()); + ServerPlayNetworkingImpl.sendNoCheck(context.player(), HandshakePayload.CHANNEL, HandshakePayload.server()); - ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); - ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); - - return true; + ((NetworkHandlerAccess)context.networkHandler()).osl$networking$registerChannels(payload.channels); + ServerConnectionEvents.PLAY_READY.invoker().accept(context.server(), context.player()); }); } @@ -38,11 +36,9 @@ public void initClient() { MinecraftClientEvents.START.register(ClientPlayNetworkingImpl::setUp); MinecraftClientEvents.STOP.register(ClientPlayNetworkingImpl::destroy); ClientPlayNetworkingImpl.setUpPacketFactory(Networking::newCustomPayloadPacket); - ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { - ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); - ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); - - return true; + ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (context, payload) -> { + ((NetworkHandlerAccess)context.networkHandler()).osl$networking$registerChannels(payload.channels); + ClientConnectionEvents.PLAY_READY.invoker().accept(context.minecraft()); }); } diff --git a/libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/Networking.java index 4d06185a..10f44a33 100644 --- a/libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/Networking.java +++ b/libraries/networking-impl/networking-impl-mc13w41a-mc14w20b/src/main/java/net/ornithemc/osl/networking/impl/Networking.java @@ -24,14 +24,12 @@ public void init() { MinecraftServerEvents.STOP.register(ServerPlayNetworkingImpl::destroy); ServerPlayNetworkingImpl.setUpPacketFactory((channel, data) -> new CustomPayloadS2CPacket(StringChannelIdentifierParser.toString(channel), PacketBuffers.unwrapped(data))); - ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { + ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (context, payload) -> { // send channel registration data as a response to receiving client channel registration data - ServerPlayNetworkingImpl.sendNoCheck(player, HandshakePayload.CHANNEL, HandshakePayload.server()); + ServerPlayNetworkingImpl.sendNoCheck(context.player(), HandshakePayload.CHANNEL, HandshakePayload.server()); - ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); - ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); - - return true; + ((NetworkHandlerAccess)context.networkHandler()).osl$networking$registerChannels(payload.channels); + ServerConnectionEvents.PLAY_READY.invoker().accept(context.server(), context.player()); }); } @@ -41,11 +39,9 @@ public void initClient() { MinecraftClientEvents.STOP.register(ClientPlayNetworkingImpl::destroy); ClientPlayNetworkingImpl.setUpPacketFactory((channel, data) -> new CustomPayloadC2SPacket(StringChannelIdentifierParser.toString(channel), PacketBuffers.unwrapped(data))); - ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { - ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); - ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); - - return true; + ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (context, payload) -> { + ((NetworkHandlerAccess)context.networkHandler()).osl$networking$registerChannels(payload.channels); + ClientConnectionEvents.PLAY_READY.invoker().accept(context.minecraft()); }); } diff --git a/libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/Networking.java index 4d06185a..10f44a33 100644 --- a/libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/Networking.java +++ b/libraries/networking-impl/networking-impl-mc14w21a-mc14w30c/src/main/java/net/ornithemc/osl/networking/impl/Networking.java @@ -24,14 +24,12 @@ public void init() { MinecraftServerEvents.STOP.register(ServerPlayNetworkingImpl::destroy); ServerPlayNetworkingImpl.setUpPacketFactory((channel, data) -> new CustomPayloadS2CPacket(StringChannelIdentifierParser.toString(channel), PacketBuffers.unwrapped(data))); - ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { + ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (context, payload) -> { // send channel registration data as a response to receiving client channel registration data - ServerPlayNetworkingImpl.sendNoCheck(player, HandshakePayload.CHANNEL, HandshakePayload.server()); + ServerPlayNetworkingImpl.sendNoCheck(context.player(), HandshakePayload.CHANNEL, HandshakePayload.server()); - ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); - ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); - - return true; + ((NetworkHandlerAccess)context.networkHandler()).osl$networking$registerChannels(payload.channels); + ServerConnectionEvents.PLAY_READY.invoker().accept(context.server(), context.player()); }); } @@ -41,11 +39,9 @@ public void initClient() { MinecraftClientEvents.STOP.register(ClientPlayNetworkingImpl::destroy); ClientPlayNetworkingImpl.setUpPacketFactory((channel, data) -> new CustomPayloadC2SPacket(StringChannelIdentifierParser.toString(channel), PacketBuffers.unwrapped(data))); - ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { - ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); - ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); - - return true; + ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (context, payload) -> { + ((NetworkHandlerAccess)context.networkHandler()).osl$networking$registerChannels(payload.channels); + ClientConnectionEvents.PLAY_READY.invoker().accept(context.minecraft()); }); } diff --git a/libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/Networking.java index 4d06185a..10f44a33 100644 --- a/libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/Networking.java +++ b/libraries/networking-impl/networking-impl-mc14w31a-mc1.13-pre2/src/main/java/net/ornithemc/osl/networking/impl/Networking.java @@ -24,14 +24,12 @@ public void init() { MinecraftServerEvents.STOP.register(ServerPlayNetworkingImpl::destroy); ServerPlayNetworkingImpl.setUpPacketFactory((channel, data) -> new CustomPayloadS2CPacket(StringChannelIdentifierParser.toString(channel), PacketBuffers.unwrapped(data))); - ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { + ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (context, payload) -> { // send channel registration data as a response to receiving client channel registration data - ServerPlayNetworkingImpl.sendNoCheck(player, HandshakePayload.CHANNEL, HandshakePayload.server()); + ServerPlayNetworkingImpl.sendNoCheck(context.player(), HandshakePayload.CHANNEL, HandshakePayload.server()); - ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); - ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); - - return true; + ((NetworkHandlerAccess)context.networkHandler()).osl$networking$registerChannels(payload.channels); + ServerConnectionEvents.PLAY_READY.invoker().accept(context.server(), context.player()); }); } @@ -41,11 +39,9 @@ public void initClient() { MinecraftClientEvents.STOP.register(ClientPlayNetworkingImpl::destroy); ClientPlayNetworkingImpl.setUpPacketFactory((channel, data) -> new CustomPayloadC2SPacket(StringChannelIdentifierParser.toString(channel), PacketBuffers.unwrapped(data))); - ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { - ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); - ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); - - return true; + ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (context, payload) -> { + ((NetworkHandlerAccess)context.networkHandler()).osl$networking$registerChannels(payload.channels); + ClientConnectionEvents.PLAY_READY.invoker().accept(context.minecraft()); }); } diff --git a/libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/Networking.java index 431eefe5..2785b5e8 100644 --- a/libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/Networking.java +++ b/libraries/networking-impl/networking-impl-mc18w43a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/Networking.java @@ -24,14 +24,12 @@ public void init() { MinecraftServerEvents.STOP.register(ServerPlayNetworkingImpl::destroy); ServerPlayNetworkingImpl.setUpPacketFactory((channel, data) -> new CustomPayloadS2CPacket(IdentifierChannelIdentifierParser.toIdentifier(channel), PacketBuffers.unwrapped(data))); - ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { + ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (context, payload) -> { // send channel registration data as a response to receiving client channel registration data - ServerPlayNetworkingImpl.sendNoCheck(player, HandshakePayload.CHANNEL, HandshakePayload.server()); + ServerPlayNetworkingImpl.sendNoCheck(context.player(), HandshakePayload.CHANNEL, HandshakePayload.server()); - ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); - ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); - - return true; + ((NetworkHandlerAccess)context.networkHandler()).osl$networking$registerChannels(payload.channels); + ServerConnectionEvents.PLAY_READY.invoker().accept(context.server(), context.player()); }); } @@ -41,11 +39,9 @@ public void initClient() { MinecraftClientEvents.STOP.register(ClientPlayNetworkingImpl::destroy); ClientPlayNetworkingImpl.setUpPacketFactory((channel, data) -> new CustomPayloadC2SPacket(IdentifierChannelIdentifierParser.toIdentifier(channel), PacketBuffers.unwrapped(data))); - ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { - ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); - ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); - - return true; + ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (context, payload) -> { + ((NetworkHandlerAccess)context.networkHandler()).osl$networking$registerChannels(payload.channels); + ClientConnectionEvents.PLAY_READY.invoker().accept(context.minecraft()); }); } diff --git a/libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/Networking.java index 009d2d35..191575c6 100644 --- a/libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/Networking.java +++ b/libraries/networking-impl/networking-impl-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/Networking.java @@ -20,14 +20,12 @@ public void initClient() { MinecraftClientEvents.START.register(ClientPlayNetworkingImpl::setUp); MinecraftClientEvents.STOP.register(ClientPlayNetworkingImpl::destroy); ClientPlayNetworkingImpl.setUpPacketFactory(CustomPayloadPacket::new); - ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { + ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (context, payload) -> { // send channel registration data as a response to receiving server channel registration data ClientPlayNetworkingImpl.sendNoCheck(HandshakePayload.CHANNEL, HandshakePayload.client()); - ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); - ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); - - return true; + ((NetworkHandlerAccess)context.networkHandler()).osl$networking$registerChannels(payload.channels); + ClientConnectionEvents.PLAY_READY.invoker().accept(context.minecraft()); }); } diff --git a/libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/Networking.java index 9c28c416..296d88d0 100644 --- a/libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/Networking.java +++ b/libraries/networking-impl/networking-impl-mcb1.0-mcb1.4_01/src/main/java/net/ornithemc/osl/networking/impl/Networking.java @@ -23,14 +23,12 @@ public void initClient() { MinecraftClientEvents.START.register(ClientPlayNetworkingImpl::setUp); MinecraftClientEvents.STOP.register(ClientPlayNetworkingImpl::destroy); ClientPlayNetworkingImpl.setUpPacketFactory(CustomPayloadPacket::new); - ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { + ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (context, payload) -> { // send channel registration data as a response to receiving server channel registration data ClientPlayNetworkingImpl.sendNoCheck(HandshakePayload.CHANNEL, HandshakePayload.client()); - ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); - ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); - - return true; + ((NetworkHandlerAccess)context.networkHandler()).osl$networking$registerChannels(payload.channels); + ClientConnectionEvents.PLAY_READY.invoker().accept(context.minecraft()); }); } @@ -39,11 +37,9 @@ public void initServer() { MinecraftServerEvents.START.register(ServerPlayNetworkingImpl::setUp); MinecraftServerEvents.STOP.register(ServerPlayNetworkingImpl::destroy); ServerPlayNetworkingImpl.setUpPacketFactory(CustomPayloadPacket::new); - ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { - ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); - ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); - - return true; + ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (context, payload) -> { + ((NetworkHandlerAccess)context.networkHandler()).osl$networking$registerChannels(payload.channels); + ServerConnectionEvents.PLAY_READY.invoker().accept(context.server(), context.player()); }); } } diff --git a/libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java index 9c28c416..296d88d0 100644 --- a/libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java +++ b/libraries/networking-impl/networking-impl-mcb1.5-mc11w48a/src/main/java/net/ornithemc/osl/networking/impl/Networking.java @@ -23,14 +23,12 @@ public void initClient() { MinecraftClientEvents.START.register(ClientPlayNetworkingImpl::setUp); MinecraftClientEvents.STOP.register(ClientPlayNetworkingImpl::destroy); ClientPlayNetworkingImpl.setUpPacketFactory(CustomPayloadPacket::new); - ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (minecraft, handler, payload) -> { + ClientPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (context, payload) -> { // send channel registration data as a response to receiving server channel registration data ClientPlayNetworkingImpl.sendNoCheck(HandshakePayload.CHANNEL, HandshakePayload.client()); - ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); - ClientConnectionEvents.PLAY_READY.invoker().accept(minecraft); - - return true; + ((NetworkHandlerAccess)context.networkHandler()).osl$networking$registerChannels(payload.channels); + ClientConnectionEvents.PLAY_READY.invoker().accept(context.minecraft()); }); } @@ -39,11 +37,9 @@ public void initServer() { MinecraftServerEvents.START.register(ServerPlayNetworkingImpl::setUp); MinecraftServerEvents.STOP.register(ServerPlayNetworkingImpl::destroy); ServerPlayNetworkingImpl.setUpPacketFactory(CustomPayloadPacket::new); - ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { - ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); - ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); - - return true; + ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (context, payload) -> { + ((NetworkHandlerAccess)context.networkHandler()).osl$networking$registerChannels(payload.channels); + ServerConnectionEvents.PLAY_READY.invoker().accept(context.server(), context.player()); }); } } diff --git a/libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/Networking.java b/libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/Networking.java index 5fdd6a7e..5875b287 100644 --- a/libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/Networking.java +++ b/libraries/networking-impl/networking-impl-mcserver-a0.1.2_01-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/Networking.java @@ -25,11 +25,9 @@ public void initServer() { MinecraftServerEvents.START.register(ServerPlayNetworkingImpl::setUp); MinecraftServerEvents.STOP.register(ServerPlayNetworkingImpl::destroy); ServerPlayNetworkingImpl.setUpPacketFactory(CustomPayloadPacket::new); - ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (server, handler, player, payload) -> { - ((NetworkHandlerAccess)handler).osl$networking$registerChannels(payload.channels); - ServerConnectionEvents.PLAY_READY.invoker().accept(server, player); - - return true; + ServerPlayNetworkingImpl.registerListener(HandshakePayload.CHANNEL, HandshakePayload::new, (context, payload) -> { + ((NetworkHandlerAccess)context.networkHandler()).osl$networking$registerChannels(payload.channels); + ServerConnectionEvents.PLAY_READY.invoker().accept(context.server(), context.player()); }); } } diff --git a/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPacketListener.java b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPacketListener.java index 1e24b0e4..ddee55ed 100644 --- a/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPacketListener.java +++ b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPacketListener.java @@ -10,22 +10,37 @@ public interface ClientPacketListener { /** * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. */ - boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, T data); + void handle(Context ctx, T data); @FunctionalInterface - public interface Payload extends ClientPacketListener { + interface Payload extends ClientPacketListener { } @FunctionalInterface - public interface Buffer extends ClientPacketListener { + interface Buffer extends ClientPacketListener { } @FunctionalInterface - public interface Bytes extends ClientPacketListener { + interface Bytes extends ClientPacketListener { + } + + interface Context { + + /** + * @return the current Minecraft game instance. + */ + Minecraft minecraft(); + + /** + * @return the network handler that received the packet. + */ + ClientPlayNetworkHandler networkHandler(); + + /** + * Ensure the packet listener is running on the main thread. + */ + void ensureOnMainThread(); + } } diff --git a/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java index 06d6ff52..3b700508 100644 --- a/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java +++ b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java @@ -12,7 +12,7 @@ public final class ClientPlayNetworking { /** * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. + * The data will be deserialized into a {@code CustomPayload} object of the given type. */ public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { ClientPlayNetworkingImpl.registerListener(channel, initializer, listener); @@ -20,15 +20,7 @@ public static void registerListener(NamespacedIdentifi /** * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. - */ - public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { - ClientPlayNetworkingImpl.registerListenerAsync(channel, initializer, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. + * The data will be wrapped in a {@link PacketBuffer} from which it can be read. */ public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { ClientPlayNetworkingImpl.registerListener(channel, listener); @@ -36,28 +28,12 @@ public static void registerListener(NamespacedIdentifier channel, ClientPacketLi /** * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. + * The data will be given as a raw {@code byte[]}. */ - public static void registerListenerAsync(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { - ClientPlayNetworkingImpl.registerListenerAsync(channel, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - */ - public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { + public static void registerLegacyListener(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { ClientPlayNetworkingImpl.registerListener(channel, listener); } - /** - * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. - */ - public static void registerListenerAsync(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { - ClientPlayNetworkingImpl.registerListenerAsync(channel, listener); - } - /** * Remove the listener registered to the given channel. */ diff --git a/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java index fc0a43a7..f64f13bb 100644 --- a/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java +++ b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java @@ -11,22 +11,42 @@ public interface ServerPacketListener { /** * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, T data); + void handle(Context ctx, T data); @FunctionalInterface - public interface Payload extends ServerPacketListener { + interface Payload extends ServerPacketListener { } @FunctionalInterface - public interface Buffer extends ServerPacketListener { + interface Buffer extends ServerPacketListener { } @FunctionalInterface - public interface Bytes extends ServerPacketListener { + interface Bytes extends ServerPacketListener { + } + + interface Context { + + /** + * @return the current MinecraftServer game instance. + */ + MinecraftServer server(); + + /** + * @return the network handler that received the packet. + */ + ServerPlayNetworkHandler networkHandler(); + + /** + * @return the player that received the packet. + */ + ServerPlayerEntity player(); + + /** + * Ensure the packet listener is running on the main thread. + */ + void ensureOnMainThread(); + } } diff --git a/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java index 3df6fc42..88bff1f0 100644 --- a/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java +++ b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java @@ -14,7 +14,7 @@ public final class ServerPlayNetworking { /** * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. + * The data will be deserialized into a {@code CustomPayload} object of the given type. */ public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { ServerPlayNetworkingImpl.registerListener(channel, initializer, listener); @@ -22,15 +22,7 @@ public static void registerListener(NamespacedIdentifi /** * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. - */ - public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { - ServerPlayNetworkingImpl.registerListenerAsync(channel, initializer, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. + * The data will be wrapped in a {@link PacketBuffer} from which it can be read. */ public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { ServerPlayNetworkingImpl.registerListener(channel, listener); @@ -38,28 +30,12 @@ public static void registerListener(NamespacedIdentifier channel, ServerPacketLi /** * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. + * The data will be given as a raw {@code byte[]}. */ - public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { - ServerPlayNetworkingImpl.registerListenerAsync(channel, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - */ - public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { + public static void registerLegacyListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { ServerPlayNetworkingImpl.registerListener(channel, listener); } - /** - * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. - */ - public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { - ServerPlayNetworkingImpl.registerListenerAsync(channel, listener); - } - /** * Remove the listener registered to the given channel. */ diff --git a/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java index 32dd8d57..662e7666 100644 --- a/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java +++ b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java @@ -18,6 +18,7 @@ import net.ornithemc.osl.networking.api.PacketBuffers; import net.ornithemc.osl.networking.api.PacketPayload; import net.ornithemc.osl.networking.api.client.ClientPacketListener; +import net.ornithemc.osl.networking.impl.NotOnMainThreadException; import net.ornithemc.osl.networking.impl.PacketFactory; import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; @@ -63,75 +64,20 @@ public static void destroy(Minecraft minecraft) { public static final Map CHANNEL_LISTENERS = new LinkedHashMap<>(); public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { - registerListener(channel, initializer, listener, false); - } - - public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { - registerListener(channel, initializer, listener, true); - } + registerListenerImpl(channel, (context, buffer) -> { + T payload = initializer.get(); + payload.read(buffer); - private static void registerListener(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener, boolean async) { - registerListenerImpl(channel, new ChannelListener() { - - @Override - public boolean isAsync() { - return async; - } - - @Override - public boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, PacketBuffer buffer) throws IOException { - T payload = initializer.get(); - payload.read(buffer); - - return listener.handle(minecraft, handler, payload); - } + listener.handle(context, payload); }); } public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { - registerListener(channel, listener, false); - } - - public static void registerListenerAsync(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { - registerListener(channel, listener, true); - } - - private static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Buffer listener, boolean async) { - registerListenerImpl(channel, new ChannelListener() { - - @Override - public boolean isAsync() { - return async; - } - - @Override - public boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, PacketBuffer buffer) throws IOException { - return listener.handle(minecraft, handler, buffer); - } - }); + registerListenerImpl(channel, listener::handle); } public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { - registerListener(channel, listener, false); - } - - public static void registerListenerAsync(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { - registerListener(channel, listener, true); - } - - private static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Bytes listener, boolean async) { - registerListenerImpl(channel, new ChannelListener() { - - @Override - public boolean isAsync() { - return async; - } - - @Override - public boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, PacketBuffer buffer) throws IOException { - return listener.handle(minecraft, handler, buffer.readByteArray()); - } - }); + registerListenerImpl(channel, (context, buffer) -> listener.handle(context, buffer.readByteArray())); } private static void registerListenerImpl(NamespacedIdentifier channel, ChannelListener listener) { @@ -157,26 +103,27 @@ public static boolean handlePacket(Minecraft minecraft, ClientPlayNetworkHandler ChannelListener listener = CHANNEL_LISTENERS.get(channel); if (listener != null) { + ChannelListener.Context ctx = new ChannelListener.Context(); PacketBuffer data = p.osl$networking$getData(); - if (Thread.currentThread() == thread || listener.isAsync()) { - return handlePayload(minecraft, handler, listener, channel, data); - } else { - return ((TaskRunnerAccess) minecraft).osl$networking$submit(() -> handlePayload(minecraft, handler, listener, channel, data)); + try { + handlePayload(channel, listener, ctx, data); + } catch (NotOnMainThreadException e) { + ((TaskRunnerAccess) minecraft).osl$networking$submit(() -> handlePayload(channel, listener, ctx, data)); } + + return true; } return false; } - private static boolean handlePayload(Minecraft minecraft, ClientPlayNetworkHandler handler, ChannelListener listener, NamespacedIdentifier channel, PacketBuffer data) { + private static void handlePayload(NamespacedIdentifier channel, ChannelListener listener, ChannelListener.Context ctx, PacketBuffer data) { try { - return listener.handle(minecraft, handler, data); + listener.handle(ctx, data); } catch (IOException e) { LOGGER.warn("error handling custom payload on channel \'" + channel + "\'", e); } - - return true; } public static boolean isPlayReady() { @@ -257,11 +204,29 @@ private static void sendPacket(NamespacedIdentifier channel, PacketBuffer data) minecraft.getNetworkHandler().sendPacket(packetFactory.create(channel, data)); } + @FunctionalInterface private interface ChannelListener { - boolean isAsync(); + void handle(Context context, PacketBuffer buffer) throws IOException; + + class Context implements ClientPacketListener.Context { + + @Override + public Minecraft minecraft() { + return minecraft; + } - boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, PacketBuffer buffer) throws IOException; + @Override + public ClientPlayNetworkHandler networkHandler() { + return minecraft.getNetworkHandler(); + } + @Override + public void ensureOnMainThread() { + if (Thread.currentThread() != thread) { + throw NotOnMainThreadException.INSTANCE; + } + } + } } } diff --git a/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java index 175a9d06..f55fc7c8 100644 --- a/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java +++ b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java @@ -22,6 +22,7 @@ import net.ornithemc.osl.networking.api.PacketBuffers; import net.ornithemc.osl.networking.api.PacketPayload; import net.ornithemc.osl.networking.api.server.ServerPacketListener; +import net.ornithemc.osl.networking.impl.NotOnMainThreadException; import net.ornithemc.osl.networking.impl.PacketFactory; import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; @@ -68,75 +69,20 @@ public static void destroy(MinecraftServer server) { public static final Map CHANNEL_LISTENERS = new LinkedHashMap<>(); public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { - ServerPlayNetworkingImpl.registerListener(channel, initializer, listener, false); - } - - public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { - ServerPlayNetworkingImpl.registerListener(channel, initializer, listener, true); - } - - private static void registerListener(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener, boolean async) { - registerListenerImpl(channel, new ChannelListener() { - - @Override - public boolean isAsync() { - return async; - } + registerListenerImpl(channel, (context, buffer) -> { + T payload = initializer.get(); + payload.read(buffer); - @Override - public boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, PacketBuffer buffer) throws IOException { - T payload = initializer.get(); - payload.read(buffer); - - return listener.handle(server, handler, player, payload); - } + listener.handle(context, payload); }); } public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { - ServerPlayNetworkingImpl.registerListener(channel, listener, false); - } - - public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { - ServerPlayNetworkingImpl.registerListener(channel, listener, true); - } - - private static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Buffer listener, boolean async) { - registerListenerImpl(channel, new ChannelListener() { - - @Override - public boolean isAsync() { - return async; - } - - @Override - public boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, PacketBuffer buffer) throws IOException { - return listener.handle(server, handler, player, buffer); - } - }); + registerListenerImpl(channel, listener::handle); } public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { - ServerPlayNetworkingImpl.registerListener(channel, listener, false); - } - - public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { - ServerPlayNetworkingImpl.registerListener(channel, listener, true); - } - - private static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener, boolean async) { - registerListenerImpl(channel, new ChannelListener() { - - @Override - public boolean isAsync() { - return async; - } - - @Override - public boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, PacketBuffer buffer) throws IOException { - return listener.handle(server, handler, player, buffer.readByteArray()); - } - }); + registerListenerImpl(channel, (context, buffer) -> listener.handle(context, buffer.readByteArray())); } private static void registerListenerImpl(NamespacedIdentifier channel, ChannelListener listener) { @@ -162,26 +108,27 @@ public static boolean handlePacket(MinecraftServer server, ServerPlayNetworkHand ChannelListener listener = CHANNEL_LISTENERS.get(channel); if (listener != null) { + ChannelListener.Context ctx = new ChannelListener.Context(player); PacketBuffer data = p.osl$networking$getData(); - if (Thread.currentThread() == thread || listener.isAsync()) { - return handlePayload(server, handler, player, listener, channel, data); - } else { - return ((TaskRunnerAccess) server).osl$networking$submit(() -> handlePayload(server, handler, player, listener, channel, data)); + try { + handlePayload(channel, listener, ctx, data); + } catch (NotOnMainThreadException e) { + ((TaskRunnerAccess) server).osl$networking$submit(() -> handlePayload(channel, listener, ctx, data)); } + + return true; } return false; } - private static boolean handlePayload(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, ChannelListener listener, NamespacedIdentifier channel, PacketBuffer data) { + private static void handlePayload(NamespacedIdentifier channel, ChannelListener listener, ChannelListener.Context ctx, PacketBuffer data) { try { - return listener.handle(server, handler, player, data); + listener.handle(ctx, data); } catch (IOException e) { LOGGER.warn("error handling custom payload on channel \'" + channel + "\'", e); } - - return true; } public static boolean isPlayReady(ServerPlayerEntity player) { @@ -412,9 +359,37 @@ private static void sendPacket(Iterable players, NamespacedI private interface ChannelListener { - boolean isAsync(); + void handle(Context context, PacketBuffer buffer) throws IOException; + + class Context implements ServerPacketListener.Context { + + private final ServerPlayerEntity player; + + Context(ServerPlayerEntity player) { + this.player = player; + } + + @Override + public MinecraftServer server() { + return server; + } + + @Override + public ServerPlayNetworkHandler networkHandler() { + return player.networkHandler; + } - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, PacketBuffer buffer) throws IOException; + @Override + public ServerPlayerEntity player() { + return player; + } + @Override + public void ensureOnMainThread() { + if (Thread.currentThread() != thread) { + throw NotOnMainThreadException.INSTANCE; + } + } + } } } diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/client/ClientPacketListener.java b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/client/ClientPacketListener.java index 1e24b0e4..ddee55ed 100644 --- a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/client/ClientPacketListener.java +++ b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/client/ClientPacketListener.java @@ -10,22 +10,37 @@ public interface ClientPacketListener { /** * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. */ - boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, T data); + void handle(Context ctx, T data); @FunctionalInterface - public interface Payload extends ClientPacketListener { + interface Payload extends ClientPacketListener { } @FunctionalInterface - public interface Buffer extends ClientPacketListener { + interface Buffer extends ClientPacketListener { } @FunctionalInterface - public interface Bytes extends ClientPacketListener { + interface Bytes extends ClientPacketListener { + } + + interface Context { + + /** + * @return the current Minecraft game instance. + */ + Minecraft minecraft(); + + /** + * @return the network handler that received the packet. + */ + ClientPlayNetworkHandler networkHandler(); + + /** + * Ensure the packet listener is running on the main thread. + */ + void ensureOnMainThread(); + } } diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java index 06d6ff52..3b700508 100644 --- a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java +++ b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java @@ -12,7 +12,7 @@ public final class ClientPlayNetworking { /** * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. + * The data will be deserialized into a {@code CustomPayload} object of the given type. */ public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { ClientPlayNetworkingImpl.registerListener(channel, initializer, listener); @@ -20,15 +20,7 @@ public static void registerListener(NamespacedIdentifi /** * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. - */ - public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { - ClientPlayNetworkingImpl.registerListenerAsync(channel, initializer, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. + * The data will be wrapped in a {@link PacketBuffer} from which it can be read. */ public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { ClientPlayNetworkingImpl.registerListener(channel, listener); @@ -36,28 +28,12 @@ public static void registerListener(NamespacedIdentifier channel, ClientPacketLi /** * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. + * The data will be given as a raw {@code byte[]}. */ - public static void registerListenerAsync(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { - ClientPlayNetworkingImpl.registerListenerAsync(channel, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - */ - public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { + public static void registerLegacyListener(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { ClientPlayNetworkingImpl.registerListener(channel, listener); } - /** - * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. - */ - public static void registerListenerAsync(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { - ClientPlayNetworkingImpl.registerListenerAsync(channel, listener); - } - /** * Remove the listener registered to the given channel. */ diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java index fc0a43a7..f64f13bb 100644 --- a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java +++ b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java @@ -11,22 +11,42 @@ public interface ServerPacketListener { /** * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, T data); + void handle(Context ctx, T data); @FunctionalInterface - public interface Payload extends ServerPacketListener { + interface Payload extends ServerPacketListener { } @FunctionalInterface - public interface Buffer extends ServerPacketListener { + interface Buffer extends ServerPacketListener { } @FunctionalInterface - public interface Bytes extends ServerPacketListener { + interface Bytes extends ServerPacketListener { + } + + interface Context { + + /** + * @return the current MinecraftServer game instance. + */ + MinecraftServer server(); + + /** + * @return the network handler that received the packet. + */ + ServerPlayNetworkHandler networkHandler(); + + /** + * @return the player that received the packet. + */ + ServerPlayerEntity player(); + + /** + * Ensure the packet listener is running on the main thread. + */ + void ensureOnMainThread(); + } } diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java index 34a7821d..d983696d 100644 --- a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java +++ b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java @@ -15,7 +15,7 @@ public final class ServerPlayNetworking { /** * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. + * The data will be deserialized into a {@code CustomPayload} object of the given type. */ public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { ServerPlayNetworkingImpl.registerListener(channel, initializer, listener); @@ -23,15 +23,7 @@ public static void registerListener(NamespacedIdentifi /** * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. - */ - public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { - ServerPlayNetworkingImpl.registerListenerAsync(channel, initializer, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. + * The data will be wrapped in a {@link PacketBuffer} from which it can be read. */ public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { ServerPlayNetworkingImpl.registerListener(channel, listener); @@ -39,28 +31,12 @@ public static void registerListener(NamespacedIdentifier channel, ServerPacketLi /** * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. + * The data will be given as a raw {@code byte[]}. */ - public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { - ServerPlayNetworkingImpl.registerListenerAsync(channel, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - */ - public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { + public static void registerLegacyListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { ServerPlayNetworkingImpl.registerListener(channel, listener); } - /** - * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. - */ - public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { - ServerPlayNetworkingImpl.registerListenerAsync(channel, listener); - } - /** * Remove the listener registered to the given channel. */ diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java index 84d48a2c..e7d037a5 100644 --- a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java +++ b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java @@ -18,6 +18,7 @@ import net.ornithemc.osl.networking.api.PacketBuffers; import net.ornithemc.osl.networking.api.PacketPayload; import net.ornithemc.osl.networking.api.client.ClientPacketListener; +import net.ornithemc.osl.networking.impl.NotOnMainThreadException; import net.ornithemc.osl.networking.impl.PacketFactory; import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; @@ -63,75 +64,20 @@ public static void destroy(Minecraft minecraft) { public static final Map CHANNEL_LISTENERS = new LinkedHashMap<>(); public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { - registerListener(channel, initializer, listener, false); - } - - public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { - registerListener(channel, initializer, listener, true); - } + registerListenerImpl(channel, (context, buffer) -> { + T payload = initializer.get(); + payload.read(buffer); - private static void registerListener(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener, boolean async) { - registerListenerImpl(channel, new ChannelListener() { - - @Override - public boolean isAsync() { - return async; - } - - @Override - public boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, PacketBuffer buffer) throws IOException { - T payload = initializer.get(); - payload.read(buffer); - - return listener.handle(minecraft, handler, payload); - } + listener.handle(context, payload); }); } public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { - registerListener(channel, listener, false); - } - - public static void registerListenerAsync(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { - registerListener(channel, listener, true); - } - - private static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Buffer listener, boolean async) { - registerListenerImpl(channel, new ChannelListener() { - - @Override - public boolean isAsync() { - return async; - } - - @Override - public boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, PacketBuffer buffer) throws IOException { - return listener.handle(minecraft, handler, buffer); - } - }); + registerListenerImpl(channel, listener::handle); } public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { - registerListener(channel, listener, false); - } - - public static void registerListenerAsync(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { - registerListener(channel, listener, true); - } - - private static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Bytes listener, boolean async) { - registerListenerImpl(channel, new ChannelListener() { - - @Override - public boolean isAsync() { - return async; - } - - @Override - public boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, PacketBuffer buffer) throws IOException { - return listener.handle(minecraft, handler, buffer.readByteArray()); - } - }); + registerListenerImpl(channel, (context, buffer) -> listener.handle(context, buffer.readByteArray())); } private static void registerListenerImpl(NamespacedIdentifier channel, ChannelListener listener) { @@ -155,26 +101,27 @@ public static boolean handlePacket(Minecraft minecraft, ClientPlayNetworkHandler ChannelListener listener = CHANNEL_LISTENERS.get(channel); if (listener != null) { + ChannelListener.Context ctx = new ChannelListener.Context(); PacketBuffer data = p.osl$networking$getData(); - if (Thread.currentThread() == thread || listener.isAsync()) { - return handlePayload(minecraft, handler, listener, channel, data); - } else { - return ((TaskRunnerAccess) minecraft).osl$networking$submit(() -> handlePayload(minecraft, handler, listener, channel, data)); + try { + handlePayload(channel, listener, ctx, data); + } catch (NotOnMainThreadException e) { + ((TaskRunnerAccess) minecraft).osl$networking$submit(() -> handlePayload(channel, listener, ctx, data)); } + + return true; } return false; } - private static boolean handlePayload(Minecraft minecraft, ClientPlayNetworkHandler handler, ChannelListener listener, NamespacedIdentifier channel, PacketBuffer data) { + private static void handlePayload(NamespacedIdentifier channel, ChannelListener listener, ChannelListener.Context ctx, PacketBuffer data) { try { - return listener.handle(minecraft, handler, data); + listener.handle(ctx, data); } catch (IOException e) { LOGGER.warn("error handling custom payload on channel \'" + channel + "\'", e); } - - return true; } public static boolean isPlayReady() { @@ -255,11 +202,29 @@ private static void sendPacket(NamespacedIdentifier channel, PacketBuffer data) minecraft.getNetworkHandler().sendPacket(packetFactory.create(channel, data)); } + @FunctionalInterface private interface ChannelListener { - boolean isAsync(); + void handle(Context context, PacketBuffer buffer) throws IOException; + + class Context implements ClientPacketListener.Context { + + @Override + public Minecraft minecraft() { + return minecraft; + } - boolean handle(Minecraft minecraft, ClientPlayNetworkHandler handler, PacketBuffer buffer) throws IOException; + @Override + public ClientPlayNetworkHandler networkHandler() { + return minecraft.getNetworkHandler(); + } + @Override + public void ensureOnMainThread() { + if (Thread.currentThread() != thread) { + throw NotOnMainThreadException.INSTANCE; + } + } + } } } diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java index b76d268f..5c8ad59d 100644 --- a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java +++ b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java @@ -23,6 +23,7 @@ import net.ornithemc.osl.networking.api.PacketBuffers; import net.ornithemc.osl.networking.api.PacketPayload; import net.ornithemc.osl.networking.api.server.ServerPacketListener; +import net.ornithemc.osl.networking.impl.NotOnMainThreadException; import net.ornithemc.osl.networking.impl.PacketFactory; import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; @@ -68,75 +69,20 @@ public static void destroy(MinecraftServer server) { public static final Map CHANNEL_LISTENERS = new LinkedHashMap<>(); public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { - ServerPlayNetworkingImpl.registerListener(channel, initializer, listener, false); - } - - public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { - ServerPlayNetworkingImpl.registerListener(channel, initializer, listener, true); - } - - private static void registerListener(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener, boolean async) { - registerListenerImpl(channel, new ChannelListener() { - - @Override - public boolean isAsync() { - return async; - } + registerListenerImpl(channel, (context, buffer) -> { + T payload = initializer.get(); + payload.read(buffer); - @Override - public boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, PacketBuffer buffer) throws IOException { - T payload = initializer.get(); - payload.read(buffer); - - return listener.handle(server, handler, player, payload); - } + listener.handle(context, payload); }); } public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { - ServerPlayNetworkingImpl.registerListener(channel, listener, false); - } - - public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { - ServerPlayNetworkingImpl.registerListener(channel, listener, true); - } - - private static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Buffer listener, boolean async) { - registerListenerImpl(channel, new ChannelListener() { - - @Override - public boolean isAsync() { - return async; - } - - @Override - public boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, PacketBuffer buffer) throws IOException { - return listener.handle(server, handler, player, buffer); - } - }); + registerListenerImpl(channel, listener::handle); } public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { - ServerPlayNetworkingImpl.registerListener(channel, listener, false); - } - - public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { - ServerPlayNetworkingImpl.registerListener(channel, listener, true); - } - - private static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener, boolean async) { - registerListenerImpl(channel, new ChannelListener() { - - @Override - public boolean isAsync() { - return async; - } - - @Override - public boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, PacketBuffer buffer) throws IOException { - return listener.handle(server, handler, player, buffer.readByteArray()); - } - }); + registerListenerImpl(channel, (context, buffer) -> listener.handle(context, buffer.readByteArray())); } private static void registerListenerImpl(NamespacedIdentifier channel, ChannelListener listener) { @@ -160,26 +106,27 @@ public static boolean handlePacket(MinecraftServer server, ServerPlayNetworkHand ChannelListener listener = CHANNEL_LISTENERS.get(channel); if (listener != null) { + ChannelListener.Context ctx = new ChannelListener.Context(player); PacketBuffer data = p.osl$networking$getData(); - if (Thread.currentThread() == thread || listener.isAsync()) { - return handlePayload(server, handler, player, listener, channel, data); - } else { - return ((TaskRunnerAccess) server).osl$networking$submit(() -> handlePayload(server, handler, player, listener, channel, data)); + try { + handlePayload(channel, listener, ctx, data); + } catch (NotOnMainThreadException e) { + ((TaskRunnerAccess) server).osl$networking$submit(() -> handlePayload(channel, listener, ctx, data)); } + + return true; } return false; } - private static boolean handlePayload(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, ChannelListener listener, NamespacedIdentifier channel, PacketBuffer data) { + private static void handlePayload(NamespacedIdentifier channel, ChannelListener listener, ChannelListener.Context ctx, PacketBuffer data) { try { - return listener.handle(server, handler, player, data); + listener.handle(ctx, data); } catch (IOException e) { LOGGER.warn("error handling custom payload on channel \'" + channel + "\'", e); } - - return true; } public static boolean isPlayReady(ServerPlayerEntity player) { @@ -410,9 +357,37 @@ private static void sendPacket(Iterable players, NamespacedI private interface ChannelListener { - boolean isAsync(); + void handle(Context context, PacketBuffer buffer) throws IOException; + + class Context implements ServerPacketListener.Context { + + private final ServerPlayerEntity player; + + Context(ServerPlayerEntity player) { + this.player = player; + } + + @Override + public MinecraftServer server() { + return server; + } + + @Override + public ServerPlayNetworkHandler networkHandler() { + return player.networkHandler; + } - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, PacketBuffer buffer) throws IOException; + @Override + public ServerPlayerEntity player() { + return player; + } + @Override + public void ensureOnMainThread() { + if (Thread.currentThread() != thread) { + throw NotOnMainThreadException.INSTANCE; + } + } + } } } diff --git a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/client/ClientPacketListener.java b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/client/ClientPacketListener.java index 4b9f15d4..558efde4 100644 --- a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/client/ClientPacketListener.java +++ b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/client/ClientPacketListener.java @@ -10,22 +10,37 @@ public interface ClientPacketListener { /** * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. */ - boolean handle(Minecraft minecraft, ClientNetworkHandler handler, T data); + void handle(Context ctx, T data); @FunctionalInterface - public interface Payload extends ClientPacketListener { + interface Payload extends ClientPacketListener { } @FunctionalInterface - public interface Buffer extends ClientPacketListener { + interface Buffer extends ClientPacketListener { } @FunctionalInterface - public interface Bytes extends ClientPacketListener { + interface Bytes extends ClientPacketListener { + } + + interface Context { + + /** + * @return the current Minecraft game instance. + */ + Minecraft minecraft(); + + /** + * @return the network handler that received the packet. + */ + ClientNetworkHandler networkHandler(); + + /** + * Ensure the packet listener is running on the main thread. + */ + void ensureOnMainThread(); + } } diff --git a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java index 06d6ff52..3b700508 100644 --- a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java +++ b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java @@ -12,7 +12,7 @@ public final class ClientPlayNetworking { /** * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. + * The data will be deserialized into a {@code CustomPayload} object of the given type. */ public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { ClientPlayNetworkingImpl.registerListener(channel, initializer, listener); @@ -20,15 +20,7 @@ public static void registerListener(NamespacedIdentifi /** * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. - */ - public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { - ClientPlayNetworkingImpl.registerListenerAsync(channel, initializer, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. + * The data will be wrapped in a {@link PacketBuffer} from which it can be read. */ public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { ClientPlayNetworkingImpl.registerListener(channel, listener); @@ -36,28 +28,12 @@ public static void registerListener(NamespacedIdentifier channel, ClientPacketLi /** * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. + * The data will be given as a raw {@code byte[]}. */ - public static void registerListenerAsync(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { - ClientPlayNetworkingImpl.registerListenerAsync(channel, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - */ - public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { + public static void registerLegacyListener(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { ClientPlayNetworkingImpl.registerListener(channel, listener); } - /** - * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. - */ - public static void registerListenerAsync(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { - ClientPlayNetworkingImpl.registerListenerAsync(channel, listener); - } - /** * Remove the listener registered to the given channel. */ diff --git a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java index 8ef8c508..316284f3 100644 --- a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java +++ b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java @@ -18,6 +18,7 @@ import net.ornithemc.osl.networking.api.PacketBuffers; import net.ornithemc.osl.networking.api.PacketPayload; import net.ornithemc.osl.networking.api.client.ClientPacketListener; +import net.ornithemc.osl.networking.impl.NotOnMainThreadException; import net.ornithemc.osl.networking.impl.PacketFactory; import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; import net.ornithemc.osl.networking.impl.access.LocalClientPlayerAccess; @@ -64,75 +65,20 @@ public static void destroy(Minecraft minecraft) { public static final Map CHANNEL_LISTENERS = new LinkedHashMap<>(); public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { - registerListener(channel, initializer, listener, false); - } - - public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { - registerListener(channel, initializer, listener, true); - } + registerListenerImpl(channel, (context, bytes) -> { + T payload = initializer.get(); + payload.read(PacketBuffers.wrap(bytes)); - private static void registerListener(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener, boolean async) { - registerListenerImpl(channel, new ChannelListener() { - - @Override - public boolean isAsync() { - return async; - } - - @Override - public boolean handle(Minecraft minecraft, ClientNetworkHandler handler, byte[] bytes) throws IOException { - T payload = initializer.get(); - payload.read(PacketBuffers.wrap(bytes)); - - return listener.handle(minecraft, handler, payload); - } + listener.handle(context, payload); }); } public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { - registerListener(channel, listener, false); - } - - public static void registerListenerAsync(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { - registerListener(channel, listener, true); - } - - private static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Buffer listener, boolean async) { - registerListenerImpl(channel, new ChannelListener() { - - @Override - public boolean isAsync() { - return async; - } - - @Override - public boolean handle(Minecraft minecraft, ClientNetworkHandler handler, byte[] bytes) throws IOException { - return listener.handle(minecraft, handler, PacketBuffers.wrap(bytes)); - } - }); + registerListenerImpl(channel, (context, bytes) -> listener.handle(context, PacketBuffers.wrap(bytes))); } public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { - registerListener(channel, listener, false); - } - - public static void registerListenerAsync(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { - registerListener(channel, listener, true); - } - - private static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Bytes listener, boolean async) { - registerListenerImpl(channel, new ChannelListener() { - - @Override - public boolean isAsync() { - return async; - } - - @Override - public boolean handle(Minecraft minecraft, ClientNetworkHandler handler, byte[] bytes) throws IOException { - return listener.handle(minecraft, handler, bytes); - } - }); + registerListenerImpl(channel, listener::handle); } private static void registerListenerImpl(NamespacedIdentifier channel, ChannelListener listener) { @@ -156,26 +102,27 @@ public static boolean handlePacket(Minecraft minecraft, ClientNetworkHandler han ChannelListener listener = CHANNEL_LISTENERS.get(channel); if (listener != null) { + ChannelListener.Context ctx = new ChannelListener.Context(); byte[] data = p.osl$networking$getData(); - if (Thread.currentThread() == thread || listener.isAsync()) { - return handlePayload(minecraft, handler, listener, channel, data); - } else { - return ((TaskRunnerAccess) minecraft).osl$networking$submit(() -> handlePayload(minecraft, handler, listener, channel, data)); + try { + handlePayload(channel, listener, ctx, data); + } catch (NotOnMainThreadException e) { + ((TaskRunnerAccess) minecraft).osl$networking$submit(() -> handlePayload(channel, listener, ctx, data)); } + + return true; } return false; } - private static boolean handlePayload(Minecraft minecraft, ClientNetworkHandler handler, ChannelListener listener, NamespacedIdentifier channel, byte[] data) { + private static void handlePayload(NamespacedIdentifier channel, ChannelListener listener, ChannelListener.Context ctx, byte[] data) { try { - return listener.handle(minecraft, handler, data); + listener.handle(ctx, data); } catch (IOException e) { LOGGER.warn("error handling custom payload on channel \'" + channel + "\'", e); } - - return true; } private static ClientNetworkHandler networkHandler() { @@ -261,11 +208,29 @@ private static void sendPacket(NamespacedIdentifier channel, byte[] data) { networkHandler().sendPacket(packetFactory.create(channel, data)); } + @FunctionalInterface private interface ChannelListener { - boolean isAsync(); + void handle(Context context, byte[] bytes) throws IOException; + + class Context implements ClientPacketListener.Context { + + @Override + public Minecraft minecraft() { + return minecraft; + } - boolean handle(Minecraft minecraft, ClientNetworkHandler handler, byte[] bytes) throws IOException; + @Override + public ClientNetworkHandler networkHandler() { + return ClientPlayNetworkingImpl.networkHandler(); + } + @Override + public void ensureOnMainThread() { + if (Thread.currentThread() != thread) { + throw NotOnMainThreadException.INSTANCE; + } + } + } } } diff --git a/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPacketListener.java b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPacketListener.java index 4b9f15d4..558efde4 100644 --- a/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPacketListener.java +++ b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPacketListener.java @@ -10,22 +10,37 @@ public interface ClientPacketListener { /** * Receive incoming data from the server. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. */ - boolean handle(Minecraft minecraft, ClientNetworkHandler handler, T data); + void handle(Context ctx, T data); @FunctionalInterface - public interface Payload extends ClientPacketListener { + interface Payload extends ClientPacketListener { } @FunctionalInterface - public interface Buffer extends ClientPacketListener { + interface Buffer extends ClientPacketListener { } @FunctionalInterface - public interface Bytes extends ClientPacketListener { + interface Bytes extends ClientPacketListener { + } + + interface Context { + + /** + * @return the current Minecraft game instance. + */ + Minecraft minecraft(); + + /** + * @return the network handler that received the packet. + */ + ClientNetworkHandler networkHandler(); + + /** + * Ensure the packet listener is running on the main thread. + */ + void ensureOnMainThread(); + } } diff --git a/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java index 06d6ff52..3b700508 100644 --- a/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java +++ b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/client/ClientPlayNetworking.java @@ -12,7 +12,7 @@ public final class ClientPlayNetworking { /** * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. + * The data will be deserialized into a {@code CustomPayload} object of the given type. */ public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { ClientPlayNetworkingImpl.registerListener(channel, initializer, listener); @@ -20,15 +20,7 @@ public static void registerListener(NamespacedIdentifi /** * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. - */ - public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { - ClientPlayNetworkingImpl.registerListenerAsync(channel, initializer, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. + * The data will be wrapped in a {@link PacketBuffer} from which it can be read. */ public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { ClientPlayNetworkingImpl.registerListener(channel, listener); @@ -36,28 +28,12 @@ public static void registerListener(NamespacedIdentifier channel, ClientPacketLi /** * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. + * The data will be given as a raw {@code byte[]}. */ - public static void registerListenerAsync(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { - ClientPlayNetworkingImpl.registerListenerAsync(channel, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - */ - public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { + public static void registerLegacyListener(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { ClientPlayNetworkingImpl.registerListener(channel, listener); } - /** - * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. - */ - public static void registerListenerAsync(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { - ClientPlayNetworkingImpl.registerListenerAsync(channel, listener); - } - /** * Remove the listener registered to the given channel. */ diff --git a/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java index 1ec5a4f0..89fb46e9 100644 --- a/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java +++ b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java @@ -11,22 +11,42 @@ public interface ServerPacketListener { /** * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, T data); + void handle(Context ctx, T data); @FunctionalInterface - public interface Payload extends ServerPacketListener { + interface Payload extends ServerPacketListener { } @FunctionalInterface - public interface Buffer extends ServerPacketListener { + interface Buffer extends ServerPacketListener { } @FunctionalInterface - public interface Bytes extends ServerPacketListener { + interface Bytes extends ServerPacketListener { + } + + interface Context { + + /** + * @return the current MinecraftServer game instance. + */ + MinecraftServer server(); + + /** + * @return the network handler that received the packet. + */ + ServerPlayNetworkHandler networkHandler(); + + /** + * @return the player that received the packet. + */ + ServerPlayerEntity player(); + + /** + * Ensure the packet listener is running on the main thread. + */ + void ensureOnMainThread(); + } } diff --git a/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java index c46df829..4f45df86 100644 --- a/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java +++ b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java @@ -14,7 +14,7 @@ public final class ServerPlayNetworking { /** * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. + * The data will be deserialized into a {@code CustomPayload} object of the given type. */ public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { ServerPlayNetworkingImpl.registerListener(channel, initializer, listener); @@ -22,15 +22,7 @@ public static void registerListener(NamespacedIdentifi /** * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. - */ - public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { - ServerPlayNetworkingImpl.registerListenerAsync(channel, initializer, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. + * The data will be wrapped in a {@link PacketBuffer} from which it can be read. */ public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { ServerPlayNetworkingImpl.registerListener(channel, listener); @@ -38,28 +30,12 @@ public static void registerListener(NamespacedIdentifier channel, ServerPacketLi /** * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. + * The data will be given as a raw {@code byte[]}. */ - public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { - ServerPlayNetworkingImpl.registerListenerAsync(channel, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - */ - public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { + public static void registerLegacyListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { ServerPlayNetworkingImpl.registerListener(channel, listener); } - /** - * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. - */ - public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { - ServerPlayNetworkingImpl.registerListenerAsync(channel, listener); - } - /** * Remove the listener registered to the given channel. */ diff --git a/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java index 86440add..40c4bc76 100644 --- a/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java +++ b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java @@ -18,6 +18,7 @@ import net.ornithemc.osl.networking.api.PacketBuffers; import net.ornithemc.osl.networking.api.PacketPayload; import net.ornithemc.osl.networking.api.client.ClientPacketListener; +import net.ornithemc.osl.networking.impl.NotOnMainThreadException; import net.ornithemc.osl.networking.impl.PacketFactory; import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; @@ -63,75 +64,20 @@ public static void destroy(Minecraft minecraft) { public static final Map CHANNEL_LISTENERS = new LinkedHashMap<>(); public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { - registerListener(channel, initializer, listener, false); - } - - public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { - registerListener(channel, initializer, listener, true); - } + registerListenerImpl(channel, (context, bytes) -> { + T payload = initializer.get(); + payload.read(PacketBuffers.wrap(bytes)); - private static void registerListener(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener, boolean async) { - registerListenerImpl(channel, new ChannelListener() { - - @Override - public boolean isAsync() { - return async; - } - - @Override - public boolean handle(Minecraft minecraft, ClientNetworkHandler handler, byte[] bytes) throws IOException { - T payload = initializer.get(); - payload.read(PacketBuffers.wrap(bytes)); - - return listener.handle(minecraft, handler, payload); - } + listener.handle(context, payload); }); } public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { - registerListener(channel, listener, false); - } - - public static void registerListenerAsync(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { - registerListener(channel, listener, true); - } - - private static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Buffer listener, boolean async) { - registerListenerImpl(channel, new ChannelListener() { - - @Override - public boolean isAsync() { - return async; - } - - @Override - public boolean handle(Minecraft minecraft, ClientNetworkHandler handler, byte[] bytes) throws IOException { - return listener.handle(minecraft, handler, PacketBuffers.wrap(bytes)); - } - }); + registerListenerImpl(channel, (context, bytes) -> listener.handle(context, PacketBuffers.wrap(bytes))); } public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { - registerListener(channel, listener, false); - } - - public static void registerListenerAsync(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { - registerListener(channel, listener, true); - } - - private static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Bytes listener, boolean async) { - registerListenerImpl(channel, new ChannelListener() { - - @Override - public boolean isAsync() { - return async; - } - - @Override - public boolean handle(Minecraft minecraft, ClientNetworkHandler handler, byte[] bytes) throws IOException { - return listener.handle(minecraft, handler, bytes); - } - }); + registerListenerImpl(channel, listener::handle); } private static void registerListenerImpl(NamespacedIdentifier channel, ChannelListener listener) { @@ -155,26 +101,27 @@ public static boolean handlePacket(Minecraft minecraft, ClientNetworkHandler han ChannelListener listener = CHANNEL_LISTENERS.get(channel); if (listener != null) { + ChannelListener.Context ctx = new ChannelListener.Context(); byte[] data = p.osl$networking$getData(); - if (Thread.currentThread() == thread || listener.isAsync()) { - return handlePayload(minecraft, handler, listener, channel, data); - } else { - return ((TaskRunnerAccess) minecraft).osl$networking$submit(() -> handlePayload(minecraft, handler, listener, channel, data)); + try { + handlePayload(channel, listener, ctx, data); + } catch (NotOnMainThreadException e) { + ((TaskRunnerAccess) minecraft).osl$networking$submit(() -> handlePayload(channel, listener, ctx, data)); } + + return true; } return false; } - private static boolean handlePayload(Minecraft minecraft, ClientNetworkHandler handler, ChannelListener listener, NamespacedIdentifier channel, byte[] data) { + private static void handlePayload(NamespacedIdentifier channel, ChannelListener listener, ChannelListener.Context ctx, byte[] data) { try { - return listener.handle(minecraft, handler, data); + listener.handle(ctx, data); } catch (IOException e) { LOGGER.warn("error handling custom payload on channel \'" + channel + "\'", e); } - - return true; } public static boolean isPlayReady() { @@ -255,11 +202,29 @@ private static void sendPacket(NamespacedIdentifier channel, byte[] data) { minecraft.getNetworkHandler().sendPacket(packetFactory.create(channel, data)); } + @FunctionalInterface private interface ChannelListener { - boolean isAsync(); + void handle(Context context, byte[] bytes) throws IOException; + + class Context implements ClientPacketListener.Context { + + @Override + public Minecraft minecraft() { + return minecraft; + } - boolean handle(Minecraft minecraft, ClientNetworkHandler handler, byte[] bytes) throws IOException; + @Override + public ClientNetworkHandler networkHandler() { + return minecraft.getNetworkHandler(); + } + @Override + public void ensureOnMainThread() { + if (Thread.currentThread() != thread) { + throw NotOnMainThreadException.INSTANCE; + } + } + } } } diff --git a/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java index bed7ee2c..0df44086 100644 --- a/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java +++ b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java @@ -22,6 +22,7 @@ import net.ornithemc.osl.networking.api.PacketBuffers; import net.ornithemc.osl.networking.api.PacketPayload; import net.ornithemc.osl.networking.api.server.ServerPacketListener; +import net.ornithemc.osl.networking.impl.NotOnMainThreadException; import net.ornithemc.osl.networking.impl.PacketFactory; import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; @@ -67,75 +68,20 @@ public static void destroy(MinecraftServer server) { public static final Map CHANNEL_LISTENERS = new LinkedHashMap<>(); public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { - ServerPlayNetworkingImpl.registerListener(channel, initializer, listener, false); - } - - public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { - ServerPlayNetworkingImpl.registerListener(channel, initializer, listener, true); - } - - private static void registerListener(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener, boolean async) { - registerListenerImpl(channel, new ChannelListener() { - - @Override - public boolean isAsync() { - return async; - } + registerListenerImpl(channel, (context, bytes) -> { + T payload = initializer.get(); + payload.read(PacketBuffers.wrap(bytes)); - @Override - public boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] bytes) throws IOException { - T payload = initializer.get(); - payload.read(PacketBuffers.wrap(bytes)); - - return listener.handle(server, handler, player, payload); - } + listener.handle(context, payload); }); } public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { - ServerPlayNetworkingImpl.registerListener(channel, listener, false); - } - - public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { - ServerPlayNetworkingImpl.registerListener(channel, listener, true); - } - - private static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Buffer listener, boolean async) { - registerListenerImpl(channel, new ChannelListener() { - - @Override - public boolean isAsync() { - return async; - } - - @Override - public boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] bytes) throws IOException { - return listener.handle(server, handler, player, PacketBuffers.wrap(bytes)); - } - }); + registerListenerImpl(channel, (context, bytes) -> listener.handle(context, PacketBuffers.wrap(bytes))); } public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { - ServerPlayNetworkingImpl.registerListener(channel, listener, false); - } - - public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { - ServerPlayNetworkingImpl.registerListener(channel, listener, true); - } - - private static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener, boolean async) { - registerListenerImpl(channel, new ChannelListener() { - - @Override - public boolean isAsync() { - return async; - } - - @Override - public boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] bytes) throws IOException { - return listener.handle(server, handler, player, bytes); - } - }); + registerListenerImpl(channel, listener::handle); } private static void registerListenerImpl(NamespacedIdentifier channel, ChannelListener listener) { @@ -159,26 +105,27 @@ public static boolean handlePacket(MinecraftServer server, ServerPlayNetworkHand ChannelListener listener = CHANNEL_LISTENERS.get(channel); if (listener != null) { + ChannelListener.Context ctx = new ChannelListener.Context(player); byte[] data = p.osl$networking$getData(); - if (Thread.currentThread() == thread || listener.isAsync()) { - return handlePayload(server, handler, player, listener, channel, data); - } else { - return ((TaskRunnerAccess) server).osl$networking$submit(() -> handlePayload(server, handler, player, listener, channel, data)); + try { + handlePayload(channel, listener, ctx, data); + } catch (NotOnMainThreadException e) { + ((TaskRunnerAccess) server).osl$networking$submit(() -> handlePayload(channel, listener, ctx, data)); } + + return true; } return false; } - private static boolean handlePayload(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, ChannelListener listener, NamespacedIdentifier channel, byte[] data) { + private static void handlePayload(NamespacedIdentifier channel, ChannelListener listener, ChannelListener.Context ctx, byte[] data) { try { - return listener.handle(server, handler, player, data); + listener.handle(ctx, data); } catch (IOException e) { LOGGER.warn("error handling custom payload on channel \'" + channel + "\'", e); } - - return true; } public static boolean isPlayReady(ServerPlayerEntity player) { @@ -409,9 +356,37 @@ private static void sendPacket(Iterable players, NamespacedI private interface ChannelListener { - boolean isAsync(); + void handle(Context context, byte[] bytes) throws IOException; + + class Context implements ServerPacketListener.Context { + + private final ServerPlayerEntity player; + + Context(ServerPlayerEntity player) { + this.player = player; + } + + @Override + public MinecraftServer server() { + return server; + } + + @Override + public ServerPlayNetworkHandler networkHandler() { + return player.networkHandler; + } - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] bytes) throws IOException; + @Override + public ServerPlayerEntity player() { + return player; + } + @Override + public void ensureOnMainThread() { + if (Thread.currentThread() != thread) { + throw NotOnMainThreadException.INSTANCE; + } + } + } } } diff --git a/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java index 1ec5a4f0..89fb46e9 100644 --- a/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java +++ b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java @@ -11,22 +11,42 @@ public interface ServerPacketListener { /** * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, T data); + void handle(Context ctx, T data); @FunctionalInterface - public interface Payload extends ServerPacketListener { + interface Payload extends ServerPacketListener { } @FunctionalInterface - public interface Buffer extends ServerPacketListener { + interface Buffer extends ServerPacketListener { } @FunctionalInterface - public interface Bytes extends ServerPacketListener { + interface Bytes extends ServerPacketListener { + } + + interface Context { + + /** + * @return the current MinecraftServer game instance. + */ + MinecraftServer server(); + + /** + * @return the network handler that received the packet. + */ + ServerPlayNetworkHandler networkHandler(); + + /** + * @return the player that received the packet. + */ + ServerPlayerEntity player(); + + /** + * Ensure the packet listener is running on the main thread. + */ + void ensureOnMainThread(); + } } diff --git a/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java index 23ee3976..0b6bc7ad 100644 --- a/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java +++ b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java @@ -14,7 +14,7 @@ public final class ServerPlayNetworking { /** * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. + * The data will be deserialized into a {@code CustomPayload} object of the given type. */ public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { ServerPlayNetworkingImpl.registerListener(channel, initializer, listener); @@ -22,15 +22,7 @@ public static void registerListener(NamespacedIdentifi /** * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. - */ - public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { - ServerPlayNetworkingImpl.registerListenerAsync(channel, initializer, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. + * The data will be wrapped in a {@link PacketBuffer} from which it can be read. */ public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { ServerPlayNetworkingImpl.registerListener(channel, listener); @@ -38,28 +30,12 @@ public static void registerListener(NamespacedIdentifier channel, ServerPacketLi /** * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. + * The data will be given as a raw {@code byte[]}. */ - public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { - ServerPlayNetworkingImpl.registerListenerAsync(channel, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - */ - public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { + public static void registerLegacyListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { ServerPlayNetworkingImpl.registerListener(channel, listener); } - /** - * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. - */ - public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { - ServerPlayNetworkingImpl.registerListenerAsync(channel, listener); - } - /** * Remove the listener registered to the given channel. */ diff --git a/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java index 528a6e03..6f39e27c 100644 --- a/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java +++ b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java @@ -22,6 +22,7 @@ import net.ornithemc.osl.networking.api.PacketBuffers; import net.ornithemc.osl.networking.api.PacketPayload; import net.ornithemc.osl.networking.api.server.ServerPacketListener; +import net.ornithemc.osl.networking.impl.NotOnMainThreadException; import net.ornithemc.osl.networking.impl.PacketFactory; import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; @@ -67,75 +68,20 @@ public static void destroy(MinecraftServer server) { public static final Map CHANNEL_LISTENERS = new LinkedHashMap<>(); public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { - ServerPlayNetworkingImpl.registerListener(channel, initializer, listener, false); - } - - public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { - ServerPlayNetworkingImpl.registerListener(channel, initializer, listener, true); - } - - private static void registerListener(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener, boolean async) { - registerListenerImpl(channel, new ChannelListener() { - - @Override - public boolean isAsync() { - return async; - } + registerListenerImpl(channel, (context, bytes) -> { + T payload = initializer.get(); + payload.read(PacketBuffers.wrap(bytes)); - @Override - public boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] bytes) throws IOException { - T payload = initializer.get(); - payload.read(PacketBuffers.wrap(bytes)); - - return listener.handle(server, handler, player, payload); - } + listener.handle(context, payload); }); } public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { - ServerPlayNetworkingImpl.registerListener(channel, listener, false); - } - - public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { - ServerPlayNetworkingImpl.registerListener(channel, listener, true); - } - - private static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Buffer listener, boolean async) { - registerListenerImpl(channel, new ChannelListener() { - - @Override - public boolean isAsync() { - return async; - } - - @Override - public boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] bytes) throws IOException { - return listener.handle(server, handler, player, PacketBuffers.wrap(bytes)); - } - }); + registerListenerImpl(channel, (context, bytes) -> listener.handle(context, PacketBuffers.wrap(bytes))); } public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { - ServerPlayNetworkingImpl.registerListener(channel, listener, false); - } - - public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { - ServerPlayNetworkingImpl.registerListener(channel, listener, true); - } - - private static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener, boolean async) { - registerListenerImpl(channel, new ChannelListener() { - - @Override - public boolean isAsync() { - return async; - } - - @Override - public boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] bytes) throws IOException { - return listener.handle(server, handler, player, bytes); - } - }); + registerListenerImpl(channel, listener::handle); } private static void registerListenerImpl(NamespacedIdentifier channel, ChannelListener listener) { @@ -159,26 +105,27 @@ public static boolean handlePacket(MinecraftServer server, ServerPlayNetworkHand ChannelListener listener = CHANNEL_LISTENERS.get(channel); if (listener != null) { + ChannelListener.Context ctx = new ChannelListener.Context(player); byte[] data = p.osl$networking$getData(); - if (Thread.currentThread() == thread || listener.isAsync()) { - return handlePayload(server, handler, player, listener, channel, data); - } else { - return ((TaskRunnerAccess) server).osl$networking$submit(() -> handlePayload(server, handler, player, listener, channel, data)); + try { + handlePayload(channel, listener, ctx, data); + } catch (NotOnMainThreadException e) { + ((TaskRunnerAccess) server).osl$networking$submit(() -> handlePayload(channel, listener, ctx, data)); } + + return true; } return false; } - private static boolean handlePayload(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, ChannelListener listener, NamespacedIdentifier channel, byte[] data) { + private static void handlePayload(NamespacedIdentifier channel, ChannelListener listener, ChannelListener.Context ctx, byte[] data) { try { - return listener.handle(server, handler, player, data); + listener.handle(ctx, data); } catch (IOException e) { LOGGER.warn("error handling custom payload on channel \'" + channel + "\'", e); } - - return true; } public static boolean isPlayReady(ServerPlayerEntity player) { @@ -377,9 +324,37 @@ private static void sendPacket(Iterable players, NamespacedI private interface ChannelListener { - boolean isAsync(); + void handle(Context context, byte[] bytes) throws IOException; + + class Context implements ServerPacketListener.Context { + + private final ServerPlayerEntity player; + + Context(ServerPlayerEntity player) { + this.player = player; + } + + @Override + public MinecraftServer server() { + return server; + } + + @Override + public ServerPlayNetworkHandler networkHandler() { + return player.networkHandler; + } - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] bytes) throws IOException; + @Override + public ServerPlayerEntity player() { + return player; + } + @Override + public void ensureOnMainThread() { + if (Thread.currentThread() != thread) { + throw NotOnMainThreadException.INSTANCE; + } + } + } } } diff --git a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java index 1ec5a4f0..89fb46e9 100644 --- a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java +++ b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/server/ServerPacketListener.java @@ -11,22 +11,42 @@ public interface ServerPacketListener { /** * Receive incoming data from the client. - * - * @return - * Whether the data is consumed. Should only return {@code false} if the - * data is completely ignored. */ - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, T data); + void handle(Context ctx, T data); @FunctionalInterface - public interface Payload extends ServerPacketListener { + interface Payload extends ServerPacketListener { } @FunctionalInterface - public interface Buffer extends ServerPacketListener { + interface Buffer extends ServerPacketListener { } @FunctionalInterface - public interface Bytes extends ServerPacketListener { + interface Bytes extends ServerPacketListener { + } + + interface Context { + + /** + * @return the current MinecraftServer game instance. + */ + MinecraftServer server(); + + /** + * @return the network handler that received the packet. + */ + ServerPlayNetworkHandler networkHandler(); + + /** + * @return the player that received the packet. + */ + ServerPlayerEntity player(); + + /** + * Ensure the packet listener is running on the main thread. + */ + void ensureOnMainThread(); + } } diff --git a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java index c46df829..4f45df86 100644 --- a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java +++ b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/api/server/ServerPlayNetworking.java @@ -14,7 +14,7 @@ public final class ServerPlayNetworking { /** * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. + * The data will be deserialized into a {@code CustomPayload} object of the given type. */ public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { ServerPlayNetworkingImpl.registerListener(channel, initializer, listener); @@ -22,15 +22,7 @@ public static void registerListener(NamespacedIdentifi /** * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. - */ - public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { - ServerPlayNetworkingImpl.registerListenerAsync(channel, initializer, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. + * The data will be wrapped in a {@link PacketBuffer} from which it can be read. */ public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { ServerPlayNetworkingImpl.registerListener(channel, listener); @@ -38,28 +30,12 @@ public static void registerListener(NamespacedIdentifier channel, ServerPacketLi /** * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. + * The data will be given as a raw {@code byte[]}. */ - public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { - ServerPlayNetworkingImpl.registerListenerAsync(channel, listener); - } - - /** - * Register a listener to receive data from the server through the given channel. - * This listener will only be called from the main thread. - */ - public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { + public static void registerLegacyListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { ServerPlayNetworkingImpl.registerListener(channel, listener); } - /** - * Register a listener to receive data from the server through the given channel. - * This listener may be called off the main thread. - */ - public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { - ServerPlayNetworkingImpl.registerListenerAsync(channel, listener); - } - /** * Remove the listener registered to the given channel. */ diff --git a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java index 042f3fbd..23340806 100644 --- a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java +++ b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java @@ -22,6 +22,7 @@ import net.ornithemc.osl.networking.api.PacketBuffers; import net.ornithemc.osl.networking.api.PacketPayload; import net.ornithemc.osl.networking.api.server.ServerPacketListener; +import net.ornithemc.osl.networking.impl.NotOnMainThreadException; import net.ornithemc.osl.networking.impl.PacketFactory; import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; import net.ornithemc.osl.networking.impl.access.NetworkHandlerAccess; @@ -67,75 +68,20 @@ public static void destroy(MinecraftServer server) { public static final Map CHANNEL_LISTENERS = new LinkedHashMap<>(); public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { - ServerPlayNetworkingImpl.registerListener(channel, initializer, listener, false); - } - - public static void registerListenerAsync(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { - ServerPlayNetworkingImpl.registerListener(channel, initializer, listener, true); - } - - private static void registerListener(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener, boolean async) { - registerListenerImpl(channel, new ChannelListener() { - - @Override - public boolean isAsync() { - return async; - } + registerListenerImpl(channel, (context, bytes) -> { + T payload = initializer.get(); + payload.read(PacketBuffers.wrap(bytes)); - @Override - public boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] bytes) throws IOException { - T payload = initializer.get(); - payload.read(PacketBuffers.wrap(bytes)); - - return listener.handle(server, handler, player, payload); - } + listener.handle(context, payload); }); } public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { - ServerPlayNetworkingImpl.registerListener(channel, listener, false); - } - - public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { - ServerPlayNetworkingImpl.registerListener(channel, listener, true); - } - - private static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Buffer listener, boolean async) { - registerListenerImpl(channel, new ChannelListener() { - - @Override - public boolean isAsync() { - return async; - } - - @Override - public boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] bytes) throws IOException { - return listener.handle(server, handler, player, PacketBuffers.wrap(bytes)); - } - }); + registerListenerImpl(channel, (context, bytes) -> listener.handle(context, PacketBuffers.wrap(bytes))); } public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { - ServerPlayNetworkingImpl.registerListener(channel, listener, false); - } - - public static void registerListenerAsync(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { - ServerPlayNetworkingImpl.registerListener(channel, listener, true); - } - - private static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener, boolean async) { - registerListenerImpl(channel, new ChannelListener() { - - @Override - public boolean isAsync() { - return async; - } - - @Override - public boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] bytes) throws IOException { - return listener.handle(server, handler, player, bytes); - } - }); + registerListenerImpl(channel, listener::handle); } private static void registerListenerImpl(NamespacedIdentifier channel, ChannelListener listener) { @@ -159,26 +105,27 @@ public static boolean handlePacket(MinecraftServer server, ServerPlayNetworkHand ChannelListener listener = CHANNEL_LISTENERS.get(channel); if (listener != null) { + ChannelListener.Context ctx = new ChannelListener.Context(player); byte[] data = p.osl$networking$getData(); - if (Thread.currentThread() == thread || listener.isAsync()) { - return handlePayload(server, handler, player, listener, channel, data); - } else { - return ((TaskRunnerAccess) server).osl$networking$submit(() -> handlePayload(server, handler, player, listener, channel, data)); + try { + handlePayload(channel, listener, ctx, data); + } catch (NotOnMainThreadException e) { + ((TaskRunnerAccess) server).osl$networking$submit(() -> handlePayload(channel, listener, ctx, data)); } + + return true; } return false; } - private static boolean handlePayload(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, ChannelListener listener, NamespacedIdentifier channel, byte[] data) { + private static void handlePayload(NamespacedIdentifier channel, ChannelListener listener, ChannelListener.Context ctx, byte[] data) { try { - return listener.handle(server, handler, player, data); + listener.handle(ctx, data); } catch (IOException e) { LOGGER.warn("error handling custom payload on channel \'" + channel + "\'", e); } - - return true; } public static boolean isPlayReady(ServerPlayerEntity player) { @@ -409,9 +356,37 @@ private static void sendPacket(Iterable players, NamespacedI private interface ChannelListener { - boolean isAsync(); + void handle(Context context, byte[] bytes) throws IOException; + + class Context implements ServerPacketListener.Context { + + private final ServerPlayerEntity player; + + Context(ServerPlayerEntity player) { + this.player = player; + } + + @Override + public MinecraftServer server() { + return server; + } + + @Override + public ServerPlayNetworkHandler networkHandler() { + return player.networkHandler; + } - boolean handle(MinecraftServer server, ServerPlayNetworkHandler handler, ServerPlayerEntity player, byte[] bytes) throws IOException; + @Override + public ServerPlayerEntity player() { + return player; + } + @Override + public void ensureOnMainThread() { + if (Thread.currentThread() != thread) { + throw NotOnMainThreadException.INSTANCE; + } + } + } } } diff --git a/libraries/networking/src/main/java/net/ornithemc/osl/networking/impl/NotOnMainThreadException.java b/libraries/networking/src/main/java/net/ornithemc/osl/networking/impl/NotOnMainThreadException.java new file mode 100644 index 00000000..83693fcc --- /dev/null +++ b/libraries/networking/src/main/java/net/ornithemc/osl/networking/impl/NotOnMainThreadException.java @@ -0,0 +1,11 @@ +package net.ornithemc.osl.networking.impl; + +@SuppressWarnings("serial") +public final class NotOnMainThreadException extends RuntimeException { + + public static final NotOnMainThreadException INSTANCE = new NotOnMainThreadException(); + + private NotOnMainThreadException() { + super(); + } +} From 4b04dccce41ed9ab85d970b6d7621456da45eb6b Mon Sep 17 00:00:00 2001 From: Space Walker Date: Mon, 15 Dec 2025 19:21:47 +0100 Subject: [PATCH 6/8] add channel registry and channel settings --- .../osl/networking/impl/HandshakePayload.java | 3 +- .../impl/client/ClientPlayNetworkingImpl.java | 24 +++++++++--- .../impl/server/ServerPlayNetworkingImpl.java | 34 +++++++++++----- .../osl/networking/impl/HandshakePayload.java | 3 +- .../impl/client/ClientPlayNetworkingImpl.java | 24 +++++++++--- .../impl/server/ServerPlayNetworkingImpl.java | 34 +++++++++++----- .../osl/networking/impl/HandshakePayload.java | 3 +- .../impl/client/ClientPlayNetworkingImpl.java | 24 +++++++++--- .../osl/networking/impl/HandshakePayload.java | 3 +- .../impl/client/ClientPlayNetworkingImpl.java | 24 +++++++++--- .../impl/server/ServerPlayNetworkingImpl.java | 34 +++++++++++----- .../osl/networking/impl/HandshakePayload.java | 3 +- .../impl/server/ServerPlayNetworkingImpl.java | 34 +++++++++++----- .../osl/networking/impl/HandshakePayload.java | 3 +- .../impl/server/ServerPlayNetworkingImpl.java | 34 +++++++++++----- .../osl/networking/api/ChannelRegistry.java | 36 +++++++++++++++++ .../networking/impl/ChannelRegistryImpl.java | 39 +++++++++++++++++++ .../osl/networking/impl/ChannelSettings.java | 31 +++++++++++++++ 18 files changed, 315 insertions(+), 75 deletions(-) create mode 100644 libraries/networking/src/main/java/net/ornithemc/osl/networking/api/ChannelRegistry.java create mode 100644 libraries/networking/src/main/java/net/ornithemc/osl/networking/impl/ChannelRegistryImpl.java create mode 100644 libraries/networking/src/main/java/net/ornithemc/osl/networking/impl/ChannelSettings.java diff --git a/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java index 27d46bc9..a9bbf2ba 100644 --- a/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java +++ b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java @@ -6,6 +6,7 @@ import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.networking.api.ChannelIdentifiers; +import net.ornithemc.osl.networking.api.ChannelRegistry; import net.ornithemc.osl.networking.api.PacketBuffer; import net.ornithemc.osl.networking.api.PacketPayload; import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; @@ -13,7 +14,7 @@ public class HandshakePayload implements PacketPayload { - public static final NamespacedIdentifier CHANNEL = Constants.OSL_HANDSHAKE_CHANNEL; + public static final NamespacedIdentifier CHANNEL = ChannelRegistry.register(Constants.OSL_HANDSHAKE_CHANNEL); public byte protocol; public Set channels; diff --git a/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java index 662e7666..8aa40704 100644 --- a/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java +++ b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java @@ -18,6 +18,8 @@ import net.ornithemc.osl.networking.api.PacketBuffers; import net.ornithemc.osl.networking.api.PacketPayload; import net.ornithemc.osl.networking.api.client.ClientPacketListener; +import net.ornithemc.osl.networking.impl.ChannelRegistryImpl; +import net.ornithemc.osl.networking.impl.ChannelSettings; import net.ornithemc.osl.networking.impl.NotOnMainThreadException; import net.ornithemc.osl.networking.impl.PacketFactory; import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; @@ -64,7 +66,7 @@ public static void destroy(Minecraft minecraft) { public static final Map CHANNEL_LISTENERS = new LinkedHashMap<>(); public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { - registerListenerImpl(channel, (context, buffer) -> { + registerListenerInternal(channel, (context, buffer) -> { T payload = initializer.get(); payload.read(buffer); @@ -73,17 +75,23 @@ public static void registerListener(NamespacedIdentifi } public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { - registerListenerImpl(channel, listener::handle); + registerListenerInternal(channel, listener::handle); } public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { - registerListenerImpl(channel, (context, buffer) -> listener.handle(context, buffer.readByteArray())); + registerListenerInternal(channel, (context, buffer) -> listener.handle(context, buffer.readByteArray())); } - private static void registerListenerImpl(NamespacedIdentifier channel, ChannelListener listener) { + private static void registerListenerInternal(NamespacedIdentifier channel, ChannelListener listener) { + ChannelSettings settings = ChannelRegistryImpl.getSettings(channel); + + if (settings == null || !settings.isClientbound()) { + throw new IllegalArgumentException("channel \'" + channel + "\' is not client-bound - did you register it with the wrong settings?"); + } + CHANNEL_LISTENERS.compute(channel, (key, value) -> { if (value != null) { - throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); + throw new IllegalArgumentException("there is already a listener on channel \'" + channel + "\'"); } return listener; @@ -201,7 +209,11 @@ private static void sendInternal(NamespacedIdentifier channel, byte[] bytes) { } private static void sendPacket(NamespacedIdentifier channel, PacketBuffer data) { - minecraft.getNetworkHandler().sendPacket(packetFactory.create(channel, data)); + ChannelSettings settings = ChannelRegistryImpl.getSettings(channel); + + if (settings != null && settings.isServerbound()) { + minecraft.getNetworkHandler().sendPacket(packetFactory.create(channel, data)); + } } @FunctionalInterface diff --git a/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java index f55fc7c8..b73ca1a1 100644 --- a/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java +++ b/libraries/networking/networking-mc13w41a-mc18w30b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java @@ -22,6 +22,8 @@ import net.ornithemc.osl.networking.api.PacketBuffers; import net.ornithemc.osl.networking.api.PacketPayload; import net.ornithemc.osl.networking.api.server.ServerPacketListener; +import net.ornithemc.osl.networking.impl.ChannelRegistryImpl; +import net.ornithemc.osl.networking.impl.ChannelSettings; import net.ornithemc.osl.networking.impl.NotOnMainThreadException; import net.ornithemc.osl.networking.impl.PacketFactory; import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; @@ -69,7 +71,7 @@ public static void destroy(MinecraftServer server) { public static final Map CHANNEL_LISTENERS = new LinkedHashMap<>(); public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { - registerListenerImpl(channel, (context, buffer) -> { + registerListenerInternal(channel, (context, buffer) -> { T payload = initializer.get(); payload.read(buffer); @@ -78,17 +80,23 @@ public static void registerListener(NamespacedIdentifi } public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { - registerListenerImpl(channel, listener::handle); + registerListenerInternal(channel, listener::handle); } public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { - registerListenerImpl(channel, (context, buffer) -> listener.handle(context, buffer.readByteArray())); + registerListenerInternal(channel, (context, buffer) -> listener.handle(context, buffer.readByteArray())); } - private static void registerListenerImpl(NamespacedIdentifier channel, ChannelListener listener) { + private static void registerListenerInternal(NamespacedIdentifier channel, ChannelListener listener) { + ChannelSettings settings = ChannelRegistryImpl.getSettings(channel); + + if (settings == null || !settings.isServerbound()) { + throw new IllegalArgumentException("channel \'" + channel + "\' is not server-bound - did you register it with the wrong settings?"); + } + CHANNEL_LISTENERS.compute(channel, (key, value) -> { if (value != null) { - throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); + throw new IllegalArgumentException("there is already a listener on channel \'" + channel + "\'"); } return listener; @@ -346,14 +354,22 @@ private static Iterable collectPlayers(Iterable players, NamespacedIdentifier channel, PacketBuffer data) { - Packet packet = packetFactory.create(channel, data); + ChannelSettings settings = ChannelRegistryImpl.getSettings(channel); + + if (settings != null && settings.isClientbound()) { + Packet packet = packetFactory.create(channel, data); - for (ServerPlayerEntity player : players) { - player.networkHandler.sendPacket(packet); + for (ServerPlayerEntity player : players) { + player.networkHandler.sendPacket(packet); + } } } diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java index 27d46bc9..a9bbf2ba 100644 --- a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java +++ b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java @@ -6,6 +6,7 @@ import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.networking.api.ChannelIdentifiers; +import net.ornithemc.osl.networking.api.ChannelRegistry; import net.ornithemc.osl.networking.api.PacketBuffer; import net.ornithemc.osl.networking.api.PacketPayload; import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; @@ -13,7 +14,7 @@ public class HandshakePayload implements PacketPayload { - public static final NamespacedIdentifier CHANNEL = Constants.OSL_HANDSHAKE_CHANNEL; + public static final NamespacedIdentifier CHANNEL = ChannelRegistry.register(Constants.OSL_HANDSHAKE_CHANNEL); public byte protocol; public Set channels; diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java index e7d037a5..e9ba1661 100644 --- a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java +++ b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java @@ -18,6 +18,8 @@ import net.ornithemc.osl.networking.api.PacketBuffers; import net.ornithemc.osl.networking.api.PacketPayload; import net.ornithemc.osl.networking.api.client.ClientPacketListener; +import net.ornithemc.osl.networking.impl.ChannelRegistryImpl; +import net.ornithemc.osl.networking.impl.ChannelSettings; import net.ornithemc.osl.networking.impl.NotOnMainThreadException; import net.ornithemc.osl.networking.impl.PacketFactory; import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; @@ -64,7 +66,7 @@ public static void destroy(Minecraft minecraft) { public static final Map CHANNEL_LISTENERS = new LinkedHashMap<>(); public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { - registerListenerImpl(channel, (context, buffer) -> { + registerListenerInternal(channel, (context, buffer) -> { T payload = initializer.get(); payload.read(buffer); @@ -73,17 +75,23 @@ public static void registerListener(NamespacedIdentifi } public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { - registerListenerImpl(channel, listener::handle); + registerListenerInternal(channel, listener::handle); } public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { - registerListenerImpl(channel, (context, buffer) -> listener.handle(context, buffer.readByteArray())); + registerListenerInternal(channel, (context, buffer) -> listener.handle(context, buffer.readByteArray())); } - private static void registerListenerImpl(NamespacedIdentifier channel, ChannelListener listener) { + private static void registerListenerInternal(NamespacedIdentifier channel, ChannelListener listener) { + ChannelSettings settings = ChannelRegistryImpl.getSettings(channel); + + if (settings == null || !settings.isClientbound()) { + throw new IllegalArgumentException("channel \'" + channel + "\' is not client-bound - did you register it with the wrong settings?"); + } + CHANNEL_LISTENERS.compute(channel, (key, value) -> { if (value != null) { - throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); + throw new IllegalArgumentException("there is already a listener on channel \'" + channel + "\'"); } return listener; @@ -199,7 +207,11 @@ private static void sendInternal(NamespacedIdentifier channel, byte[] bytes) { } private static void sendPacket(NamespacedIdentifier channel, PacketBuffer data) { - minecraft.getNetworkHandler().sendPacket(packetFactory.create(channel, data)); + ChannelSettings settings = ChannelRegistryImpl.getSettings(channel); + + if (settings != null && settings.isServerbound()) { + minecraft.getNetworkHandler().sendPacket(packetFactory.create(channel, data)); + } } @FunctionalInterface diff --git a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java index 5c8ad59d..647c0c11 100644 --- a/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java +++ b/libraries/networking/networking-mc18w31a-mc1.14.4/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java @@ -23,6 +23,8 @@ import net.ornithemc.osl.networking.api.PacketBuffers; import net.ornithemc.osl.networking.api.PacketPayload; import net.ornithemc.osl.networking.api.server.ServerPacketListener; +import net.ornithemc.osl.networking.impl.ChannelRegistryImpl; +import net.ornithemc.osl.networking.impl.ChannelSettings; import net.ornithemc.osl.networking.impl.NotOnMainThreadException; import net.ornithemc.osl.networking.impl.PacketFactory; import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; @@ -69,7 +71,7 @@ public static void destroy(MinecraftServer server) { public static final Map CHANNEL_LISTENERS = new LinkedHashMap<>(); public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { - registerListenerImpl(channel, (context, buffer) -> { + registerListenerInternal(channel, (context, buffer) -> { T payload = initializer.get(); payload.read(buffer); @@ -78,17 +80,23 @@ public static void registerListener(NamespacedIdentifi } public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { - registerListenerImpl(channel, listener::handle); + registerListenerInternal(channel, listener::handle); } public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { - registerListenerImpl(channel, (context, buffer) -> listener.handle(context, buffer.readByteArray())); + registerListenerInternal(channel, (context, buffer) -> listener.handle(context, buffer.readByteArray())); } - private static void registerListenerImpl(NamespacedIdentifier channel, ChannelListener listener) { + private static void registerListenerInternal(NamespacedIdentifier channel, ChannelListener listener) { + ChannelSettings settings = ChannelRegistryImpl.getSettings(channel); + + if (settings == null || !settings.isServerbound()) { + throw new IllegalArgumentException("channel \'" + channel + "\' is not server-bound - did you register it with the wrong settings?"); + } + CHANNEL_LISTENERS.compute(channel, (key, value) -> { if (value != null) { - throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); + throw new IllegalArgumentException("there is already a listener on channel \'" + channel + "\'"); } return listener; @@ -344,14 +352,22 @@ private static Iterable collectPlayers(Iterable players, NamespacedIdentifier channel, PacketBuffer data) { - Packet packet = packetFactory.create(channel, data); + ChannelSettings settings = ChannelRegistryImpl.getSettings(channel); + + if (settings != null && settings.isClientbound()) { + Packet packet = packetFactory.create(channel, data); - for (ServerPlayerEntity player : players) { - player.networkHandler.sendPacket(packet); + for (ServerPlayerEntity player : players) { + player.networkHandler.sendPacket(packet); + } } } diff --git a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java index 2866823a..d09f7dbd 100644 --- a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java +++ b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java @@ -6,13 +6,14 @@ import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.networking.api.ChannelIdentifiers; +import net.ornithemc.osl.networking.api.ChannelRegistry; import net.ornithemc.osl.networking.api.PacketBuffer; import net.ornithemc.osl.networking.api.PacketPayload; import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; public class HandshakePayload implements PacketPayload { - public static final NamespacedIdentifier CHANNEL = Constants.OSL_HANDSHAKE_CHANNEL; + public static final NamespacedIdentifier CHANNEL = ChannelRegistry.register(Constants.OSL_HANDSHAKE_CHANNEL); public byte protocol; public Set channels; diff --git a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java index 316284f3..7972bac3 100644 --- a/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java +++ b/libraries/networking/networking-mca1.0.16-mca1.2.6/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java @@ -18,6 +18,8 @@ import net.ornithemc.osl.networking.api.PacketBuffers; import net.ornithemc.osl.networking.api.PacketPayload; import net.ornithemc.osl.networking.api.client.ClientPacketListener; +import net.ornithemc.osl.networking.impl.ChannelRegistryImpl; +import net.ornithemc.osl.networking.impl.ChannelSettings; import net.ornithemc.osl.networking.impl.NotOnMainThreadException; import net.ornithemc.osl.networking.impl.PacketFactory; import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; @@ -65,7 +67,7 @@ public static void destroy(Minecraft minecraft) { public static final Map CHANNEL_LISTENERS = new LinkedHashMap<>(); public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { - registerListenerImpl(channel, (context, bytes) -> { + registerListenerInternal(channel, (context, bytes) -> { T payload = initializer.get(); payload.read(PacketBuffers.wrap(bytes)); @@ -74,17 +76,23 @@ public static void registerListener(NamespacedIdentifi } public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { - registerListenerImpl(channel, (context, bytes) -> listener.handle(context, PacketBuffers.wrap(bytes))); + registerListenerInternal(channel, (context, bytes) -> listener.handle(context, PacketBuffers.wrap(bytes))); } public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { - registerListenerImpl(channel, listener::handle); + registerListenerInternal(channel, listener::handle); } - private static void registerListenerImpl(NamespacedIdentifier channel, ChannelListener listener) { + private static void registerListenerInternal(NamespacedIdentifier channel, ChannelListener listener) { + ChannelSettings settings = ChannelRegistryImpl.getSettings(channel); + + if (settings == null || !settings.isClientbound()) { + throw new IllegalArgumentException("channel \'" + channel + "\' is not client-bound - did you register it with the wrong settings?"); + } + CHANNEL_LISTENERS.compute(channel, (key, value) -> { if (value != null) { - throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); + throw new IllegalArgumentException("there is already a listener on channel \'" + channel + "\'"); } return listener; @@ -205,7 +213,11 @@ private static void sendInternal(NamespacedIdentifier channel, byte[] bytes) { } private static void sendPacket(NamespacedIdentifier channel, byte[] data) { - networkHandler().sendPacket(packetFactory.create(channel, data)); + ChannelSettings settings = ChannelRegistryImpl.getSettings(channel); + + if (settings != null && settings.isServerbound()) { + networkHandler().sendPacket(packetFactory.create(channel, data)); + } } @FunctionalInterface diff --git a/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java index 27d46bc9..a9bbf2ba 100644 --- a/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java +++ b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java @@ -6,6 +6,7 @@ import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.networking.api.ChannelIdentifiers; +import net.ornithemc.osl.networking.api.ChannelRegistry; import net.ornithemc.osl.networking.api.PacketBuffer; import net.ornithemc.osl.networking.api.PacketPayload; import net.ornithemc.osl.networking.impl.client.ClientPlayNetworkingImpl; @@ -13,7 +14,7 @@ public class HandshakePayload implements PacketPayload { - public static final NamespacedIdentifier CHANNEL = Constants.OSL_HANDSHAKE_CHANNEL; + public static final NamespacedIdentifier CHANNEL = ChannelRegistry.register(Constants.OSL_HANDSHAKE_CHANNEL); public byte protocol; public Set channels; diff --git a/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java index 40c4bc76..1421579f 100644 --- a/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java +++ b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/client/ClientPlayNetworkingImpl.java @@ -18,6 +18,8 @@ import net.ornithemc.osl.networking.api.PacketBuffers; import net.ornithemc.osl.networking.api.PacketPayload; import net.ornithemc.osl.networking.api.client.ClientPacketListener; +import net.ornithemc.osl.networking.impl.ChannelRegistryImpl; +import net.ornithemc.osl.networking.impl.ChannelSettings; import net.ornithemc.osl.networking.impl.NotOnMainThreadException; import net.ornithemc.osl.networking.impl.PacketFactory; import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; @@ -64,7 +66,7 @@ public static void destroy(Minecraft minecraft) { public static final Map CHANNEL_LISTENERS = new LinkedHashMap<>(); public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ClientPacketListener.Payload listener) { - registerListenerImpl(channel, (context, bytes) -> { + registerListenerInternal(channel, (context, bytes) -> { T payload = initializer.get(); payload.read(PacketBuffers.wrap(bytes)); @@ -73,17 +75,23 @@ public static void registerListener(NamespacedIdentifi } public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Buffer listener) { - registerListenerImpl(channel, (context, bytes) -> listener.handle(context, PacketBuffers.wrap(bytes))); + registerListenerInternal(channel, (context, bytes) -> listener.handle(context, PacketBuffers.wrap(bytes))); } public static void registerListener(NamespacedIdentifier channel, ClientPacketListener.Bytes listener) { - registerListenerImpl(channel, listener::handle); + registerListenerInternal(channel, listener::handle); } - private static void registerListenerImpl(NamespacedIdentifier channel, ChannelListener listener) { + private static void registerListenerInternal(NamespacedIdentifier channel, ChannelListener listener) { + ChannelSettings settings = ChannelRegistryImpl.getSettings(channel); + + if (settings == null || !settings.isClientbound()) { + throw new IllegalArgumentException("channel \'" + channel + "\' is not client-bound - did you register it with the wrong settings?"); + } + CHANNEL_LISTENERS.compute(channel, (key, value) -> { if (value != null) { - throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); + throw new IllegalArgumentException("there is already a listener on channel \'" + channel + "\'"); } return listener; @@ -199,7 +207,11 @@ private static void sendInternal(NamespacedIdentifier channel, byte[] bytes) { } private static void sendPacket(NamespacedIdentifier channel, byte[] data) { - minecraft.getNetworkHandler().sendPacket(packetFactory.create(channel, data)); + ChannelSettings settings = ChannelRegistryImpl.getSettings(channel); + + if (settings != null && settings.isServerbound()) { + minecraft.getNetworkHandler().sendPacket(packetFactory.create(channel, data)); + } } @FunctionalInterface diff --git a/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java index 0df44086..40674912 100644 --- a/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java +++ b/libraries/networking/networking-mcb1.0-mc13w39b/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java @@ -22,6 +22,8 @@ import net.ornithemc.osl.networking.api.PacketBuffers; import net.ornithemc.osl.networking.api.PacketPayload; import net.ornithemc.osl.networking.api.server.ServerPacketListener; +import net.ornithemc.osl.networking.impl.ChannelRegistryImpl; +import net.ornithemc.osl.networking.impl.ChannelSettings; import net.ornithemc.osl.networking.impl.NotOnMainThreadException; import net.ornithemc.osl.networking.impl.PacketFactory; import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; @@ -68,7 +70,7 @@ public static void destroy(MinecraftServer server) { public static final Map CHANNEL_LISTENERS = new LinkedHashMap<>(); public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { - registerListenerImpl(channel, (context, bytes) -> { + registerListenerInternal(channel, (context, bytes) -> { T payload = initializer.get(); payload.read(PacketBuffers.wrap(bytes)); @@ -77,17 +79,23 @@ public static void registerListener(NamespacedIdentifi } public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { - registerListenerImpl(channel, (context, bytes) -> listener.handle(context, PacketBuffers.wrap(bytes))); + registerListenerInternal(channel, (context, bytes) -> listener.handle(context, PacketBuffers.wrap(bytes))); } public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { - registerListenerImpl(channel, listener::handle); + registerListenerInternal(channel, listener::handle); } - private static void registerListenerImpl(NamespacedIdentifier channel, ChannelListener listener) { + private static void registerListenerInternal(NamespacedIdentifier channel, ChannelListener listener) { + ChannelSettings settings = ChannelRegistryImpl.getSettings(channel); + + if (settings == null || !settings.isServerbound()) { + throw new IllegalArgumentException("channel \'" + channel + "\' is not server-bound - did you register it with the wrong settings?"); + } + CHANNEL_LISTENERS.compute(channel, (key, value) -> { if (value != null) { - throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); + throw new IllegalArgumentException("there is already a listener on channel \'" + channel + "\'"); } return listener; @@ -343,14 +351,22 @@ private static Iterable collectPlayers(Iterable players, NamespacedIdentifier channel, byte[] data) { - Packet packet = packetFactory.create(channel, data); + ChannelSettings settings = ChannelRegistryImpl.getSettings(channel); + + if (settings != null && settings.isClientbound()) { + Packet packet = packetFactory.create(channel, data); - for (ServerPlayerEntity player : players) { - player.networkHandler.sendPacket(packet); + for (ServerPlayerEntity player : players) { + player.networkHandler.sendPacket(packet); + } } } diff --git a/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java index 1c65baa7..c07137a5 100644 --- a/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java +++ b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java @@ -6,13 +6,14 @@ import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.networking.api.ChannelIdentifiers; +import net.ornithemc.osl.networking.api.ChannelRegistry; import net.ornithemc.osl.networking.api.PacketBuffer; import net.ornithemc.osl.networking.api.PacketPayload; import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; public class HandshakePayload implements PacketPayload { - public static final NamespacedIdentifier CHANNEL = Constants.OSL_HANDSHAKE_CHANNEL; + public static final NamespacedIdentifier CHANNEL = ChannelRegistry.register(Constants.OSL_HANDSHAKE_CHANNEL); public byte protocol; public Set channels; diff --git a/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java index 6f39e27c..218a1e67 100644 --- a/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java +++ b/libraries/networking/networking-mcserver-a0.1.0-mcserver-a0.2.1/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java @@ -22,6 +22,8 @@ import net.ornithemc.osl.networking.api.PacketBuffers; import net.ornithemc.osl.networking.api.PacketPayload; import net.ornithemc.osl.networking.api.server.ServerPacketListener; +import net.ornithemc.osl.networking.impl.ChannelRegistryImpl; +import net.ornithemc.osl.networking.impl.ChannelSettings; import net.ornithemc.osl.networking.impl.NotOnMainThreadException; import net.ornithemc.osl.networking.impl.PacketFactory; import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; @@ -68,7 +70,7 @@ public static void destroy(MinecraftServer server) { public static final Map CHANNEL_LISTENERS = new LinkedHashMap<>(); public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { - registerListenerImpl(channel, (context, bytes) -> { + registerListenerInternal(channel, (context, bytes) -> { T payload = initializer.get(); payload.read(PacketBuffers.wrap(bytes)); @@ -77,17 +79,23 @@ public static void registerListener(NamespacedIdentifi } public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { - registerListenerImpl(channel, (context, bytes) -> listener.handle(context, PacketBuffers.wrap(bytes))); + registerListenerInternal(channel, (context, bytes) -> listener.handle(context, PacketBuffers.wrap(bytes))); } public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { - registerListenerImpl(channel, listener::handle); + registerListenerInternal(channel, listener::handle); } - private static void registerListenerImpl(NamespacedIdentifier channel, ChannelListener listener) { + private static void registerListenerInternal(NamespacedIdentifier channel, ChannelListener listener) { + ChannelSettings settings = ChannelRegistryImpl.getSettings(channel); + + if (settings == null || !settings.isServerbound()) { + throw new IllegalArgumentException("channel \'" + channel + "\' is not server-bound - did you register it with the wrong settings?"); + } + CHANNEL_LISTENERS.compute(channel, (key, value) -> { if (value != null) { - throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); + throw new IllegalArgumentException("there is already a listener on channel \'" + channel + "\'"); } return listener; @@ -311,14 +319,22 @@ private static Iterable collectPlayers(Iterable players, NamespacedIdentifier channel, byte[] data) { - Packet packet = packetFactory.create(channel, data); + ChannelSettings settings = ChannelRegistryImpl.getSettings(channel); + + if (settings != null && settings.isClientbound()) { + Packet packet = packetFactory.create(channel, data); - for (ServerPlayerEntity player : players) { - player.networkHandler.sendPacket(packet); + for (ServerPlayerEntity player : players) { + player.networkHandler.sendPacket(packet); + } } } diff --git a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java index 1c65baa7..c07137a5 100644 --- a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java +++ b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/HandshakePayload.java @@ -6,13 +6,14 @@ import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.networking.api.ChannelIdentifiers; +import net.ornithemc.osl.networking.api.ChannelRegistry; import net.ornithemc.osl.networking.api.PacketBuffer; import net.ornithemc.osl.networking.api.PacketPayload; import net.ornithemc.osl.networking.impl.server.ServerPlayNetworkingImpl; public class HandshakePayload implements PacketPayload { - public static final NamespacedIdentifier CHANNEL = Constants.OSL_HANDSHAKE_CHANNEL; + public static final NamespacedIdentifier CHANNEL = ChannelRegistry.register(Constants.OSL_HANDSHAKE_CHANNEL); public byte protocol; public Set channels; diff --git a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java index 23340806..fd016d8b 100644 --- a/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java +++ b/libraries/networking/networking-mcserver-a0.2.2-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/networking/impl/server/ServerPlayNetworkingImpl.java @@ -22,6 +22,8 @@ import net.ornithemc.osl.networking.api.PacketBuffers; import net.ornithemc.osl.networking.api.PacketPayload; import net.ornithemc.osl.networking.api.server.ServerPacketListener; +import net.ornithemc.osl.networking.impl.ChannelRegistryImpl; +import net.ornithemc.osl.networking.impl.ChannelSettings; import net.ornithemc.osl.networking.impl.NotOnMainThreadException; import net.ornithemc.osl.networking.impl.PacketFactory; import net.ornithemc.osl.networking.impl.access.CustomPayloadPacketAccess; @@ -68,7 +70,7 @@ public static void destroy(MinecraftServer server) { public static final Map CHANNEL_LISTENERS = new LinkedHashMap<>(); public static void registerListener(NamespacedIdentifier channel, Supplier initializer, ServerPacketListener.Payload listener) { - registerListenerImpl(channel, (context, bytes) -> { + registerListenerInternal(channel, (context, bytes) -> { T payload = initializer.get(); payload.read(PacketBuffers.wrap(bytes)); @@ -77,17 +79,23 @@ public static void registerListener(NamespacedIdentifi } public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Buffer listener) { - registerListenerImpl(channel, (context, bytes) -> listener.handle(context, PacketBuffers.wrap(bytes))); + registerListenerInternal(channel, (context, bytes) -> listener.handle(context, PacketBuffers.wrap(bytes))); } public static void registerListener(NamespacedIdentifier channel, ServerPacketListener.Bytes listener) { - registerListenerImpl(channel, listener::handle); + registerListenerInternal(channel, listener::handle); } - private static void registerListenerImpl(NamespacedIdentifier channel, ChannelListener listener) { + private static void registerListenerInternal(NamespacedIdentifier channel, ChannelListener listener) { + ChannelSettings settings = ChannelRegistryImpl.getSettings(channel); + + if (settings == null || !settings.isServerbound()) { + throw new IllegalArgumentException("channel \'" + channel + "\' is not server-bound - did you register it with the wrong settings?"); + } + CHANNEL_LISTENERS.compute(channel, (key, value) -> { if (value != null) { - throw new IllegalStateException("there is already a listener on channel \'" + channel + "\'"); + throw new IllegalArgumentException("there is already a listener on channel \'" + channel + "\'"); } return listener; @@ -343,14 +351,22 @@ private static Iterable collectPlayers(Iterable players, NamespacedIdentifier channel, byte[] data) { - Packet packet = packetFactory.create(channel, data); + ChannelSettings settings = ChannelRegistryImpl.getSettings(channel); + + if (settings != null && settings.isClientbound()) { + Packet packet = packetFactory.create(channel, data); - for (ServerPlayerEntity player : players) { - player.networkHandler.sendPacket(packet); + for (ServerPlayerEntity player : players) { + player.networkHandler.sendPacket(packet); + } } } diff --git a/libraries/networking/src/main/java/net/ornithemc/osl/networking/api/ChannelRegistry.java b/libraries/networking/src/main/java/net/ornithemc/osl/networking/api/ChannelRegistry.java new file mode 100644 index 00000000..d499e4b8 --- /dev/null +++ b/libraries/networking/src/main/java/net/ornithemc/osl/networking/api/ChannelRegistry.java @@ -0,0 +1,36 @@ +package net.ornithemc.osl.networking.api; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; +import net.ornithemc.osl.networking.impl.ChannelRegistryImpl; + +public final class ChannelRegistry { + + /** + * Register a channel with default settings. This means the channel will accept + * both client-bound and server-bound packets. For finer control over channel + * settings, see {@linkplain #register(NamespacedIdentifier, boolean, boolean)}. + * + * @return the registered channel. + */ + public static NamespacedIdentifier register(NamespacedIdentifier channel) { + return ChannelRegistryImpl.register(channel); + } + + /** + * Register a channel with the given settings. + *

+ * A channel should be marked as client-bound if the client is expected to + * receive and handle packets sent over that channel. + *
+ * A channel should be marked as server-bound if the server is expected to + * receive and handle packets sent over that channel. + *

+ * A channel that has not been registered can not have any listeners and is + * considered 'closed'. + * + * @return the registered channel. + */ + public static NamespacedIdentifier register(NamespacedIdentifier channel, boolean clientbound, boolean serverbound) { + return ChannelRegistryImpl.register(channel, clientbound, serverbound); + } +} diff --git a/libraries/networking/src/main/java/net/ornithemc/osl/networking/impl/ChannelRegistryImpl.java b/libraries/networking/src/main/java/net/ornithemc/osl/networking/impl/ChannelRegistryImpl.java new file mode 100644 index 00000000..59f19d2b --- /dev/null +++ b/libraries/networking/src/main/java/net/ornithemc/osl/networking/impl/ChannelRegistryImpl.java @@ -0,0 +1,39 @@ +package net.ornithemc.osl.networking.impl; + +import java.util.HashMap; +import java.util.Map; + +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; + +public final class ChannelRegistryImpl { + + private static final Map SETTINGS = new HashMap<>(); + + public static NamespacedIdentifier register(NamespacedIdentifier channel) { + return register(channel, new ChannelSettings()); + } + + public static NamespacedIdentifier register(NamespacedIdentifier channel, boolean clientbound, boolean serverbound) { + return register(channel, new ChannelSettings(clientbound, serverbound)); + } + + public static NamespacedIdentifier register(NamespacedIdentifier channel, ChannelSettings settings) { + SETTINGS.compute(channel, (key, value) -> { + if (value != null && !value.is(settings)) { + throw new IllegalArgumentException("channel \'" + channel + "\' was already registered with different settings!"); + } + + return settings; + }); + + return channel; + } + + public static boolean contains(NamespacedIdentifier channel) { + return SETTINGS.containsKey(channel); + } + + public static ChannelSettings getSettings(NamespacedIdentifier channel) { + return SETTINGS.get(channel); + } +} diff --git a/libraries/networking/src/main/java/net/ornithemc/osl/networking/impl/ChannelSettings.java b/libraries/networking/src/main/java/net/ornithemc/osl/networking/impl/ChannelSettings.java new file mode 100644 index 00000000..6c976148 --- /dev/null +++ b/libraries/networking/src/main/java/net/ornithemc/osl/networking/impl/ChannelSettings.java @@ -0,0 +1,31 @@ +package net.ornithemc.osl.networking.impl; + +public final class ChannelSettings { + + private final boolean clientbound; + private final boolean serverbound; + + public ChannelSettings() { + this(true, true); + } + + public ChannelSettings(boolean clientbound, boolean serverbound) { + this.clientbound = clientbound; + this.serverbound = serverbound; + } + + public boolean is(ChannelSettings o) { + if (this == o) { + return true; + } + return clientbound == o.clientbound && serverbound == o.serverbound; + } + + public boolean isClientbound() { + return clientbound; + } + + public boolean isServerbound() { + return serverbound; + } +} From 85066094a04423c553e79147e29fa8300a48b207 Mon Sep 17 00:00:00 2001 From: Space Walker Date: Sun, 7 Dec 2025 16:53:09 +0100 Subject: [PATCH 7/8] update Networking API README --- libraries/networking/README.md | 52 +++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 11 deletions(-) diff --git a/libraries/networking/README.md b/libraries/networking/README.md index d017563f..329edc42 100644 --- a/libraries/networking/README.md +++ b/libraries/networking/README.md @@ -17,22 +17,39 @@ are also fired for connections to integrated servers. ## Networking Sending and receiving data is done through the `ClientPlayNetworking` and `ServerPlayNetworking` classes. -Mods can register network listeners through the `registerListener` and `registerListenerAsync` methods, -allowing them to receive data through specific channels. Sending data is done through the `send` methods. +Mods can register packet listeners through the `registerListener` methods, and send data through the `send` methods. -Each custom payload is tied to a channel. Only connections that have listeners on that channel will receive the payload, and on the receiving end, the payload will only be handled by the listener on that channel. In Minecraft versions 1.13-pre2 and below, a channel can be any `String` of length 20 or less. In Minecraft versions 1.13-pre4 and above, a channel can be any valid `Identifier`. For `String` channels, the convention is `<(abbreviated) mod id>|` (e.g. `Example|Cookie`), while for `Identifier` channels, the convention is `:` (e.g. `example:cookie`). +Custom payloads are sent over specific channels. Channels are namespaced identifiers, used to identify the payload being sent or received. +Channels identifiers should be constructed through the `ChannelIdentifieres` class. The convention is to use your mod id as the namespace, +and snake case for the identifier. -For ease of use data can be wrapped in custom payload objects. These must implement the `CustomPayload` interface -and must have a public construcor without parameters. An example can be seen below. +```java +public static final NamespacedIdentifier COOKIE_CHANNEL = ChannelIdentifiers.from("example", "cookie"); +``` + +You are expected to register your channels through the `ChannelRegistry`. + +```java +ChannelRegistry.register(COOKIE_CHANNEL); +``` + +You are expected to register your packet listeners in your mod initializer through `ClientPlayNetworking` and `ServerPlayNetworking`. + +```java +ClientPlayNetworking.registerListener(COOKIE_CHANNEL, (context, buffer) -> { }); +``` + +For ease of use data can be wrapped in custom payload objects. +These must implement the `CustomPayload` interface and must have a public constructor without parameters. +An example can be seen below. ```java package com.example; import java.io.IOException; -import net.minecraft.network.PacketByteBuf; - import net.ornithemc.osl.networking.api.CustomPayload; +import net.ornithemc.osl.networking.api.PacketBuffer; public class CookiePayload implements CustomPayload { @@ -46,30 +63,43 @@ public class CookiePayload implements CustomPayload { } @Override - public void read(PacketByteBuf buffer) throws IOException { + public void read(PacketBuffer buffer) throws IOException { // deserialize data } @Override - public void write(PacketByteBuf buffer) throws IOException { + public void write(PacketBuffer buffer) throws IOException { // serialize data } } ``` -Listeners for these custom payload objects can be registered as follows: +A basic networking setup might look as follows. + ```java package com.example; +import net.ornithemc.osl.core.api.util.NamespacedIdentifier; import net.ornithemc.osl.entrypoints.api.ModInitializer; +import net.ornithemc.osl.networking.api.ChannelIdentifiers; import net.ornithemc.osl.networking.api.client.ClientPlayNetworking; public class ExampleInitializer implements ModInitializer { + public static final NamespacedIdentifier COOKIE_CHANNEL = ChannelIdentifiers.from("example", "cookie"); + @Override public void init() { - ClientPlayNetworking.registerListener("Example|Cookie", CookiePayload::new, (minecraft, handler, payload) -> { + ChannelRegistry.register(COOKIE_CHANNEL, true, false); + } + + @Override + public void initClient() { + ClientPlayNetworking.registerListener(COOKIE_CHANNEL, CookiePayload::new, (context, payload) -> { + // ensure this listener is running on the main thread + context.ensureOnMainThread(); + // handle custom payload }); } From 677ee3d2b9ca81dde21c132927d2d58a5f7bdcc6 Mon Sep 17 00:00:00 2001 From: Space Walker Date: Tue, 16 Dec 2025 17:09:00 +0100 Subject: [PATCH 8/8] [lifecycle events] add MinecraftServer instance API --- .../api/server/MinecraftServerInstance.java | 21 +++++++++++ .../mixin/server/MinecraftServerMixin.java | 35 ++++++++++++------ .../impl/server/MinecraftServerAccess.java | 16 ++++++++ .../api/server/MinecraftServerInstance.java | 21 +++++++++++ .../mixin/common/MinecraftServerMixin.java | 35 ++++++++++++------ .../impl/server/MinecraftServerAccess.java | 16 ++++++++ .../api/server/MinecraftServerInstance.java | 21 +++++++++++ .../mixin/common/MinecraftServerMixin.java | 35 ++++++++++++------ .../impl/server/MinecraftServerAccess.java | 16 ++++++++ .../api/server/MinecraftServerInstance.java | 21 +++++++++++ .../mixin/common/MinecraftServerMixin.java | 35 ++++++++++++------ .../impl/server/MinecraftServerAccess.java | 16 ++++++++ .../api/server/MinecraftServerInstance.java | 21 +++++++++++ .../mixin/common/MinecraftServerMixin.java | 37 +++++++++++++------ .../impl/server/MinecraftServerAccess.java | 16 ++++++++ .../api/server/MinecraftServerInstance.java | 21 +++++++++++ .../mixin/common/MinecraftServerMixin.java | 37 +++++++++++++------ .../impl/server/MinecraftServerAccess.java | 16 ++++++++ .../api/server/MinecraftServerInstance.java | 21 +++++++++++ .../mixin/server/MinecraftServerMixin.java | 35 ++++++++++++------ .../impl/server/MinecraftServerAccess.java | 16 ++++++++ .../api/server/MinecraftServerInstance.java | 21 +++++++++++ .../mixin/server/MinecraftServerMixin.java | 35 ++++++++++++------ .../impl/server/MinecraftServerAccess.java | 16 ++++++++ .../api/server/MinecraftServerInstance.java | 21 +++++++++++ .../mixin/server/MinecraftServerMixin.java | 35 ++++++++++++------ .../impl/server/MinecraftServerAccess.java | 16 ++++++++ .../api/server/MinecraftServerInstance.java | 21 +++++++++++ .../mixin/server/MinecraftServerMixin.java | 35 ++++++++++++------ .../impl/server/MinecraftServerAccess.java | 16 ++++++++ .../api/server/MinecraftServerInstance.java | 21 +++++++++++ .../mixin/server/MinecraftServerMixin.java | 35 ++++++++++++------ .../impl/server/MinecraftServerAccess.java | 16 ++++++++ 33 files changed, 673 insertions(+), 123 deletions(-) create mode 100644 libraries/lifecycle-events/lifecycle-events-mc12w01a-mc12w17a/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java create mode 100644 libraries/lifecycle-events/lifecycle-events-mc12w01a-mc12w17a/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java create mode 100644 libraries/lifecycle-events/lifecycle-events-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java create mode 100644 libraries/lifecycle-events/lifecycle-events-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java create mode 100644 libraries/lifecycle-events/lifecycle-events-mc12w21a-mc1.6.4/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java create mode 100644 libraries/lifecycle-events/lifecycle-events-mc12w21a-mc1.6.4/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java create mode 100644 libraries/lifecycle-events/lifecycle-events-mc13w36a-09051446-mc1.13/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java create mode 100644 libraries/lifecycle-events/lifecycle-events-mc13w36a-09051446-mc1.13/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java create mode 100644 libraries/lifecycle-events/lifecycle-events-mc18w30a-mc18w50a/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java create mode 100644 libraries/lifecycle-events/lifecycle-events-mc18w30a-mc18w50a/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java create mode 100644 libraries/lifecycle-events/lifecycle-events-mc19w04a-mc1.14.4/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java create mode 100644 libraries/lifecycle-events/lifecycle-events-mc19w04a-mc1.14.4/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java create mode 100644 libraries/lifecycle-events/lifecycle-events-mcb1.0-mcb1.2_02/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java create mode 100644 libraries/lifecycle-events/lifecycle-events-mcb1.0-mcb1.2_02/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java create mode 100644 libraries/lifecycle-events/lifecycle-events-mcb1.4-1507-mcb1.7.3/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java create mode 100644 libraries/lifecycle-events/lifecycle-events-mcb1.4-1507-mcb1.7.3/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java create mode 100644 libraries/lifecycle-events/lifecycle-events-mcb1.8-pre1-201109081459-mc11w50a/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java create mode 100644 libraries/lifecycle-events/lifecycle-events-mcb1.8-pre1-201109081459-mc11w50a/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java create mode 100644 libraries/lifecycle-events/lifecycle-events-mcserver-a0.1.0-mcserver-a0.1.4/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java create mode 100644 libraries/lifecycle-events/lifecycle-events-mcserver-a0.1.0-mcserver-a0.1.4/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java create mode 100644 libraries/lifecycle-events/lifecycle-events-mcserver-a0.2.0-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java create mode 100644 libraries/lifecycle-events/lifecycle-events-mcserver-a0.2.0-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java diff --git a/libraries/lifecycle-events/lifecycle-events-mc12w01a-mc12w17a/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java b/libraries/lifecycle-events/lifecycle-events-mc12w01a-mc12w17a/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java new file mode 100644 index 00000000..be030e30 --- /dev/null +++ b/libraries/lifecycle-events/lifecycle-events-mc12w01a-mc12w17a/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java @@ -0,0 +1,21 @@ +package net.ornithemc.osl.lifecycle.api.server; + +import net.minecraft.server.MinecraftServer; + +import net.ornithemc.osl.lifecycle.impl.server.MinecraftServerAccess; + +/** + * A wrapper class for getting the {@linkplain MinecraftServer} instance. + */ +public class MinecraftServerInstance { + + /** + * Retrieves the current Minecraft server instance, + * or throws an exception. + * + * @return the current Minecraft server instance + */ + public static MinecraftServer get() { + return MinecraftServerAccess.getInstance(); + } +} diff --git a/libraries/lifecycle-events/lifecycle-events-mc12w01a-mc12w17a/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/server/MinecraftServerMixin.java b/libraries/lifecycle-events/lifecycle-events-mc12w01a-mc12w17a/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/server/MinecraftServerMixin.java index 84b106ee..cde5852a 100644 --- a/libraries/lifecycle-events/lifecycle-events-mc12w01a-mc12w17a/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/server/MinecraftServerMixin.java +++ b/libraries/lifecycle-events/lifecycle-events-mc12w01a-mc12w17a/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/server/MinecraftServerMixin.java @@ -10,11 +10,12 @@ import net.minecraft.server.MinecraftServer; import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; +import net.ornithemc.osl.lifecycle.impl.server.MinecraftServerAccess; @Mixin(MinecraftServer.class) public class MinecraftServerMixin { - @Unique private boolean osl$lifecycle$stopped; + @Unique private int osl$lifecycle$shutdownDepth; @Inject( method = "run", @@ -23,7 +24,8 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$start(CallbackInfo ci) { - MinecraftServerEvents.START.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerAccess.INSTANCE = (MinecraftServer)(Object)this; + MinecraftServerEvents.START.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -35,7 +37,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$ready(CallbackInfo ci) { - MinecraftServerEvents.READY.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.READY.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -45,9 +47,20 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$stop(CallbackInfo ci) { - if (!osl$lifecycle$stopped) { - osl$lifecycle$stopped = true; - MinecraftServerEvents.STOP.invoker().accept((MinecraftServer)(Object)this); + if (osl$lifecycle$shutdownDepth++ == 0) { + MinecraftServerEvents.STOP.invoker().accept(MinecraftServerAccess.INSTANCE); + } + } + + @Inject( + method = "shutdown", + at = @At( + value = "HEAD" + ) + ) + private void osl$lifecycle$stopped(CallbackInfo ci) { + if (--osl$lifecycle$shutdownDepth == 0) { + MinecraftServerAccess.INSTANCE = null; } } @@ -58,7 +71,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$startTick(CallbackInfo ci) { - MinecraftServerEvents.TICK_START.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.TICK_START.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -68,7 +81,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$endTick(CallbackInfo ci) { - MinecraftServerEvents.TICK_END.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.TICK_END.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -78,7 +91,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$loadWorld(CallbackInfo ci) { - MinecraftServerEvents.LOAD_WORLD.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.LOAD_WORLD.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -91,7 +104,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$prepareWorld(CallbackInfo ci) { - MinecraftServerEvents.PREPARE_WORLD.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.PREPARE_WORLD.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -101,6 +114,6 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$readyWorld(CallbackInfo ci) { - MinecraftServerEvents.READY_WORLD.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.READY_WORLD.invoker().accept(MinecraftServerAccess.INSTANCE); } } diff --git a/libraries/lifecycle-events/lifecycle-events-mc12w01a-mc12w17a/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java b/libraries/lifecycle-events/lifecycle-events-mc12w01a-mc12w17a/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java new file mode 100644 index 00000000..eb9c5e2b --- /dev/null +++ b/libraries/lifecycle-events/lifecycle-events-mc12w01a-mc12w17a/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java @@ -0,0 +1,16 @@ +package net.ornithemc.osl.lifecycle.impl.server; + +import net.minecraft.server.MinecraftServer; + +public class MinecraftServerAccess { + + public static MinecraftServer INSTANCE; + + public static MinecraftServer getInstance() { + if (INSTANCE == null) { + throw new IllegalStateException("no MinecraftServer instance available right now"); + } + + return INSTANCE; + } +} diff --git a/libraries/lifecycle-events/lifecycle-events-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java b/libraries/lifecycle-events/lifecycle-events-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java new file mode 100644 index 00000000..be030e30 --- /dev/null +++ b/libraries/lifecycle-events/lifecycle-events-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java @@ -0,0 +1,21 @@ +package net.ornithemc.osl.lifecycle.api.server; + +import net.minecraft.server.MinecraftServer; + +import net.ornithemc.osl.lifecycle.impl.server.MinecraftServerAccess; + +/** + * A wrapper class for getting the {@linkplain MinecraftServer} instance. + */ +public class MinecraftServerInstance { + + /** + * Retrieves the current Minecraft server instance, + * or throws an exception. + * + * @return the current Minecraft server instance + */ + public static MinecraftServer get() { + return MinecraftServerAccess.getInstance(); + } +} diff --git a/libraries/lifecycle-events/lifecycle-events-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/common/MinecraftServerMixin.java b/libraries/lifecycle-events/lifecycle-events-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/common/MinecraftServerMixin.java index 607cc6a3..4380fc76 100644 --- a/libraries/lifecycle-events/lifecycle-events-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/common/MinecraftServerMixin.java +++ b/libraries/lifecycle-events/lifecycle-events-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/common/MinecraftServerMixin.java @@ -10,11 +10,12 @@ import net.minecraft.server.MinecraftServer; import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; +import net.ornithemc.osl.lifecycle.impl.server.MinecraftServerAccess; @Mixin(MinecraftServer.class) public class MinecraftServerMixin { - @Unique private boolean osl$lifecycle$stopped; + @Unique private int osl$lifecycle$shutdownDepth; @Inject( method = "run", @@ -23,7 +24,8 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$start(CallbackInfo ci) { - MinecraftServerEvents.START.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerAccess.INSTANCE = (MinecraftServer)(Object)this; + MinecraftServerEvents.START.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -35,7 +37,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$ready(CallbackInfo ci) { - MinecraftServerEvents.READY.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.READY.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -45,9 +47,20 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$stop(CallbackInfo ci) { - if (!osl$lifecycle$stopped) { - osl$lifecycle$stopped = true; - MinecraftServerEvents.STOP.invoker().accept((MinecraftServer)(Object)this); + if (osl$lifecycle$shutdownDepth++ == 0) { + MinecraftServerEvents.STOP.invoker().accept(MinecraftServerAccess.INSTANCE); + } + } + + @Inject( + method = "shutdown", + at = @At( + value = "HEAD" + ) + ) + private void osl$lifecycle$stopped(CallbackInfo ci) { + if (--osl$lifecycle$shutdownDepth == 0) { + MinecraftServerAccess.INSTANCE = null; } } @@ -58,7 +71,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$startTick(CallbackInfo ci) { - MinecraftServerEvents.TICK_START.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.TICK_START.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -68,7 +81,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$endTick(CallbackInfo ci) { - MinecraftServerEvents.TICK_END.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.TICK_END.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -78,7 +91,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$loadWorld(CallbackInfo ci) { - MinecraftServerEvents.LOAD_WORLD.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.LOAD_WORLD.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -91,7 +104,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$prepareWorld(CallbackInfo ci) { - MinecraftServerEvents.PREPARE_WORLD.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.PREPARE_WORLD.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -101,6 +114,6 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$readyWorld(CallbackInfo ci) { - MinecraftServerEvents.READY_WORLD.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.READY_WORLD.invoker().accept(MinecraftServerAccess.INSTANCE); } } diff --git a/libraries/lifecycle-events/lifecycle-events-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java b/libraries/lifecycle-events/lifecycle-events-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java new file mode 100644 index 00000000..eb9c5e2b --- /dev/null +++ b/libraries/lifecycle-events/lifecycle-events-mc12w18a-mc12w19a/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java @@ -0,0 +1,16 @@ +package net.ornithemc.osl.lifecycle.impl.server; + +import net.minecraft.server.MinecraftServer; + +public class MinecraftServerAccess { + + public static MinecraftServer INSTANCE; + + public static MinecraftServer getInstance() { + if (INSTANCE == null) { + throw new IllegalStateException("no MinecraftServer instance available right now"); + } + + return INSTANCE; + } +} diff --git a/libraries/lifecycle-events/lifecycle-events-mc12w21a-mc1.6.4/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java b/libraries/lifecycle-events/lifecycle-events-mc12w21a-mc1.6.4/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java new file mode 100644 index 00000000..be030e30 --- /dev/null +++ b/libraries/lifecycle-events/lifecycle-events-mc12w21a-mc1.6.4/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java @@ -0,0 +1,21 @@ +package net.ornithemc.osl.lifecycle.api.server; + +import net.minecraft.server.MinecraftServer; + +import net.ornithemc.osl.lifecycle.impl.server.MinecraftServerAccess; + +/** + * A wrapper class for getting the {@linkplain MinecraftServer} instance. + */ +public class MinecraftServerInstance { + + /** + * Retrieves the current Minecraft server instance, + * or throws an exception. + * + * @return the current Minecraft server instance + */ + public static MinecraftServer get() { + return MinecraftServerAccess.getInstance(); + } +} diff --git a/libraries/lifecycle-events/lifecycle-events-mc12w21a-mc1.6.4/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/common/MinecraftServerMixin.java b/libraries/lifecycle-events/lifecycle-events-mc12w21a-mc1.6.4/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/common/MinecraftServerMixin.java index a17b3451..23a39ca3 100644 --- a/libraries/lifecycle-events/lifecycle-events-mc12w21a-mc1.6.4/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/common/MinecraftServerMixin.java +++ b/libraries/lifecycle-events/lifecycle-events-mc12w21a-mc1.6.4/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/common/MinecraftServerMixin.java @@ -10,11 +10,12 @@ import net.minecraft.server.MinecraftServer; import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; +import net.ornithemc.osl.lifecycle.impl.server.MinecraftServerAccess; @Mixin(MinecraftServer.class) public class MinecraftServerMixin { - @Unique private boolean osl$lifecycle$stopped; + @Unique private int osl$lifecycle$shutdownDepth; @Inject( method = "run", @@ -23,7 +24,8 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$start(CallbackInfo ci) { - MinecraftServerEvents.START.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerAccess.INSTANCE = (MinecraftServer)(Object)this; + MinecraftServerEvents.START.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -35,7 +37,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$ready(CallbackInfo ci) { - MinecraftServerEvents.READY.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.READY.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -45,9 +47,20 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$stop(CallbackInfo ci) { - if (!osl$lifecycle$stopped) { - osl$lifecycle$stopped = true; - MinecraftServerEvents.STOP.invoker().accept((MinecraftServer)(Object)this); + if (osl$lifecycle$shutdownDepth++ == 0) { + MinecraftServerEvents.STOP.invoker().accept(MinecraftServerAccess.INSTANCE); + } + } + + @Inject( + method = "shutdown", + at = @At( + value = "HEAD" + ) + ) + private void osl$lifecycle$stopped(CallbackInfo ci) { + if (--osl$lifecycle$shutdownDepth == 0) { + MinecraftServerAccess.INSTANCE = null; } } @@ -58,7 +71,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$startTick(CallbackInfo ci) { - MinecraftServerEvents.TICK_START.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.TICK_START.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -68,7 +81,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$endTick(CallbackInfo ci) { - MinecraftServerEvents.TICK_END.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.TICK_END.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -78,7 +91,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$loadWorld(CallbackInfo ci) { - MinecraftServerEvents.LOAD_WORLD.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.LOAD_WORLD.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -88,7 +101,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$prepareWorld(CallbackInfo ci) { - MinecraftServerEvents.PREPARE_WORLD.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.PREPARE_WORLD.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -98,6 +111,6 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$readyWorld(CallbackInfo ci) { - MinecraftServerEvents.READY_WORLD.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.READY_WORLD.invoker().accept(MinecraftServerAccess.INSTANCE); } } diff --git a/libraries/lifecycle-events/lifecycle-events-mc12w21a-mc1.6.4/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java b/libraries/lifecycle-events/lifecycle-events-mc12w21a-mc1.6.4/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java new file mode 100644 index 00000000..eb9c5e2b --- /dev/null +++ b/libraries/lifecycle-events/lifecycle-events-mc12w21a-mc1.6.4/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java @@ -0,0 +1,16 @@ +package net.ornithemc.osl.lifecycle.impl.server; + +import net.minecraft.server.MinecraftServer; + +public class MinecraftServerAccess { + + public static MinecraftServer INSTANCE; + + public static MinecraftServer getInstance() { + if (INSTANCE == null) { + throw new IllegalStateException("no MinecraftServer instance available right now"); + } + + return INSTANCE; + } +} diff --git a/libraries/lifecycle-events/lifecycle-events-mc13w36a-09051446-mc1.13/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java b/libraries/lifecycle-events/lifecycle-events-mc13w36a-09051446-mc1.13/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java new file mode 100644 index 00000000..be030e30 --- /dev/null +++ b/libraries/lifecycle-events/lifecycle-events-mc13w36a-09051446-mc1.13/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java @@ -0,0 +1,21 @@ +package net.ornithemc.osl.lifecycle.api.server; + +import net.minecraft.server.MinecraftServer; + +import net.ornithemc.osl.lifecycle.impl.server.MinecraftServerAccess; + +/** + * A wrapper class for getting the {@linkplain MinecraftServer} instance. + */ +public class MinecraftServerInstance { + + /** + * Retrieves the current Minecraft server instance, + * or throws an exception. + * + * @return the current Minecraft server instance + */ + public static MinecraftServer get() { + return MinecraftServerAccess.getInstance(); + } +} diff --git a/libraries/lifecycle-events/lifecycle-events-mc13w36a-09051446-mc1.13/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/common/MinecraftServerMixin.java b/libraries/lifecycle-events/lifecycle-events-mc13w36a-09051446-mc1.13/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/common/MinecraftServerMixin.java index a17b3451..23a39ca3 100644 --- a/libraries/lifecycle-events/lifecycle-events-mc13w36a-09051446-mc1.13/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/common/MinecraftServerMixin.java +++ b/libraries/lifecycle-events/lifecycle-events-mc13w36a-09051446-mc1.13/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/common/MinecraftServerMixin.java @@ -10,11 +10,12 @@ import net.minecraft.server.MinecraftServer; import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; +import net.ornithemc.osl.lifecycle.impl.server.MinecraftServerAccess; @Mixin(MinecraftServer.class) public class MinecraftServerMixin { - @Unique private boolean osl$lifecycle$stopped; + @Unique private int osl$lifecycle$shutdownDepth; @Inject( method = "run", @@ -23,7 +24,8 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$start(CallbackInfo ci) { - MinecraftServerEvents.START.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerAccess.INSTANCE = (MinecraftServer)(Object)this; + MinecraftServerEvents.START.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -35,7 +37,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$ready(CallbackInfo ci) { - MinecraftServerEvents.READY.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.READY.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -45,9 +47,20 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$stop(CallbackInfo ci) { - if (!osl$lifecycle$stopped) { - osl$lifecycle$stopped = true; - MinecraftServerEvents.STOP.invoker().accept((MinecraftServer)(Object)this); + if (osl$lifecycle$shutdownDepth++ == 0) { + MinecraftServerEvents.STOP.invoker().accept(MinecraftServerAccess.INSTANCE); + } + } + + @Inject( + method = "shutdown", + at = @At( + value = "HEAD" + ) + ) + private void osl$lifecycle$stopped(CallbackInfo ci) { + if (--osl$lifecycle$shutdownDepth == 0) { + MinecraftServerAccess.INSTANCE = null; } } @@ -58,7 +71,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$startTick(CallbackInfo ci) { - MinecraftServerEvents.TICK_START.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.TICK_START.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -68,7 +81,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$endTick(CallbackInfo ci) { - MinecraftServerEvents.TICK_END.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.TICK_END.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -78,7 +91,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$loadWorld(CallbackInfo ci) { - MinecraftServerEvents.LOAD_WORLD.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.LOAD_WORLD.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -88,7 +101,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$prepareWorld(CallbackInfo ci) { - MinecraftServerEvents.PREPARE_WORLD.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.PREPARE_WORLD.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -98,6 +111,6 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$readyWorld(CallbackInfo ci) { - MinecraftServerEvents.READY_WORLD.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.READY_WORLD.invoker().accept(MinecraftServerAccess.INSTANCE); } } diff --git a/libraries/lifecycle-events/lifecycle-events-mc13w36a-09051446-mc1.13/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java b/libraries/lifecycle-events/lifecycle-events-mc13w36a-09051446-mc1.13/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java new file mode 100644 index 00000000..eb9c5e2b --- /dev/null +++ b/libraries/lifecycle-events/lifecycle-events-mc13w36a-09051446-mc1.13/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java @@ -0,0 +1,16 @@ +package net.ornithemc.osl.lifecycle.impl.server; + +import net.minecraft.server.MinecraftServer; + +public class MinecraftServerAccess { + + public static MinecraftServer INSTANCE; + + public static MinecraftServer getInstance() { + if (INSTANCE == null) { + throw new IllegalStateException("no MinecraftServer instance available right now"); + } + + return INSTANCE; + } +} diff --git a/libraries/lifecycle-events/lifecycle-events-mc18w30a-mc18w50a/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java b/libraries/lifecycle-events/lifecycle-events-mc18w30a-mc18w50a/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java new file mode 100644 index 00000000..be030e30 --- /dev/null +++ b/libraries/lifecycle-events/lifecycle-events-mc18w30a-mc18w50a/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java @@ -0,0 +1,21 @@ +package net.ornithemc.osl.lifecycle.api.server; + +import net.minecraft.server.MinecraftServer; + +import net.ornithemc.osl.lifecycle.impl.server.MinecraftServerAccess; + +/** + * A wrapper class for getting the {@linkplain MinecraftServer} instance. + */ +public class MinecraftServerInstance { + + /** + * Retrieves the current Minecraft server instance, + * or throws an exception. + * + * @return the current Minecraft server instance + */ + public static MinecraftServer get() { + return MinecraftServerAccess.getInstance(); + } +} diff --git a/libraries/lifecycle-events/lifecycle-events-mc18w30a-mc18w50a/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/common/MinecraftServerMixin.java b/libraries/lifecycle-events/lifecycle-events-mc18w30a-mc18w50a/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/common/MinecraftServerMixin.java index a151a2dc..23a39ca3 100644 --- a/libraries/lifecycle-events/lifecycle-events-mc18w30a-mc18w50a/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/common/MinecraftServerMixin.java +++ b/libraries/lifecycle-events/lifecycle-events-mc18w30a-mc18w50a/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/common/MinecraftServerMixin.java @@ -3,18 +3,19 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.At.Shift; +import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import net.minecraft.server.MinecraftServer; import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; +import net.ornithemc.osl.lifecycle.impl.server.MinecraftServerAccess; @Mixin(MinecraftServer.class) public class MinecraftServerMixin { - @Unique private boolean osl$lifecycle$stopped; + @Unique private int osl$lifecycle$shutdownDepth; @Inject( method = "run", @@ -23,7 +24,8 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$start(CallbackInfo ci) { - MinecraftServerEvents.START.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerAccess.INSTANCE = (MinecraftServer)(Object)this; + MinecraftServerEvents.START.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -35,7 +37,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$ready(CallbackInfo ci) { - MinecraftServerEvents.READY.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.READY.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -45,9 +47,20 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$stop(CallbackInfo ci) { - if (!osl$lifecycle$stopped) { - osl$lifecycle$stopped = true; - MinecraftServerEvents.STOP.invoker().accept((MinecraftServer)(Object)this); + if (osl$lifecycle$shutdownDepth++ == 0) { + MinecraftServerEvents.STOP.invoker().accept(MinecraftServerAccess.INSTANCE); + } + } + + @Inject( + method = "shutdown", + at = @At( + value = "HEAD" + ) + ) + private void osl$lifecycle$stopped(CallbackInfo ci) { + if (--osl$lifecycle$shutdownDepth == 0) { + MinecraftServerAccess.INSTANCE = null; } } @@ -58,7 +71,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$startTick(CallbackInfo ci) { - MinecraftServerEvents.TICK_START.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.TICK_START.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -68,7 +81,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$endTick(CallbackInfo ci) { - MinecraftServerEvents.TICK_END.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.TICK_END.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -78,7 +91,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$loadWorld(CallbackInfo ci) { - MinecraftServerEvents.LOAD_WORLD.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.LOAD_WORLD.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -88,7 +101,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$prepareWorld(CallbackInfo ci) { - MinecraftServerEvents.PREPARE_WORLD.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.PREPARE_WORLD.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -98,6 +111,6 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$readyWorld(CallbackInfo ci) { - MinecraftServerEvents.READY_WORLD.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.READY_WORLD.invoker().accept(MinecraftServerAccess.INSTANCE); } } diff --git a/libraries/lifecycle-events/lifecycle-events-mc18w30a-mc18w50a/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java b/libraries/lifecycle-events/lifecycle-events-mc18w30a-mc18w50a/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java new file mode 100644 index 00000000..eb9c5e2b --- /dev/null +++ b/libraries/lifecycle-events/lifecycle-events-mc18w30a-mc18w50a/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java @@ -0,0 +1,16 @@ +package net.ornithemc.osl.lifecycle.impl.server; + +import net.minecraft.server.MinecraftServer; + +public class MinecraftServerAccess { + + public static MinecraftServer INSTANCE; + + public static MinecraftServer getInstance() { + if (INSTANCE == null) { + throw new IllegalStateException("no MinecraftServer instance available right now"); + } + + return INSTANCE; + } +} diff --git a/libraries/lifecycle-events/lifecycle-events-mc19w04a-mc1.14.4/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java b/libraries/lifecycle-events/lifecycle-events-mc19w04a-mc1.14.4/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java new file mode 100644 index 00000000..be030e30 --- /dev/null +++ b/libraries/lifecycle-events/lifecycle-events-mc19w04a-mc1.14.4/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java @@ -0,0 +1,21 @@ +package net.ornithemc.osl.lifecycle.api.server; + +import net.minecraft.server.MinecraftServer; + +import net.ornithemc.osl.lifecycle.impl.server.MinecraftServerAccess; + +/** + * A wrapper class for getting the {@linkplain MinecraftServer} instance. + */ +public class MinecraftServerInstance { + + /** + * Retrieves the current Minecraft server instance, + * or throws an exception. + * + * @return the current Minecraft server instance + */ + public static MinecraftServer get() { + return MinecraftServerAccess.getInstance(); + } +} diff --git a/libraries/lifecycle-events/lifecycle-events-mc19w04a-mc1.14.4/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/common/MinecraftServerMixin.java b/libraries/lifecycle-events/lifecycle-events-mc19w04a-mc1.14.4/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/common/MinecraftServerMixin.java index a151a2dc..23a39ca3 100644 --- a/libraries/lifecycle-events/lifecycle-events-mc19w04a-mc1.14.4/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/common/MinecraftServerMixin.java +++ b/libraries/lifecycle-events/lifecycle-events-mc19w04a-mc1.14.4/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/common/MinecraftServerMixin.java @@ -3,18 +3,19 @@ import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; -import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.At.Shift; +import org.spongepowered.asm.mixin.injection.Inject; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import net.minecraft.server.MinecraftServer; import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; +import net.ornithemc.osl.lifecycle.impl.server.MinecraftServerAccess; @Mixin(MinecraftServer.class) public class MinecraftServerMixin { - @Unique private boolean osl$lifecycle$stopped; + @Unique private int osl$lifecycle$shutdownDepth; @Inject( method = "run", @@ -23,7 +24,8 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$start(CallbackInfo ci) { - MinecraftServerEvents.START.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerAccess.INSTANCE = (MinecraftServer)(Object)this; + MinecraftServerEvents.START.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -35,7 +37,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$ready(CallbackInfo ci) { - MinecraftServerEvents.READY.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.READY.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -45,9 +47,20 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$stop(CallbackInfo ci) { - if (!osl$lifecycle$stopped) { - osl$lifecycle$stopped = true; - MinecraftServerEvents.STOP.invoker().accept((MinecraftServer)(Object)this); + if (osl$lifecycle$shutdownDepth++ == 0) { + MinecraftServerEvents.STOP.invoker().accept(MinecraftServerAccess.INSTANCE); + } + } + + @Inject( + method = "shutdown", + at = @At( + value = "HEAD" + ) + ) + private void osl$lifecycle$stopped(CallbackInfo ci) { + if (--osl$lifecycle$shutdownDepth == 0) { + MinecraftServerAccess.INSTANCE = null; } } @@ -58,7 +71,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$startTick(CallbackInfo ci) { - MinecraftServerEvents.TICK_START.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.TICK_START.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -68,7 +81,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$endTick(CallbackInfo ci) { - MinecraftServerEvents.TICK_END.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.TICK_END.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -78,7 +91,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$loadWorld(CallbackInfo ci) { - MinecraftServerEvents.LOAD_WORLD.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.LOAD_WORLD.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -88,7 +101,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$prepareWorld(CallbackInfo ci) { - MinecraftServerEvents.PREPARE_WORLD.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.PREPARE_WORLD.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -98,6 +111,6 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$readyWorld(CallbackInfo ci) { - MinecraftServerEvents.READY_WORLD.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.READY_WORLD.invoker().accept(MinecraftServerAccess.INSTANCE); } } diff --git a/libraries/lifecycle-events/lifecycle-events-mc19w04a-mc1.14.4/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java b/libraries/lifecycle-events/lifecycle-events-mc19w04a-mc1.14.4/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java new file mode 100644 index 00000000..eb9c5e2b --- /dev/null +++ b/libraries/lifecycle-events/lifecycle-events-mc19w04a-mc1.14.4/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java @@ -0,0 +1,16 @@ +package net.ornithemc.osl.lifecycle.impl.server; + +import net.minecraft.server.MinecraftServer; + +public class MinecraftServerAccess { + + public static MinecraftServer INSTANCE; + + public static MinecraftServer getInstance() { + if (INSTANCE == null) { + throw new IllegalStateException("no MinecraftServer instance available right now"); + } + + return INSTANCE; + } +} diff --git a/libraries/lifecycle-events/lifecycle-events-mcb1.0-mcb1.2_02/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java b/libraries/lifecycle-events/lifecycle-events-mcb1.0-mcb1.2_02/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java new file mode 100644 index 00000000..be030e30 --- /dev/null +++ b/libraries/lifecycle-events/lifecycle-events-mcb1.0-mcb1.2_02/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java @@ -0,0 +1,21 @@ +package net.ornithemc.osl.lifecycle.api.server; + +import net.minecraft.server.MinecraftServer; + +import net.ornithemc.osl.lifecycle.impl.server.MinecraftServerAccess; + +/** + * A wrapper class for getting the {@linkplain MinecraftServer} instance. + */ +public class MinecraftServerInstance { + + /** + * Retrieves the current Minecraft server instance, + * or throws an exception. + * + * @return the current Minecraft server instance + */ + public static MinecraftServer get() { + return MinecraftServerAccess.getInstance(); + } +} diff --git a/libraries/lifecycle-events/lifecycle-events-mcb1.0-mcb1.2_02/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/server/MinecraftServerMixin.java b/libraries/lifecycle-events/lifecycle-events-mcb1.0-mcb1.2_02/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/server/MinecraftServerMixin.java index 016150f0..67ea8332 100644 --- a/libraries/lifecycle-events/lifecycle-events-mcb1.0-mcb1.2_02/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/server/MinecraftServerMixin.java +++ b/libraries/lifecycle-events/lifecycle-events-mcb1.0-mcb1.2_02/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/server/MinecraftServerMixin.java @@ -10,11 +10,12 @@ import net.minecraft.server.MinecraftServer; import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; +import net.ornithemc.osl.lifecycle.impl.server.MinecraftServerAccess; @Mixin(MinecraftServer.class) public class MinecraftServerMixin { - @Unique private boolean osl$lifecycle$stopped; + @Unique private int osl$lifecycle$shutdownDepth; @Inject( method = "run", @@ -23,7 +24,8 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$start(CallbackInfo ci) { - MinecraftServerEvents.START.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerAccess.INSTANCE = (MinecraftServer)(Object)this; + MinecraftServerEvents.START.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -35,7 +37,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$ready(CallbackInfo ci) { - MinecraftServerEvents.READY.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.READY.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -45,9 +47,20 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$stop(CallbackInfo ci) { - if (!osl$lifecycle$stopped) { - osl$lifecycle$stopped = true; - MinecraftServerEvents.STOP.invoker().accept((MinecraftServer)(Object)this); + if (osl$lifecycle$shutdownDepth++ == 0) { + MinecraftServerEvents.STOP.invoker().accept(MinecraftServerAccess.INSTANCE); + } + } + + @Inject( + method = "shutdown", + at = @At( + value = "HEAD" + ) + ) + private void osl$lifecycle$stopped(CallbackInfo ci) { + if (--osl$lifecycle$shutdownDepth == 0) { + MinecraftServerAccess.INSTANCE = null; } } @@ -58,7 +71,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$startTick(CallbackInfo ci) { - MinecraftServerEvents.TICK_START.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.TICK_START.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -68,7 +81,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$endTick(CallbackInfo ci) { - MinecraftServerEvents.TICK_END.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.TICK_END.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -78,7 +91,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$loadWorld(CallbackInfo ci) { - MinecraftServerEvents.LOAD_WORLD.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.LOAD_WORLD.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -90,7 +103,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$prepareWorld(CallbackInfo ci) { - MinecraftServerEvents.PREPARE_WORLD.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.PREPARE_WORLD.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -100,6 +113,6 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$readyWorld(CallbackInfo ci) { - MinecraftServerEvents.READY_WORLD.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.READY_WORLD.invoker().accept(MinecraftServerAccess.INSTANCE); } } diff --git a/libraries/lifecycle-events/lifecycle-events-mcb1.0-mcb1.2_02/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java b/libraries/lifecycle-events/lifecycle-events-mcb1.0-mcb1.2_02/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java new file mode 100644 index 00000000..eb9c5e2b --- /dev/null +++ b/libraries/lifecycle-events/lifecycle-events-mcb1.0-mcb1.2_02/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java @@ -0,0 +1,16 @@ +package net.ornithemc.osl.lifecycle.impl.server; + +import net.minecraft.server.MinecraftServer; + +public class MinecraftServerAccess { + + public static MinecraftServer INSTANCE; + + public static MinecraftServer getInstance() { + if (INSTANCE == null) { + throw new IllegalStateException("no MinecraftServer instance available right now"); + } + + return INSTANCE; + } +} diff --git a/libraries/lifecycle-events/lifecycle-events-mcb1.4-1507-mcb1.7.3/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java b/libraries/lifecycle-events/lifecycle-events-mcb1.4-1507-mcb1.7.3/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java new file mode 100644 index 00000000..be030e30 --- /dev/null +++ b/libraries/lifecycle-events/lifecycle-events-mcb1.4-1507-mcb1.7.3/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java @@ -0,0 +1,21 @@ +package net.ornithemc.osl.lifecycle.api.server; + +import net.minecraft.server.MinecraftServer; + +import net.ornithemc.osl.lifecycle.impl.server.MinecraftServerAccess; + +/** + * A wrapper class for getting the {@linkplain MinecraftServer} instance. + */ +public class MinecraftServerInstance { + + /** + * Retrieves the current Minecraft server instance, + * or throws an exception. + * + * @return the current Minecraft server instance + */ + public static MinecraftServer get() { + return MinecraftServerAccess.getInstance(); + } +} diff --git a/libraries/lifecycle-events/lifecycle-events-mcb1.4-1507-mcb1.7.3/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/server/MinecraftServerMixin.java b/libraries/lifecycle-events/lifecycle-events-mcb1.4-1507-mcb1.7.3/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/server/MinecraftServerMixin.java index 84b106ee..cde5852a 100644 --- a/libraries/lifecycle-events/lifecycle-events-mcb1.4-1507-mcb1.7.3/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/server/MinecraftServerMixin.java +++ b/libraries/lifecycle-events/lifecycle-events-mcb1.4-1507-mcb1.7.3/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/server/MinecraftServerMixin.java @@ -10,11 +10,12 @@ import net.minecraft.server.MinecraftServer; import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; +import net.ornithemc.osl.lifecycle.impl.server.MinecraftServerAccess; @Mixin(MinecraftServer.class) public class MinecraftServerMixin { - @Unique private boolean osl$lifecycle$stopped; + @Unique private int osl$lifecycle$shutdownDepth; @Inject( method = "run", @@ -23,7 +24,8 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$start(CallbackInfo ci) { - MinecraftServerEvents.START.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerAccess.INSTANCE = (MinecraftServer)(Object)this; + MinecraftServerEvents.START.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -35,7 +37,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$ready(CallbackInfo ci) { - MinecraftServerEvents.READY.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.READY.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -45,9 +47,20 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$stop(CallbackInfo ci) { - if (!osl$lifecycle$stopped) { - osl$lifecycle$stopped = true; - MinecraftServerEvents.STOP.invoker().accept((MinecraftServer)(Object)this); + if (osl$lifecycle$shutdownDepth++ == 0) { + MinecraftServerEvents.STOP.invoker().accept(MinecraftServerAccess.INSTANCE); + } + } + + @Inject( + method = "shutdown", + at = @At( + value = "HEAD" + ) + ) + private void osl$lifecycle$stopped(CallbackInfo ci) { + if (--osl$lifecycle$shutdownDepth == 0) { + MinecraftServerAccess.INSTANCE = null; } } @@ -58,7 +71,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$startTick(CallbackInfo ci) { - MinecraftServerEvents.TICK_START.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.TICK_START.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -68,7 +81,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$endTick(CallbackInfo ci) { - MinecraftServerEvents.TICK_END.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.TICK_END.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -78,7 +91,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$loadWorld(CallbackInfo ci) { - MinecraftServerEvents.LOAD_WORLD.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.LOAD_WORLD.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -91,7 +104,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$prepareWorld(CallbackInfo ci) { - MinecraftServerEvents.PREPARE_WORLD.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.PREPARE_WORLD.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -101,6 +114,6 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$readyWorld(CallbackInfo ci) { - MinecraftServerEvents.READY_WORLD.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.READY_WORLD.invoker().accept(MinecraftServerAccess.INSTANCE); } } diff --git a/libraries/lifecycle-events/lifecycle-events-mcb1.4-1507-mcb1.7.3/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java b/libraries/lifecycle-events/lifecycle-events-mcb1.4-1507-mcb1.7.3/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java new file mode 100644 index 00000000..eb9c5e2b --- /dev/null +++ b/libraries/lifecycle-events/lifecycle-events-mcb1.4-1507-mcb1.7.3/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java @@ -0,0 +1,16 @@ +package net.ornithemc.osl.lifecycle.impl.server; + +import net.minecraft.server.MinecraftServer; + +public class MinecraftServerAccess { + + public static MinecraftServer INSTANCE; + + public static MinecraftServer getInstance() { + if (INSTANCE == null) { + throw new IllegalStateException("no MinecraftServer instance available right now"); + } + + return INSTANCE; + } +} diff --git a/libraries/lifecycle-events/lifecycle-events-mcb1.8-pre1-201109081459-mc11w50a/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java b/libraries/lifecycle-events/lifecycle-events-mcb1.8-pre1-201109081459-mc11w50a/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java new file mode 100644 index 00000000..be030e30 --- /dev/null +++ b/libraries/lifecycle-events/lifecycle-events-mcb1.8-pre1-201109081459-mc11w50a/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java @@ -0,0 +1,21 @@ +package net.ornithemc.osl.lifecycle.api.server; + +import net.minecraft.server.MinecraftServer; + +import net.ornithemc.osl.lifecycle.impl.server.MinecraftServerAccess; + +/** + * A wrapper class for getting the {@linkplain MinecraftServer} instance. + */ +public class MinecraftServerInstance { + + /** + * Retrieves the current Minecraft server instance, + * or throws an exception. + * + * @return the current Minecraft server instance + */ + public static MinecraftServer get() { + return MinecraftServerAccess.getInstance(); + } +} diff --git a/libraries/lifecycle-events/lifecycle-events-mcb1.8-pre1-201109081459-mc11w50a/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/server/MinecraftServerMixin.java b/libraries/lifecycle-events/lifecycle-events-mcb1.8-pre1-201109081459-mc11w50a/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/server/MinecraftServerMixin.java index 84b106ee..cde5852a 100644 --- a/libraries/lifecycle-events/lifecycle-events-mcb1.8-pre1-201109081459-mc11w50a/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/server/MinecraftServerMixin.java +++ b/libraries/lifecycle-events/lifecycle-events-mcb1.8-pre1-201109081459-mc11w50a/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/server/MinecraftServerMixin.java @@ -10,11 +10,12 @@ import net.minecraft.server.MinecraftServer; import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; +import net.ornithemc.osl.lifecycle.impl.server.MinecraftServerAccess; @Mixin(MinecraftServer.class) public class MinecraftServerMixin { - @Unique private boolean osl$lifecycle$stopped; + @Unique private int osl$lifecycle$shutdownDepth; @Inject( method = "run", @@ -23,7 +24,8 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$start(CallbackInfo ci) { - MinecraftServerEvents.START.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerAccess.INSTANCE = (MinecraftServer)(Object)this; + MinecraftServerEvents.START.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -35,7 +37,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$ready(CallbackInfo ci) { - MinecraftServerEvents.READY.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.READY.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -45,9 +47,20 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$stop(CallbackInfo ci) { - if (!osl$lifecycle$stopped) { - osl$lifecycle$stopped = true; - MinecraftServerEvents.STOP.invoker().accept((MinecraftServer)(Object)this); + if (osl$lifecycle$shutdownDepth++ == 0) { + MinecraftServerEvents.STOP.invoker().accept(MinecraftServerAccess.INSTANCE); + } + } + + @Inject( + method = "shutdown", + at = @At( + value = "HEAD" + ) + ) + private void osl$lifecycle$stopped(CallbackInfo ci) { + if (--osl$lifecycle$shutdownDepth == 0) { + MinecraftServerAccess.INSTANCE = null; } } @@ -58,7 +71,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$startTick(CallbackInfo ci) { - MinecraftServerEvents.TICK_START.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.TICK_START.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -68,7 +81,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$endTick(CallbackInfo ci) { - MinecraftServerEvents.TICK_END.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.TICK_END.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -78,7 +91,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$loadWorld(CallbackInfo ci) { - MinecraftServerEvents.LOAD_WORLD.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.LOAD_WORLD.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -91,7 +104,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$prepareWorld(CallbackInfo ci) { - MinecraftServerEvents.PREPARE_WORLD.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.PREPARE_WORLD.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -101,6 +114,6 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$readyWorld(CallbackInfo ci) { - MinecraftServerEvents.READY_WORLD.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.READY_WORLD.invoker().accept(MinecraftServerAccess.INSTANCE); } } diff --git a/libraries/lifecycle-events/lifecycle-events-mcb1.8-pre1-201109081459-mc11w50a/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java b/libraries/lifecycle-events/lifecycle-events-mcb1.8-pre1-201109081459-mc11w50a/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java new file mode 100644 index 00000000..eb9c5e2b --- /dev/null +++ b/libraries/lifecycle-events/lifecycle-events-mcb1.8-pre1-201109081459-mc11w50a/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java @@ -0,0 +1,16 @@ +package net.ornithemc.osl.lifecycle.impl.server; + +import net.minecraft.server.MinecraftServer; + +public class MinecraftServerAccess { + + public static MinecraftServer INSTANCE; + + public static MinecraftServer getInstance() { + if (INSTANCE == null) { + throw new IllegalStateException("no MinecraftServer instance available right now"); + } + + return INSTANCE; + } +} diff --git a/libraries/lifecycle-events/lifecycle-events-mcserver-a0.1.0-mcserver-a0.1.4/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java b/libraries/lifecycle-events/lifecycle-events-mcserver-a0.1.0-mcserver-a0.1.4/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java new file mode 100644 index 00000000..be030e30 --- /dev/null +++ b/libraries/lifecycle-events/lifecycle-events-mcserver-a0.1.0-mcserver-a0.1.4/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java @@ -0,0 +1,21 @@ +package net.ornithemc.osl.lifecycle.api.server; + +import net.minecraft.server.MinecraftServer; + +import net.ornithemc.osl.lifecycle.impl.server.MinecraftServerAccess; + +/** + * A wrapper class for getting the {@linkplain MinecraftServer} instance. + */ +public class MinecraftServerInstance { + + /** + * Retrieves the current Minecraft server instance, + * or throws an exception. + * + * @return the current Minecraft server instance + */ + public static MinecraftServer get() { + return MinecraftServerAccess.getInstance(); + } +} diff --git a/libraries/lifecycle-events/lifecycle-events-mcserver-a0.1.0-mcserver-a0.1.4/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/server/MinecraftServerMixin.java b/libraries/lifecycle-events/lifecycle-events-mcserver-a0.1.0-mcserver-a0.1.4/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/server/MinecraftServerMixin.java index f5111503..c7b6a056 100644 --- a/libraries/lifecycle-events/lifecycle-events-mcserver-a0.1.0-mcserver-a0.1.4/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/server/MinecraftServerMixin.java +++ b/libraries/lifecycle-events/lifecycle-events-mcserver-a0.1.0-mcserver-a0.1.4/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/server/MinecraftServerMixin.java @@ -10,11 +10,12 @@ import net.minecraft.server.MinecraftServer; import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; +import net.ornithemc.osl.lifecycle.impl.server.MinecraftServerAccess; @Mixin(MinecraftServer.class) public class MinecraftServerMixin { - @Unique private boolean osl$lifecycle$stopped; + @Unique private int osl$lifecycle$shutdownDepth; @Inject( method = "run", @@ -23,7 +24,8 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$start(CallbackInfo ci) { - MinecraftServerEvents.START.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerAccess.INSTANCE = (MinecraftServer)(Object)this; + MinecraftServerEvents.START.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -35,7 +37,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$ready(CallbackInfo ci) { - MinecraftServerEvents.READY.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.READY.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -45,9 +47,20 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$stop(CallbackInfo ci) { - if (!osl$lifecycle$stopped) { - osl$lifecycle$stopped = true; - MinecraftServerEvents.STOP.invoker().accept((MinecraftServer)(Object)this); + if (osl$lifecycle$shutdownDepth++ == 0) { + MinecraftServerEvents.STOP.invoker().accept(MinecraftServerAccess.INSTANCE); + } + } + + @Inject( + method = "shutdown", + at = @At( + value = "HEAD" + ) + ) + private void osl$lifecycle$stopped(CallbackInfo ci) { + if (--osl$lifecycle$shutdownDepth == 0) { + MinecraftServerAccess.INSTANCE = null; } } @@ -58,7 +71,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$startTick(CallbackInfo ci) { - MinecraftServerEvents.TICK_START.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.TICK_START.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -68,7 +81,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$endTick(CallbackInfo ci) { - MinecraftServerEvents.TICK_END.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.TICK_END.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -78,7 +91,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$loadWorld(CallbackInfo ci) { - MinecraftServerEvents.LOAD_WORLD.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.LOAD_WORLD.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -90,7 +103,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$prepareWorld(CallbackInfo ci) { - MinecraftServerEvents.PREPARE_WORLD.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.PREPARE_WORLD.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -100,6 +113,6 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$readyWorld(CallbackInfo ci) { - MinecraftServerEvents.READY_WORLD.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.READY_WORLD.invoker().accept(MinecraftServerAccess.INSTANCE); } } diff --git a/libraries/lifecycle-events/lifecycle-events-mcserver-a0.1.0-mcserver-a0.1.4/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java b/libraries/lifecycle-events/lifecycle-events-mcserver-a0.1.0-mcserver-a0.1.4/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java new file mode 100644 index 00000000..eb9c5e2b --- /dev/null +++ b/libraries/lifecycle-events/lifecycle-events-mcserver-a0.1.0-mcserver-a0.1.4/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java @@ -0,0 +1,16 @@ +package net.ornithemc.osl.lifecycle.impl.server; + +import net.minecraft.server.MinecraftServer; + +public class MinecraftServerAccess { + + public static MinecraftServer INSTANCE; + + public static MinecraftServer getInstance() { + if (INSTANCE == null) { + throw new IllegalStateException("no MinecraftServer instance available right now"); + } + + return INSTANCE; + } +} diff --git a/libraries/lifecycle-events/lifecycle-events-mcserver-a0.2.0-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java b/libraries/lifecycle-events/lifecycle-events-mcserver-a0.2.0-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java new file mode 100644 index 00000000..be030e30 --- /dev/null +++ b/libraries/lifecycle-events/lifecycle-events-mcserver-a0.2.0-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/lifecycle/api/server/MinecraftServerInstance.java @@ -0,0 +1,21 @@ +package net.ornithemc.osl.lifecycle.api.server; + +import net.minecraft.server.MinecraftServer; + +import net.ornithemc.osl.lifecycle.impl.server.MinecraftServerAccess; + +/** + * A wrapper class for getting the {@linkplain MinecraftServer} instance. + */ +public class MinecraftServerInstance { + + /** + * Retrieves the current Minecraft server instance, + * or throws an exception. + * + * @return the current Minecraft server instance + */ + public static MinecraftServer get() { + return MinecraftServerAccess.getInstance(); + } +} diff --git a/libraries/lifecycle-events/lifecycle-events-mcserver-a0.2.0-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/server/MinecraftServerMixin.java b/libraries/lifecycle-events/lifecycle-events-mcserver-a0.2.0-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/server/MinecraftServerMixin.java index 016150f0..67ea8332 100644 --- a/libraries/lifecycle-events/lifecycle-events-mcserver-a0.2.0-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/server/MinecraftServerMixin.java +++ b/libraries/lifecycle-events/lifecycle-events-mcserver-a0.2.0-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/lifecycle/impl/mixin/server/MinecraftServerMixin.java @@ -10,11 +10,12 @@ import net.minecraft.server.MinecraftServer; import net.ornithemc.osl.lifecycle.api.server.MinecraftServerEvents; +import net.ornithemc.osl.lifecycle.impl.server.MinecraftServerAccess; @Mixin(MinecraftServer.class) public class MinecraftServerMixin { - @Unique private boolean osl$lifecycle$stopped; + @Unique private int osl$lifecycle$shutdownDepth; @Inject( method = "run", @@ -23,7 +24,8 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$start(CallbackInfo ci) { - MinecraftServerEvents.START.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerAccess.INSTANCE = (MinecraftServer)(Object)this; + MinecraftServerEvents.START.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -35,7 +37,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$ready(CallbackInfo ci) { - MinecraftServerEvents.READY.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.READY.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -45,9 +47,20 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$stop(CallbackInfo ci) { - if (!osl$lifecycle$stopped) { - osl$lifecycle$stopped = true; - MinecraftServerEvents.STOP.invoker().accept((MinecraftServer)(Object)this); + if (osl$lifecycle$shutdownDepth++ == 0) { + MinecraftServerEvents.STOP.invoker().accept(MinecraftServerAccess.INSTANCE); + } + } + + @Inject( + method = "shutdown", + at = @At( + value = "HEAD" + ) + ) + private void osl$lifecycle$stopped(CallbackInfo ci) { + if (--osl$lifecycle$shutdownDepth == 0) { + MinecraftServerAccess.INSTANCE = null; } } @@ -58,7 +71,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$startTick(CallbackInfo ci) { - MinecraftServerEvents.TICK_START.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.TICK_START.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -68,7 +81,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$endTick(CallbackInfo ci) { - MinecraftServerEvents.TICK_END.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.TICK_END.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -78,7 +91,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$loadWorld(CallbackInfo ci) { - MinecraftServerEvents.LOAD_WORLD.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.LOAD_WORLD.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -90,7 +103,7 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$prepareWorld(CallbackInfo ci) { - MinecraftServerEvents.PREPARE_WORLD.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.PREPARE_WORLD.invoker().accept(MinecraftServerAccess.INSTANCE); } @Inject( @@ -100,6 +113,6 @@ public class MinecraftServerMixin { ) ) private void osl$lifecycle$readyWorld(CallbackInfo ci) { - MinecraftServerEvents.READY_WORLD.invoker().accept((MinecraftServer)(Object)this); + MinecraftServerEvents.READY_WORLD.invoker().accept(MinecraftServerAccess.INSTANCE); } } diff --git a/libraries/lifecycle-events/lifecycle-events-mcserver-a0.2.0-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java b/libraries/lifecycle-events/lifecycle-events-mcserver-a0.2.0-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java new file mode 100644 index 00000000..eb9c5e2b --- /dev/null +++ b/libraries/lifecycle-events/lifecycle-events-mcserver-a0.2.0-mcserver-a0.2.8/src/main/java/net/ornithemc/osl/lifecycle/impl/server/MinecraftServerAccess.java @@ -0,0 +1,16 @@ +package net.ornithemc.osl.lifecycle.impl.server; + +import net.minecraft.server.MinecraftServer; + +public class MinecraftServerAccess { + + public static MinecraftServer INSTANCE; + + public static MinecraftServer getInstance() { + if (INSTANCE == null) { + throw new IllegalStateException("no MinecraftServer instance available right now"); + } + + return INSTANCE; + } +}

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