From d7742d94dbbc9f1e485f9087797f55655f7cc0f8 Mon Sep 17 00:00:00 2001 From: AnimeGitB Date: Wed, 13 Jul 2022 01:20:39 +0930 Subject: [PATCH 01/61] Add dispatch keys --- src/main/resources/keys/OSCB.pem | 27 +++++++++++++++++++ src/main/resources/keys/OSCB_Pub.der | Bin 0 -> 294 bytes src/main/resources/keys/OSCN.pem | 27 +++++++++++++++++++ src/main/resources/keys/OSCN_Pub.der | Bin 0 -> 294 bytes src/main/resources/keys/SigningKey.der | Bin 0 -> 1219 bytes src/main/resources/keys/SigningKey.pem | 27 +++++++++++++++++++ src/main/resources/keys/auth_private-key.der | Bin 0 -> 634 bytes src/main/resources/keys/auth_private-key.pem | 15 +++++++++++ src/main/resources/keys/auth_public-key.pem | 6 +++++ 9 files changed, 102 insertions(+) create mode 100644 src/main/resources/keys/OSCB.pem create mode 100644 src/main/resources/keys/OSCB_Pub.der create mode 100644 src/main/resources/keys/OSCN.pem create mode 100644 src/main/resources/keys/OSCN_Pub.der create mode 100644 src/main/resources/keys/SigningKey.der create mode 100644 src/main/resources/keys/SigningKey.pem create mode 100644 src/main/resources/keys/auth_private-key.der create mode 100644 src/main/resources/keys/auth_private-key.pem create mode 100644 src/main/resources/keys/auth_public-key.pem diff --git a/src/main/resources/keys/OSCB.pem b/src/main/resources/keys/OSCB.pem new file mode 100644 index 000000000..85dbee811 --- /dev/null +++ b/src/main/resources/keys/OSCB.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpAIBAAKCAQEA02M1I1V/YvxANOvLFX8R7D8At40IlT7HDWpAW3t+tAgQ7sqj +CeYOxiXqOaaw2kJhM3HT5nZll48UmykVq45Q05J57nhdSsGXLJshtLcTg9liMEoW +61BjVZi9EPPRSnE05tBJc57iqZw+aEcaSU0awfzBc8IkRd6+pJ5iIgEVfuTluani +zhHWvRli3EkAF4VNhaTfP3EkYfr4NE899aUeScbbdLFI6u1XQudlJCPTxaISx5Zc +wM+nP3v242ABcjgUcfCbz0AY547WazK4bWP3qicyxo4MoLOoe9WBq6EuG4CuZQrz +Knq8ltSxud/6chdg8Mqp/IasEQ2TpvY78tEXDQIDAQABAoIBAQC4uPsYk4AsSe75 +0Au6Dz7kSfIgdDhJ44AisvTmfLauMFZLtfxfjBDhCwTxuD7XnCZAxHm97Ty+AqSp +Km/raQQsvtWalMhBqYanzjDYMRv2niJ1vGjm3WrQxBaEF+yOtvrZsK5fQTslqInI +qknIQH7fgjazJ7Z28D18sYNj37qfFWSSymgFo+SoS/BKEr200lpRA/oaGXiHcyIO +jJidP6b7UGes7uhMXUvLrfozmCsSqslxXO5Uk5XN/fWl4LxCGX7mpNfPZIT5YBSj +HliFkNlxIjyJg8ORLGi82M2cuyxp39r93F6uaCjLtb+rdwlGur7npgXUkKfWQJf9 +WE7uar6BAoGBAPXIuIuYFFUhqNz5CKU014jZu6Ql0z5ZA08V84cTJcfLIK4e2rqC +8DFTldA0FtVfOGt0V08H/x2pRChGOvUwGG5nn9Dqqh6BjByUrW4z2hnXzT3ZuSDh +6eapiCB1jl9meJ0snhF2Ps/hqWGL2b3SkCCe90qVTzOVOeLO6YUCIOq9AoGBANws +fQkAq/0xw8neRGNTrnXimvbS+VXPIF38widljubNN7DY5cIFTQJrnTBWKbuz/t9a +J8QX6TFL0ci/9vhPJoThfL12vL2kWGYgWkWRPmqaBW3yz7Hs5rt+xuH3/7A5w5vm +kEg1NZJgnsJ0rMUTu1Q6PM5CBg6OpyHY4ThBb8qRAoGAML8ciuMgtTm1yg3CPzHZ +xZSZeJbf7K+uzlKmOBX+GkAZPS91ZiRuCvpu7hpGpQ77m6Q5ZL1LRdC6adpz+wkM +72ix87d3AhHjfg+mzgKOsS1x0WCLLRBhWZQqIXXvRNCH/3RH7WKsVoKFG4mnJ9TJ +LQ8aMLqoOKzSDD/JZM3lRWkCgYA8hn5Y2zZshCGufMuQApETFxhCgfzI+geLztAQ +xHpkOEX296kxjQN+htbPUuBmGTUXcVE9NtWEF7Oz3BGocRnFrbb83odEGsmySXKH +bUYbR/v2Ham638UOBevmcqZ3a2m6kcdYEkiH1MfP7QMRqjr1DI1qpfvERLLtOxGu +xU5WAQKBgQCaVavyY6Slj3ZRQ7iKk9fHkge/bFl+zhANxRfWVOYMC8mD2gHDsq9C +IdCp1Mg0tJpWLaGgyDM1kgChZYsff4jRxHC4czvAtoPSlxWXF2nL31qJ3vk2Zzzc +a4GSHAInodXBrKstav5SIKosWKT2YysxgHlA9Sm2f4n09GjFbslEHg== +-----END RSA PRIVATE KEY----- \ No newline at end of file diff --git a/src/main/resources/keys/OSCB_Pub.der b/src/main/resources/keys/OSCB_Pub.der new file mode 100644 index 0000000000000000000000000000000000000000..800e7ed4a68f2f1b36dac9cd60311689145a357a GIT binary patch literal 294 zcmV+>0ondAf&n5h4F(A+hDe6@4FLfG1potr0S^E$f&mHwf&l>l(_=LwRexgqKs4*i z6@L-zKLEFl2$ep^4QfDJdw#SC5bnyO3FZ#QCF(h*u-ZalGjY@Ac4e236q_j(tBz39 zl6mfUT}r{1ESn*;w-bZeVlYY;>ri7=n7t75(MoYN=FmxVp5m#TK4?c8NlhBT{K0d= zBt_o7q@H3T0Tq7a<+-Wi&JotV8DiW?02hT#g{0p0ondAf&n5h4F(A+hDe6@4FLfG1potr0S^E$f&mHwf&l>l&-e0vjO7e~)*IKi zExo<_xc76eu)RV-XcdpwO2PDW#Oj*keZh>VFJhX$vjNcktKqBGKHh@*po?(Y`A|SG zQT^Nga1WF054TtGouA^4xmHc5ROUPmUioMHk%kQfy9wW}_nqt9{VZ;-wrO&|rW8B} z&LNQUrsW5^Br2+u}0)hbn0L8ZP+HGHW ze5*sa&-=-(3}5NVg6kz>mI2W(-v(x)sR19YVW{Vy@~d!E$k#c8}C_ z8KQix5F=FmL$g1jjV;==cu>UQy*OGrclWM&)Ng%aAy3+Rhg650#~gfac% zHT?JQ9X0d2s!#*5Q$#?Jak~Ae)WD;pBxINtbLUQo1Z6tVt96f=Fmxdvt_0TBt^4Ob zFqg;sE@X?@PL{l<9ilYV#)v_Xg$eG+ZJKMO4lS6R$KL5b_9o@S48JS9hbMl%L@+21 zLeH@+;=~%V33in-)*={Xiu1m@Nx}a_B)!AY?&Fe{?*RsU5MNk?NV6srrgt>zTZ7 z(c_9ll4RX{f(7xLa|R_}4V}GhKYAxXmRx0Xr_6e7E4e3_<+HmF@G%^WW_rAP3mEI< zaNKipba$8jM>{@~BJ0(;Nw?{}V;);-*A`N?F`g-#HHsKXO6{c}50k8~1qm6-0TOh& z2v-=^MIzW9Gi~%r2sB#@F!U01{ zr7bMuedM2*a`w@$pSbe4;&^sXMWa*5WX|e;Iiz$TTVHcU*)gfi>)T*rM;tBev0C>6 zfq?+g$qtH5_8{2Kl2d9+KvYHpT5~qeWimG@aQ?v4>|7W{tEt-&85?i;G%jiw&kZR& zF!@FdW{JPxS;<{;-M!4QI8lP61Ch3h-cZ8uiiL^JNe%g`Q`SspJ}MO`p6r?%*Z}3+ z1(O+Y1a_lIv=4`(h!SokY>))-gPFJ4Kv&-afq?+3T(5_)I=m9o^Sp8c)$Andem3$9 zT6M6z1=tVAldhej(Lqx1QC*sAxR8Rzei8qlYu;D@&o1aPx#N9#dr)*F^Xy1O!xA|R z3a7J@zk4&2-l5A{a-)rJCvc`%J19>vtnIfQGG6w=@}8L%l=o*OFh*(21pIJA0&!xC zZ_Kj-fq*h5#_)`XN{+%OKQ{Zd2bCtcg6uvnruFMztX~xudc`31$ z+wi_LD7G!t;Rfic*ES&Vt@uk?r87HPjy1wk!dN45;_bPmlgItfAlD>5I`RI*<_7sE hj`zdi!~Y%JgkML^+NvuM9{z5ojgg}~=+LNlI>F3!QPcnc literal 0 HcmV?d00001 diff --git a/src/main/resources/keys/SigningKey.pem b/src/main/resources/keys/SigningKey.pem new file mode 100644 index 000000000..905ed1790 --- /dev/null +++ b/src/main/resources/keys/SigningKey.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEpQIBAAKCAQEAxbbx2m1feHyrQ7jP+8mtDF/pyYLrJWKWAdEv3wZrOtjOZzeL +GPzsmkcgncgoRhX4dT+1itSMR9j9m0/OwsH2UoF6U32LxCOQWQD1AMgIZjAkJeJv +FTrtn8fMQ1701CkbaLTVIjRMlTw8kNXvNA/A9UatoiDmi4TFG6mrxTKZpIcTInvP +EpkK2A7Qsp1E4skFK8jmysy7uRhMaYHtPTsBvxP0zn3lhKB3W+HTqpneewXWHjCD +fL7Nbby91jbz5EKPZXWLuhXIvR1Cu4tiruorwXJxmXaP1HQZonytECNU/UOzP6GN +Ldq0eFDE4b04Wjp396551G99YiFP2nqHVJ5OMQIDAQABAoIBAQDEeYZhjyq+avUu +eSuFhOaIU4/ZhlXycsOqzpwJvzEz61tBSvrZPA5LSb9pzAvpic+7hDH94jX89+8d +NfO7qlADsVNEQJBxuv2o1MCjpCRkmBZz506IBGU60Kt1j5kwdCEergTW1q375z4w +l8f7LmSL2U6WvKcdojTVxohBkIUJ7shtmmukDi2YnMfe6T/2JuXDDL8rvIcnfr5E +MCgPQs+xLeLEGrIJdpUy1iIYZYrzvrpJwf9EJL3D0e7jkpbvAQZ8EF9YhEizJhOm +dzTqW4PgW2yUaHYd3q5QjiILy7AC+oOYoTZln3RfjPOxl+bYjeMOWlqkgtpPQkAE +4I64w8RZAoGBAPLR44pEkmTdfIIF8ZtzBiVfDZ29bT96J0CWXGVzp8x6bSu5J5jl +s7sP8DEcjGZ6vHsLGOvkcNxzcnR3l/5HOz6TIuvVuUm36b1jHltq1xZStjGeKZs1 +ihhJSu2lIA+TrK8FCRnKARJ0ughXGNZFItgeM230Sgjp2RL4ISXJ724XAoGBANBy +S2RwNpUYvkCSZHSFnQM/jq1jldxw+0p4jAGpWLilEaA/8xWUnZrnCrPFF/t9llpb +dTR/dCI8ntIMAy2dH4IUHyYKUahyHSzCAUNKpS0s433kn5hy9tGvn7jyuOJ4dk9F +o1PIZM7qfzmkdCBbX3NF2TGpzOvbYGJHHC3ssVr3AoGBANHJDopN9iDYzpJTaktA +VEYDWnM2zmUyNylw/sDT7FwYRaup2xEZG2/5NC5qGM8NKTww+UYMZom/4FnJXXLd +vcyxOFGCpAORtoreUMLwioWJzkkN+apT1kxnPioVKJ7smhvYAOXcBZMZcAR2o0m0 +D4eiiBJuJWyQBPCDmbfZQFffAoGBAKpcr4ewOrwS0/O8cgPV7CTqfjbyDFp1sLwF +2A/Hk66dotFBUvBRXZpruJCCxn4R/59r3lgAzy7oMrnjfXl7UHQk8+xIRMMSOQwK +p7OSv3szk96hy1pyo41vJ3CmWDsoTzGs7bcdMl72wvKemRaU92ckMEZpzAT8cEMC +cWKLb8yzAoGAMibG8IyHSo7CJz82+7UHm98jNOlg6s73CEjp0W/+FL45Ka7MF/lp +xtR3eSmxltvwvjQoti3V4Qboqtc2IPCt+EtapTM7Wo41wlLCWCNx4u25pZPH/c8g +1yQ+OvH+xOYG+SeO98Phw/8d3IRfR83aqisQHv5upo2Rozzo0Kh3OsE= +-----END RSA PRIVATE KEY----- diff --git a/src/main/resources/keys/auth_private-key.der b/src/main/resources/keys/auth_private-key.der new file mode 100644 index 0000000000000000000000000000000000000000..ae9d35b79ac373e72239ab5c6f127510fbcf4911 GIT binary patch literal 634 zcmV-=0)_oBf&z8|0RS)!1_>&LNQUpU@(FLTmk_A0)c@5%PU~~e`U|I z=FxWm@Uto-CC^mQDPcDfdX)H7GQr}isuV5k{CltR^Lxw>&*JJ45R1Gh$EN@>WbW)M zWh`hhYzcyXfbPb?w^u3wr56X%csDpp(;dJSIEN7i@bjoqzHOBnM!@F9r>{dy$~HQ@S3bSZU&9)SM{04!9a%?_O9D<#lu<_MjZmPZcinLI7NY^ea>pJ4^w` zDPmuWDVhXyu>1u&NzM$1JTD0gU1`;@lOIvrmoW>;Jy2Ek70zm-q zHNX`nD4FG^&8UFnrhv)7*l>PqK*Zn7b4^b!ghcab zuXWg_b)7p~)I~h?Hq!mQe;K4A+ZHI~Q~zQTgeuY{koOq1x9V8Q0zm+SyE8$njN%^e za6Ld`Us)d{z2b}Hmu6v-v8tkKXh$@7WQi+-iCSxA=yBG6V3^#=ON!ud5e72f8SxuG zC`thWKy2y{PN?u~PhO4(ob%cKi;g;$G>t%Tjq*;-+`It Date: Wed, 13 Jul 2022 01:29:34 +0930 Subject: [PATCH 02/61] Libs for RealPassword --- lib/bcrypt-0.8.0.jar | Bin 0 -> 35859 bytes lib/bytes-1.3.0.jar | Bin 0 -> 68769 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 lib/bcrypt-0.8.0.jar create mode 100644 lib/bytes-1.3.0.jar diff --git a/lib/bcrypt-0.8.0.jar b/lib/bcrypt-0.8.0.jar new file mode 100644 index 0000000000000000000000000000000000000000..f4835ddbc40276f576da523d2ff81cf20a4b3bbd GIT binary patch literal 35859 zcma%hbC73E(`DPXZQC}cZQIkf{p+5#ZB5&@ZJX1!-M#bfyZi0F8?j$J6X6I6sB?jWuv+6R&#pD>PzE%dL(y4|IZ z8z2IiAD6(JX6{%Xtk*O5;D*s@fy_}*b7R}IWp1JBAs&h9v6(t41;`;|%Tl)I{eK`2 ztDh#3kdOLrBQ0r$T;mKx=>jUtwP)Gm5Zedzk;{cl~Rp-eUKvW8gqQ0kA+oO#f)7Qbx{}Vn!}T z|K4!2`i2Io1=6>#w4tab31%C#Wv8krR7r$}(BXdQD$u$jm6#5v5%io{a3*}Jwyn+e zv$yw!ih;F(hvf`)yo!QO?%Qln+3(BAs~{)ddFN3d)`kYwo^*Tjl%B8GM|U9Gm*p^P z-J5(wB|?UMZfIu0H|E}cBIi^x-KTv|!p`v2JQ&d*`i3l%rXlbKrYvUzSSS})5h1CX z_w^w*0#s7al62K$_hKhcRdEKPXC8|BLB$HdnPVA~8c)mRXoxRzmGJUq|bV8xkPrq*mNapJP3;3T!rf@b~!fK<1SZ2JL3=ri;FcF>!Jx#eZZ9$n)lY&>B(&>(>cy`zdFYG$cpvT4<2oj3;ABp4*Ua z<#dU_l4bm8u0Ka5=E~%zm###TQSh5Ic70CFq}EK zTaAn$w|#k=6yk!B_(T+~`Enc+r3pdJXltm3+2$~QAb%{WB)gm(t#(WNv_e_CryWDF ze5QI2-q@TkWXT;jYn&?RSylo|(`#?O2{5gU(A)@UmgTNPX5n1DSB6nH#R2w3sv{6R zOTT5ZW8BzzTJkN#m5hhVuud!Ofo&)0o?hVW^0nfyw}(NV&n3Lni_mb`i`4MQi&+0} zmiC);q04oY=Rd6Lt=3R4sr=jfeca>+&OUvAWZQ!sdeezyKa-0c-*VXu4le2ezM336 zqbFvr_bHS@dHwwW<60#HMAcB*M$Q*0W4K=BD(jJBJULO<)(7AcKCd@g#_%-6)*kjT3^)SoHTjmZ4)-do7pzwwYsA_r`uJ5CI-#H%7HTvSfS+ z4KXp*9@r-^`NN%b<3>{-QT9b8^#km9N^MoZ9SDtt)SX}o7i?;BXl`M+z>7Fq^nO98 zVlzG$6gbc9DVM*PJ#)EO>7hUbA1u9pKOs$CeW;&c-e}kC9hBN9S_RvWo@>Vt&2-II zfec$dyM%F=RX;>m4l?x@`p`eG$OO;*GJ)=SX$6QvD8Z$usk3AZ2d&|S3UFFXpd3lb zA`}iVzo9Kr=U9uJwZv%)yve(Dod)ywqrk`SeH^_u{Vj? zTD(>Rq;cK1n#}s_q2Xa^$t%e?kqS#OO;#CEEKxP+eAt_vAr1I(=1lY&cdwH`_Yl?` z>P!%o1mA#oX>egIO^LwS)UFym+XD2GfisU`FlsYH#`&9vdkUy~^m?~Jo<19ooY29B zxYk481`mhvR2i}wPCP>@f9OK((_}!~qGwAgeG~pCEr5OqpFTkW0qOrGTZVs33uaFL zCWRr5cLSAU?C);kG3dPj;(%~XxutciL_lN}KG#ansxh%<9?kj`K|gQ|ytJDW$h_Uw za&>0cMR)arYlTfmn|ISfK)q2%+q&Dc&DJC1>Q`vpG50YN2+01^fIzO#_QpNm&ar3i zhUfis52HM&<)9!LoabDC5u+^|BUlW^!jlmJ3SZPsoM}oDrj^euEIu|PoGE#fmr?{X z^avl;voSis?Y@#vco^dS4VJ8Lhz8-|o{2tR3}r+eD4|7vBKZrL0QFug=6Rmy4cd&t z{S6%AjMoh{qQKNe?(J>^`3s)F43)v|UL+qM<({m5$m$tVPU?->5x-JY;tNco!3{}J zjm%3%2qySA#G){HCX;p;I)5P!hz)NHO`!~1S#g2mIi2-F26&N@+KgpcQHV<8n!PR9 zpC?o0B^^{5ib8X+W>+c+7e(x)B}*x|?9#`uV*Oy|bp^VzIcI4b~ zILMk7r<{oFCVcBELgZKDVl>>1v1rl74}k=t8gQE2Kw=^6 zdv^~fJB&!1uP_~&OCVGO)$p~Iqs=7W)VefI6=r|+kfLj#yrb(KborjJ0oa}D-u1~@ zE6+gk(bMd1=cBs@8qee$`KW#Ro(8IP5L-~p`I7TTBi(=%);W}V`^eT3h=QB`#0fP~ zo3s(-lZ6#v1mv*;~g2r<_{8Hsm>qSlDSBoq};g5Ru3i79wm3V znJ0l^Q!u-=ut*%;s=3huNMVA^URh*G(D>Ey%hopkZf9@n0 zf_t4${cyyqILOZlgCM{Gx6_Je3+<*%UOG4+tZ<8m4^# zL|wM(4dYuT%td9hY)9&`wAU*1bDCuhw~+bh47=axLGL8q`hE!YwlJAtU8)5}J0D;E z3gIatyIKybC$*lpU_sauhE6r@jNzne!qi?(SV93c|K;cj z29eBF98sK>^i(mNR!#xB0gCo0Wa7)kRALIk;un;A=b$w_b5kOOZgIoD4D&OC_c!Y! zRv_gt=%YK>Tbs6dU-d41;54~i4OU=Cxh4=aJGUtuEBCa zfl?ki!@MutBUTCYpP^9(`x+pwD^o!XB9^CXT?z`=WgZc_Up60r&W5|U#9N(C^1Wx4 zuMl@L-Jx9WpZ>^D)s10OvPIQjh1OZ?1Iy?uRYF5q9@n)wI1L$RCFqNBLP~LwvlW8} z))WnG`7sfWdJgAKxf2n5(V2#_ZVquZyLb!9jY4v99V;YwWUc1Zif137)|(%OA;FO_ zm_qeG2-9)tlkHR?>faxx%`irr!t-(l zMY6bQKWKfyuNdWb*5z56p?VY>d@HcEu(U!IFJFgx(>J`VrVJc9P zSFwn-pR3>HPx!OYkLYZP64h%y)Nt4HTClE2zB`%5#`|ljLSXu;t7>N)``4V7IfWI2$WzIc&7RpdjLWJ?V|Oo=A0){TgfXMn+S+EF^M2DO( z+Qv)1&HNirsr*q-k7<;(Kn$Ffez^lj6b}$`4;TTyXc|7ziejygytjh{h( zXUKqV9k#fO7vfb@^a({9Nd~Rxv6QzhSJ=L^hcnffut4I<6-T^26FWHFS7(V#qe+c) z&7kiI5wuqdk@>-O@Wh{Ih5W{uehWENDxL5zYv6Xl*sGbs_xqEFw8ps|^7A#ux*PN) zc_X#l9nQczSrQC$^2D2CMP%5eH=o923MJ_cDFijS=}|KEW5w)&3{duIR=Mi_u5%Qt z+x%&`H3k^W8F6qWkLJnDqZHp#5L9{6?CUWL@Q)+; z)5zNEi@=UXb~m>UTk2{^{M7?v*X9B7kp801;F8%UfoLV0NGb}x3p|*jy#q+yD@)ez z_d-}lTYi+=rTBis<5)aG8r?IGF%~Gno!V-gc_!gNyR#?xx_QVFGSx@XTv_u$`5JwY z&UAOrnCytx>>Q4Q-sTV#QEvX>~P_~g)SdNf_t#pwKa3|&>_sJ?{Y zw*3?0^q*rT_4;NPlhX|Bq?wX?(5z_$V)IsR3_Nsb;_>ngD{j&3F@DLqQwGH9`B((^ zG(O|M`5GTVViicW=TCF;S0Vi8@a(g&QBBO}z1e05Q;?Vj*!g$I1^f;A93L<5o473* ze#Hy*v;2u`mWjz=E(oX<;3YBKL2pYtqCtEzXG&{J`dJC*kfQ-M{{UfMf{&Q-N5n=! z=?cMZwfp}kg9;=PSu+9y0uui#g8Z`#O4-cW^{30fGpKC!EfrifwC}Acip*H@P(@4O zS=I6ocyhIhVt7Mxcn*3(ThK-@!FFkeTGz~>DZrd#*6q$s72_E!A`fX`S>Zt<;+I^^ zL0iWLn~>Orsnc}ZbC&n?wa;ee$Ln*$4p1j3X#`zKLAW7L1eQ4oSr_9dys!Y0sXCPt z%$?HYo+x-r0o87^=B5%8p*S9^5gk-F)u=L-J9rP~@F!D*h%Sa{sBoE+BNwLC_*W&Dvr-n6Z=3L%fbf?a9m~A{g;`6ZC#B7{lX7UKE%KJz~I5ue}WtZC}UTwU}!MH{pn zHv2%jQJPFPT909dj|wM0mj3JqCVKZJmO4GJgy$G{g$(obBrbdRs)zE?Q@uXNR;ju; zr-thWl8wKLTQi&tw@dB{E=Avpe0+z6Y#cUs>(jg;HbZXO>6}cem|NSodyz}$e7|hC z|Mslhcn9N>d9AA7B(1z#6wheofZm;&%ls4UlA6oIxCQK6v%%;M2Kb{4p;R=w!fdk{b*`sYkdpI%yh`soW3{K&>-kMU@P^Enr10skVBT z6tHOJU9xL}j_uPw>&wOoo?Gq#rYDY#4se#do#udR7`Mftn_1HM(#ud+0>?BBCKkx~ z*#TD_F&{fu?N3~S{Wg*~ay|G^TDzs}h@Qw6^4p$yU@0|Au>70CUE4h&gMt8j-Dw9H zuq`U*%volE`Gtxj8tYxThgD*rbH}l6G|LmKKNGp7HNny*FNI!i9n7c{`mR#!rr8Y+ zoH+CW{pkhS!WKj9>z%oBBHo^K=0F)^`+7M|Q0ISj1NNRj02N!|{9Qe)^RPW~5+*DW zo92<=H8|VBcj}DeyHETUvrB@tO>{~T6c=8B0}D1USL-V!IH%p8DOM;#d5D~N#3Xa> zH-kZK89-aiET0oHBHKN}`-fSGub}uaU;YXPO14GMU3#YWkYQiMqMA%d_8~v=g7*uc zF1#PSE&!tKg;>wg7?#J;85YMubS>bOd=eEoz5xT-5wdfu%W^gixs0@q~ROHu)3ZK`-k9(`4zDa@|zB%t(_b*p%?*0$C z#|B`v;4ML`Q47Litz5yABxf)@U7!@|G@8g{Elnwy!^IKD%5!~=W~HcQ#j@t5{zhY8CGXYRWIRw(`@_c4~l$d`lC8+FL9Lz*?PLRRP+>P zjn4J_hUuqC#rq~8G*cM!ZFJOLt5k7nAY)SXtZQ1>OpLZRl|su9l;|Ly%D#LS2(TUr z*&xC?)jEt(2|7{to}^~j1J&wv;3vWyt5494Qn(mJSm|5I7jORQm(p(1RhE(9RU5Lh zKfTNzE~v*UfDeAojg~}(QY&&2MieghXC02k!d7N?8J`51q3uIPU^urV@{(z?8=jW2 zLOyhwHbx+zL!%R7LTPcU7Y?wwMreqd>XWWHlF0QCL|iL6nu-wwtER)<4i}lP(;djE z{W4cZPDsm7XGOs(ezMz|SMv$-+LEuSXH`p}fCazoIk1!UV!=L0%Bj=1no2imZ#woF zAJsvyxX+>)Er9`XP>g6UdnxL@l@bqITyhb}Dl1_^sM@k5s>@2ggxGtZfFc8cm7(e* zGw}Ns8$LSR+H%B=;c8_z5|l=uVvj`N_uhSL(H^yr@Bro-Ljr9vo&fJZwkLUm=bN(I-Lz##AK#POgfb(iG@vjw|v_W=w zl~r;5vc-j;Q?BqlZ|r=rApp!)%Ms~7+iy~4>^lI!{-7k{+R_7hXX%E2`R)BBP^j@v z$09}NElgg;i?UoJ%M4t-M!#1s-x;S_?vyaai)$B>Zd+ZY1 zGy~wD4v>_|QVOJUHU}j+*R#3tSn~i4V$cwsSHTc-9H2 z71ayEy}({GYyvO>S{DrrIqAB*}j!>v6^THTL~v$vx-v zJhSktl@svePE&NA8my1?jIO){nTt4bnkC#fV)dQka)n<5*tVwgJ(m(=XJF>FptTM= zUTX!WpXG;Im8@KkbvLXRI7A@wUod5yo`R z6J(fMS!Hn-wurvY)iL?LOv5~0Y8@E5Xcaw}Ze#BT{Y>{{&xxK+(?c+i4aO#!q%L*t z+olSJZ>uH7m1o{PJPRd?u;(GES` z@48vDMT!q2gH^#_1YSktzb?WTg*Q!~l}(oBc`hr+KB( zZjh`@(AWg%x9Xeew+3C%dIB{*F#K+L7bA8|qF+Fb_hVNnzCyZG3G;avoYQibTtRc3 z{@RR11l7>-f-D*~5z33@6f|Cb3dv_3jB!S@`>D{kj+yE6M7Rtjx2HVYEY3EwG^NAq z+!3LOHwJBWK}@7bDI2NP#c8q%@u%#={-4wE$%xml}b}Xu_XN z1M$0Vk{kd1P>}l^%-g!^2d%xseFaInf#_PqWbsZp#mMTK^h84|oz+q+%<^B`C1x3v z*QUgOh?K|EHo=25#}*Hcq^`8LjFB@I9V?t4Qdz}%k~2nq-`UbDL7VZS%7KUS18(x2)p}6N?Lx92fZ>U$S=pCx=~30b&@1k&P!;k1jvSaz_!ATPi}61- zaH|2~2~7wfpm#VRAjW^Bf&Wd4oUQEb{$0W~X^g4hnW26A^7AjuHiIPyiGTpeECJa2 zWMtJya7a>$P@_L)f!Uwn;9Y*2*ZzhK*4cdCYPCrwh$3)Oj1&5$O|TeD`5Y{(MX(s@ zA7u8b?=Gsz))%b8ZvUFH~UytRKLot=dvWF)T^-T{+)Su5^yt#^&kSod;si75WB0b4!(Y`I@z zHnBpsVON6?f8~*IEpwWb<`K#4pLB<3n$EBl&6WHGyfH>AuxL}lE}V~pp8iv7&+g}L z(_58K%};|H9S8)~HYkc-@Vpl0tRULn6eg?mDLE6^+<_-+$Q7SmkxZGGJSz+?39wm5 z7=cT-qFY;f{J)lc!#?*~g&aqaeSgFr;x9zFrg4YW!X6wcO1R%O6W3adxeWM^*2mY% z4Dbqgr3D<7D|g1jfC9*{qw zj+9V$H(h97s@R}-|H`|7%Uqm0rz-63{-*yO=jg28LM3mtYLifG0Wj7pBb8V$tI21H zpgV5)8NtQHG1BLJ5R=ngrb770%7|4$;b8$EVzW*iZu{phMbz*Q8rNE@NoG2+wNk4& za6PBYC^)>;#5LsQZ?dJojojbS9Eo!?x6=;9_Gqg<%LCS{ksKJ%@Tq%F@Q;?WwPE6< zBskSVRe*N~LH-z8^Wq>#wu_PA!H?o(rJFcF*ll=_Bs(8qgxzHyI?z>iW-W`e3iv3e zboquXM;q*rey=EZ*@4{)jgM5Z#R)<6niayeWk156+C$y&7#qp!0r>u8s6&U<%6gM8 z0C3ji`36RR$pM*x z0s{^^#=8c(Qfm;^z1FW<|EhT2bmNVSUiHN2)ZTnOB};!NYf2lCV>EoGzI}p&Mg{v! zFZQ6ZIAiO~+~tN+%6G9%ZMOI2?;#RCD-3g1zuDmc)*P1F;Ke=X3$pkQBz8YKj_YGy z&u~S~FX+W%`^Ra?mDdeQbrPM`#N6c6$SxVx=9Z1znaHQ)-Gtfcvj_Cnv$-mcO1B-a z2NP`idxV71zauG!z-mkzqpIL{f|pv>Oq40)33?xAJY*Yrr^`DFpE23@F3|K4LB=y%8c{xf*X7TBUfe6V>8WhQ7kWfdO`XIW z#Nm9)Dw*%G`NE0Ow1oP*qRjW5im*%hm*x@*=UC0%mA@2H_x?_!rbBn8hv^ z_k}~h*%`0!>4D!-5P~5oa1LIq57s}%v+#9TsjR8C8y&g!OIpr`0nwDlvbuwF#Rf{m zp8%Xwcg{i<#Oaw*kc!z*I|oHC(idS~YAQ_6bGnGc1uCtsH?-wRW7~w_AB9PL?k8yD z+v$iH`}FgKc1TkjSCG^~c+iO2Nlq)L_Y-u>Ssrg^Ol@kx=7gJ3iiwN^N4iL0HaEKLqh6A5F5u#_zf>39ZQT3x0r*-&6dCB@QN zH9k`JZ1w5uOo8;brVb!F2V=8fThkxBR*PVNaktcdbN(kuRb|%!k^Gez zW&YmZq5LN#^}jl_>b4rV;%I&VFb;cLm7+$mB;^7?0G(llWi1C;AlQA-8WN68bfPKo zMxq^G2QJO=i^<0>V(m+y^B+9_0KxHt?5PsDc)*|Fk2YO?Y!W>I}LgV33Bhwd^~5Gh8jDVFCYL#`E*I`~WC zd*Ij<&bK2=U7(PfTjfd0#-?FDqh@zYV#3tWTl6j>PY>J$6GQH>L)P4Csw|;=a&_bo z%VTpcy3!i3?_F!+&$bXX3G0!V2gM>vE+N$Qa&jw`VQ|%>#_4_8mYk~f)7I@7*L*c) z62Dfo7g^J7S3D~w;pI-`e{Wb@Qw)ft=-d$ta;UZyFa2qEyenKvv1v|fK@pkN2Gh4x zXDuUe(za&Nj-k`H#ki{G)#?ak9}qT$BDJtLA(bP-cdx=qkw^<7#y_P9C|l+Qm}igv zt?I<9IoD?-orw*f(pe@ENX$KW9H{GUKP_YLKE*dIsZ#prA5To#>`Sy$6`3ld`Dh1f z3NP04O20S4`A6hmSu5d^v%3z0e)@LmYsj&7cDKv$N-l%SgU^_E9jaz4Sh+{Fw^#jg zx^uVE2(bcUg#xdQip3@w7)I(v{W%-|@PwXpgD+|{s0ODZTA{=JrD9K3aVDvL@2Whh z_baW31p@g(<@P;?nCD|1HnKc~5M&pM8SHXZM^`Wbw#mXeTmCV$Vr&@;BW!v$pQFgV z7!G;t+-CSV>tN}TE0}MeVGbL6ES&Wt^}A{vkmgQLp&JEvV2sK0T_d7=^7hlAa1RY_ zi~Qid`0@;5`6SsPyP6$Qq`<3`J=mQY7Vuok4|tZ&Jzuy^5ZL*>L+YEafOvo)&>L3s z5Gxh?5Y3oCaEWUWl=`Jwzt~_bsCyzp!A-zFuqum7valnG@&aNvSSwQ{gei7allYLZ z<{P#vz;83i>5ZUqh<4>1r7_Lqh){;I$sL@U-S>CxjYLw;X6MSlVwGUFWY3nm_d zf#G#V7_m9dVYk7JuxnYqkAcKq$&SL{a3m`@N#60&y*3rIcj1rZ_>(`bFs}*OCXz?S z6$P@Ka(lO^Q$$hjANqs^GW$fA_)bw}5e(1C577UFnYi9OpQ^tw)AhHT!SzpIM#A37 z*2u-h%!y3Q%-ra|`WngVIvP6SXkYSnVIeAcv+6;~+ocppIAWDDG`0i9Ar!M5x?<%l z(iD5Mq9QZtLbvLVW1Kra&tsT`owMO?=sUU$29KBzVWr;F&|-Otny}{AYxh&ztUKG@ zPG29#D{??JdyzmN9t*MRo#bJDf+FEd2Qb?y>j8usj#UUNYJ-P9Oaa7jkW4|iPFTs! zA%rHa*g`1O=m*O3qkAcMc90H`R@^@zm_n`4S!uSF^6reAlMYIPs>x92_;i>(7iU@L zD%+arWagsi3*9y4{T+*#3CrB*Qbe_Wp>31-Bg&Z|*M;??Rj6X|{BYp6#af zQo;mLxOEYuSKH)vly%naGkU2s@4a&q_f@P$o#9}68e5|Qmd(nla)4ZlSSGcdoW6`e4(cmMN3YNPnK2PrX6aF%7 zVHSYNo;56sb2VOdZRJ5oXqlFZ+HV?H45oK+TD&UvWDBoOCq~H<$w$lfM+o^I2S!sd z-$rwgA08rw4Xv(nzZ*h@r=ATe2|df30UJlXmL?1mXZa>SB9_f3N`cKMB8*00;f9-l z=7ir%nCgV@qhug}*V=Vanbh2=kFJWx>=I#2T~V$%!<@zMWp+zk?zB;WI=`(|&tpC| zsx=uF3mjAL)!whO}NYG^v&qlDROsAdAd$aaa)z$0`0}id{6?c%oub#ZLcz^^@kL< zU0N+UZFD?dE_~iTF+Fx|l95P}ne&A96pIIetw3yuTOumzs*R{CPom8UGh*P|Paxs+ zC*S4HNwzhdVh&T*x%LBsJJ0$8HH;>;MEclNc+#mm-2|HKD@e+jGi5EVCU4@0ABN*v zJN>zy2q8JdkropaxpS%9`o#wFf+uzk`C8q)4-4ybxdaIe^(_Z*(H2%5vd)}i!_&F> zE^hom6|8qqSA;)zxxF*PhJkTv5+-acdtI|AC$ubZ8FtNjmrb#TmQ9JUkI-FsjFNJ9 zMe(cnFLlEzZ18goc3p|pvR^OOUSbt9&-oN~b6pdeYXjdNAlUj_X}OlKiFF2ea5#f= zraX6iOr5*Eo&7-NKDYB)$_j&y((_ti%JR%g%;CJ;rb(w8H;~b@PM*a%9O{Eq&^wtH z^i+a#zE8Wa-nb^OJ9+I;~%uf zLVJbT&oy}C8q8ykYe*&LQu_p3`GjHLv4sjseMdgryUF`B_5?79?Iv&99q&`OJN`B-^lb zrd3mg{0wuzGfFTalZE<%{7(o3a$FkU{|kLZ!2hsE@?Q}6@02TAVL~267^zai6iA8S zwm;q!akr1z>j5G}iezs$Ugf&P(`=KS74%ona3A7LAzZ@?j|gEqO?LU&;_=EAXfLQX z411_-C~XkVcoyd{s`UXIIxo{j7MBQXUB7s9-~;kFx7Dwu{Xu0Ywp@Pw|$jm zLxijG&W=yX0qEHmQP_#b*J|b?^it|i6IAS~D5UBh^1{jP`e$SNl}`9NPD#;kyby`2 zIlw|_&ajQNNbLK<=bVCP=n=Jl;rCT`;XX>BqL6?pS&|}jWx$z{!7iU6ZEZsyO#yr; z&$#6^@PD4y>^CH0NQyqb%oXEyK!SV?WHDpC>(HG3*T^vk0u6ESFVBnqOx_~Y% zFxvH(c**w|8c#=RFtJ=Z6J*h5pK|`_X|f{s>7mdYSleuAHayQ}_s^G|`%rz|Lq_h6CCEor~zD%f9LKZ7JzdBVl z=et<8jCHYo!~NE%nS}Vh(YzM2R?MItv~sREobPM{+sEp1B8yj(o&u{=qvjJ>XSK3I z(&$uO89p(}17maleHJUItMY85aVjx1YZHB~7825oI20U5;&0+P8Zl<6=I_NtLU33b z7Aif^1txj;TH^HHBqeY-JRL6x2N-iv2 zX26@T2B2V|A<)kwe)}&hBg$!oor}XF=SUo42a1q>Lhki1CWpmU>Gbbl-BIMB_^>Py zM2VjgP#DK{{|twF*1}iXb@&0a%^#EbYdYN`%xEYSnQ^Xot@FNhv!4?}rGfr-Fv8pn zgXBxRgv;TY=DDtGe1hoV`+^<+-a!0Nw3xk|vLLqQc4SvuOVaS+-pH;rk;$F(t(Z|D zfTob=YWOlFX#%T#rV!HlPc=U#{j=*Uyc{DPqU7sY+0*F#r8)|Txe~i7*Sn-qmTU9b zfp#+`=Irj$ww42wJP#m{_3lA9erJK0m+VNUP(e9_bjV}1YzTI_D+ln9W6Fux^ z6pphfVu8tf)ThI_G8YJQF6wfxAcF^L>-^jA()kZ9kal0IqZqB?lBB^gVOMJtxe-12 zRp0B%Uzuh&e&Q}13XrX@Z0iAClqt<3*@a_k4gxB_Wmetx?%6|%F1JEA^Zlk<*>TGM5OO|y2z$q;{lb`en2I2cH_&w= z@kewBhqA9>c@57eF79{l%GO&p!3E8S-Q;d3DNrvKnYElI()(xKUZm@~=aup3#WTF*9U>45UbNTQla zN8x!<r|j!%xt z6D4BR2^tl^R|9)fBd1vUhzWn2h^{$ zI7C~!&t|-?rzM)qzIWOEzG_ zeRfuRl6=Hiuqe>$&7yL_cmGB)@2v5IzMq+K>y4Bw-Y)p%J_PBZRWu;L*1g9Jclt{q zlEnDtU?A^Y~S~L6A)=qURsgpn)@L(5xE)VXu zw+Z$Y-aX;7V^nX@ML_k^oFj55_?InV-fQ$n=H&P%jE{CWQw+5(YuiWNFtlzjPLTcS zWX23o-Dz_&0%;WL-}>!$V_ruOd-B;bnz7W71Gk#FNr;JHZ>HBagA;VBZmIaH>~XY9 zs^t2o*-2M+k0w>!b<_Wx1i=@o>$Linv?GdClDWUQTy?sDqZ#*Z7`K^@SV!74GljQKpYlazV@$wW_^{hY?wF^#0mMmQe=6ftY z+NRwy8F0Wo5PCvS6~RQMV&b_?wc{sV3!H`y8I(hi_B1@>cKYqOK#w2O zD#6<&N0< z5ol{f%K=`T|ETezQ6FRw}A`gh60GO{bDtww3p^p z@m>{}S9dx$CD2GT6R+=6;;}t%J@1An3p)23=W-aWDw2^DFgegonu%!~V6z7r&L7W* z{5bDF6_SFwf*7jO!4IL{wv-!;w|AbPWa*#|S_L}nLF_!bK{?uT7A**)rT{0JUX+T; zY_9yB(YkoLMmvaJ=>+dWO8y&&Xs+J8M}iAQ8I8Tst7^Q)ruEXOS>>` zq;-*S$d$C_C%B$L+ihrAa7ut=R5Q-jI7L2UCCWzxEQunyiD62%odon2kB zr+=)??r>tbM&jMz=;t4sZQuU3`wT7t=jTqhiEqZY?IK)7-(xQvhujSDO51hc z*VylRMj{#5YkGmrUI3Bt<23=}qQhIb~!La~MfiX*Zo(0R;AGTtCqQyQBYL=GuH|y>eX4j$(~rmBK(}=E6kGmTn+ue^-3z?;Ku3aG_tpD^ zgRkac1V*(kBSxg#BzL<|sYRDw$;HUUim#2+mY-(CUuHPkt?2_v<$li_@A~i-J2!iW zW9ZNxwnq6^3c6Ysn?Q6JZltApqIvgXkvbZwzVTju(mi_(hcXpCwl|7* zWqg;j20*XW1fjAH}HO&e-keA;uK>N@2Wopspw`kJ>%(LZ*n5AH>5_2#S3(elPub} zQQ7%=G$LIgJ9@?~t+x`oj4*=Q6oAg`y|f8epJ-c-+a}%SdO)hdSip?jZ*9OBpS*!< z-5PqQV7I0xd9rn4c0LbkRcPS; z1f5$DrhBOIO(18nbu$i@$gEM2aBLW)BW+n+S!8uD+jAVraV0`)=<+fQB0S*-nqR7; zOXQAOdCxYC7ym9*9J2tGH@8m&1d3nF58&p`Z-+x`Hi3n8B$a~D7T-!g+<7Kr>Qx57 ztg_UtiLTD<+zNf;VIYTW>ghQVzu)!<xH|pxjDxih%H_<3~TlIg=AZ|J@Q z9sO30T$=Pp7v7ihiN5mlFT58~I5!hNce~*_5}TZ3ek_p`VdC}BZHG)Oz3B@js;wcA z_|HbhXktF?f?~ie;S91LluNaG{2|ufw(>$c?0U)?jvkPt-HlE6Gh=2pt__{m5{wp) zRy^RK(csYo#uVt{4@Q4iq0PG_zUH&+X?BJH!BmIp4ecAUHXNST>TqO!U*%p+tP1;r zUgWj+$74o#>PwmPY%l2b`J}yjdvWcUEB5)2_{2ShF}TRW%LNR;dgn;027gK-XI&0B zFXB5l5HdVDOot6yWa3HO%J5bjtv$61YjPK#kX~GQ%nW`gU_LSiY)_e!><^uEq;X$( z3SZ#2`O{jXKY4}?kvw0lSYR5BZr5I>J+{iCM!hevLv4_5=mlBKffLphIUVv^HvSxE z>V$&!k0R}6WZ3n+f7Vdi`VlUEMtRJE<>8-B3#h>_VVXGYqfx#6c19tH{a(kwHv3Kk zBrvw<0w-fF!KpA-SHdk_xA?t1!+gu0Y|Lz+UO7i*^_8#aSma+8M@w7s?%SGdGIZDT z+I7(T1$fzL_zf8(3QYAE!a|PpHpo;YzBn+qbIq@gpmy<;LBG(Fvw>azHm{2I#^i|s zROq$rFz?H?T=ss{lGH}}w828=n70<3y{N-7RcT&XXsWOE!FravXNGt_XsD6Wnb z59O{JU>-X-0OLF5_Y)L&f98%h2bY&5VRvXDOtI@;A%u+3sEB;y3^qX?LxeEyv;I6d zi?%z5C3P!(*5Kks3m*ogyJjP6SzN<6#&mc>c=E?oOLS~q+Y>3AGqXF~b>ak6<6d9( zMuY3U6*^^JyY3oHw{f`H@wp;PE66hr{T_Y5$3nHO8qO()esu6#{)B40xr_^3dRMvM z)msP`BeR%dfk51Fr1g;+U&FTvdUq9y#-YTUb2->br1I{z!=zeaKW%MTei%$TO}_8* ztN1GZcKPUhlPc9WV;c9Y#DYuaH6TTkrFjB2s?I;ZaZr9dUsd9+0vlhZu7|ysP;C!3 z|Gj|Iw{pFTG3mVH2iI~>a2cB|Io&mYo%{)OB&h8N);5A@AFu=JJ~g;j!KtuYaK98G zR1B)m#h3465%pSX)zMWgMzn3wxE7>s@2)z09%;9ubRmdgjdUoHH}`EPJ{4?o2beltJk)JdsZ=YzG9a;L)R7)J?5J zkxzztxkt_PXGi&}o0?GX{rJ%ornR;n(FP}K5q67`(Ob4U(Ov7v2rsLBdRd%EzvSdL zN0fH>HRDxU!<58|Wv`cuG==LW_M$f{ACfJ`#R7Wk&m$Ip8M*#=$^O`aJIs3b(52?% z3R1B%s?NE>_&%@D*eKl1cq=+joF=i7dEh>BVb@RUW_Q}ddU`bUB}~9|Xl~`hjxeXa zmHRg}|Hp$SFQuY|T$OC5f4Xkkbk6BF%b-;J{FvOrH|gkthHQHBIW&!XU*~Bjev_C| z?qX5mjP9r*&*HSu0&bz@I>j3)Su=*f^wTN4R$*dCqUJ*=)ub8nzHgSK3A-d@Q=E)_ysSK*rd^_tKig^jx;+tt{yZ!M>rN?ITwGKdb~Lt{ z1W`n7L26JQQ%7%=e$y+Lo1OD0nN zJr}99o&Io)ZaU9wu{Dxf#CoO&=h&s9>WJz1K~A-ty?j*k@Iq0KlSX1Iyb_r{NW#e) zC&5hcE^1YN3!l;fyZ*s_rRebNu{YEP*;LA_=N#^}mYG*Qp0SqS4HGws7#F*!sT)tH|8w=5_MLF!-d39Wp8)&X$@WImDMRGmZ$3{4?39q z95B%sA8z~6ZsM*KBFnrb((CKXO$^!tR@YZ zY-M~c7#Oy(xNX9dn!LxEN;VLYJP0+hG>$vFg1zjs`*|XR66hKnBAp;}KM}jEOzGb6 za`@Fom4{@b$7T22(rWI^>5ytj9hWSTRl-CD%Xp8qN2+ijhxZXRhul{8S@X`?r^7{S zovEn^4@2+5qXhg_3^eh`Bpbo9M}eBAp5_v;q1!}(hwRVSETLnOoL4hFa4RVLs+sDb zg^26OR5|aila}uOqRqO89}mflWm4+hrkbnWL0#RFb1TooF#qqK z9dPpxwRo9{&*$weF8J{MC=*SIGacbh+)u5~l-YQqL~wZe9{hAetdP`4BW9yiPh ze%y6}@8;G?{(OG;21Qbfmwx*BR&w0?58bqCUw6AsE^#%_ZJBj0=ViOEDi6Df=kGsg z;_t-|+(VZlu{oQY;M!Gv)zUk~uB|FWT~=g^ry3qMR#c&+%FVr9_%J8g!lYVxFkHI% zlY9VSVNo9YvlmFMh zNjrHS9@%q5rCpv?Ej}g9N^|ulJR>`#VMSdURav?YTm&SrLCG_G1rx(&IopoewNT+5 zTS-dPjtSpEMaj0uw+kN!#-16iUKq`Ib5`;t$;X|UIgN}%d?S3Hvp6eK$hHctyl+sx zIuHHOcYLL3SN^MFq-z3;RBo5`tBONiSTPLz8Nbz0;$IBA+*vVcoVDeKx4qtS;kbY4 zzW90Y{+{>y1yU=;M*fs5pC#4oTp!3V*@Z{*67IWs%*oW#P1s1x*Iz!nAAeq1)6@Fy z=dNDO^fvnDOUZe&-;Fm@FKYTy8WU!~q@fs!my^Hm!6dI3x+p0%*}YkGM%-JJF{*aN z8@P3pGx^f6h}eKdWvfe*dtxR(km%Qh-HN}iuR?gWe9*@XwXb>TS&^8y8v4z)^9%%pahtrghTwBTlO7pE zE=cWuef6MECdIsDU-GarcJmb;;bpzJcQ|I6lYc(`c+7P>!xheb7T!bFk9A4Aq`dg7 z=KVbk%t$ZRi01d&gB*wVNjAS)q-5zf;r6F)<)R)bpw*|m{t3Nw6vgPXR*@gYwJQ3O znNOlIiFx6kYK}MBPdh=H6W3R+lU6AbVI=6?Q9IG)VxJbaTsuyGQ4lu^eJq;cf>s67 z<*=sTG#cR*a*b!oG%dcpv0)`&qr={jbY3Q7agq@`p{oc%6_O!ST6E&pIWk{k`eL!& z>M=HRk(84!3=6t?qN7e1eG!@buAsu2ZkyA!DpAI0TgGXxJ3r#8!MrykHQ}5h_0qFt zlDl%}q*0~y%2-mN=2K4@lsMfYUP;uIyGC-jp++)lJ-J!q zb31cmeChCBEmoP_R6y5UOzAxl+f(7SJ)J!{lj#V-^Y`;uKhQ2JB8*@w!_I!ba6jFX zui>Pibu%@zWg3%Qd$A(7c;%`>8NBuXR(x$&zhwwIs~-xDXmvIC%eiE&WXWb-|3wMM_p%+@0=-`mbu;)z-3 zBv01A47}h>`H6W}%KIyFwEAvN*s7_a-y*}gp2&H9(5w#u`zOmr^+U=^hfT%kHR74B zp+2ISuEjIj@^HU+=JN2IHG-M0&c(ix@wUF4@zK8G@!r0I@!7sI&e*k5&Z@O6&QR5- zrqJTdAuA{)j1{U6n=PSwO%nEeR=&ffI@_Vzz=2DVU(=pHC6Tnmf6t88TIzc(*}&*d&V@^4ezb2U0y^bV?NFN&Uq@E*MxnpxU2KW0fTMc6bEBrJ(|UE$_IYPf zK4;=u+4x{lDQBIkxG8yY{?L2qt06DwBiPT9Ie~=|0RbU+qX35bkrP4n_6~~?_lU-f z#k;DvlhUS2#T7#aP+V9#R2kM;@)V{EjT*v%a>8g!)&-hNUc!W-7_b)T+aU;44whE} z6}W&;3G}O5J0;Z2ZL^rxjB6}flvTZ%6g8D7&KZ)0(!=6QUcgl0Y%tXlJJ=-r4(t+| zJG2dr8zP2Q52Zj&VK<>+Lz+Zvu%o$!Pu%l@&u%ofyG*!3k%u|lz#8Zvq%v0I8 zV`W9VWo2+QGCLtVMP!z@iCO8fZDo?TZDn&bMr4(@Wu<>KMPzU^Iy<&qTopg5Xlhy9 zI>a+|17=7#FiurD8n@bJTXN_?6^A#Noz}ttp4XtSR(D{VCbPFH=l~_oplhqo;@q^-5|W zIdEr4PRS9(5Plb8SP~9dfy+ZyN(Ldg@JA5bk`hQP+!_*FvIkLylR=bAV32XR4rIJ! z0m2Cvf^e2JL#p83kgAdkh$9>cLNp~>*f2#|=su-i_;c!hA)rcF8Q1{rT!pqN;5HcO2b#Wq>fe2 zy1Z1{y1G=>y0TQpy0%o#y23`T!;H6N4fSFLVfRRwVfR#|JfWZZ=^MnVh^MD7X^Cu5R=XMWT=P{2* z&V6TE+to*s+hIr0ZTOMGcG{8d_WL8z?KekC+pasY6B0XB6SO;_6BJWwh5b{!h0If~ zg~f2pElYUZ4`(Qiw;z74Z6!yZZAE2l%V3}G**#{|ttL2W-q#9;n3mx_jWb1PaxO)A zAIn9QD#4Z%yi!)gBwqdujrqY=0lZR9#L!sgsxu@nqpFYc;!S+<4>>4*o?gY7#2I(7 z_Ly&#L#$5+Q{4|OsC(|`iazFxbXDOkEcl_EuhAOoMR0u34^t>gZfiLc!$rI*<(4fR zUC!53^;sQa#AoS&-B)-Cw9%mX7;y+-Wf z+hYM5+;Ob!MbS=5(D1y_3Ja>e-l9S$d+6&iUHF?^xpE6SofuW{y%lKNm@r&Z`d1}- zG;3#3o|8GWB=`!BI~q>bK)u<9fN6vM@Q&$Lj@8h`LcJCC zu=p1xft5JLlWfp8HN-=*)lh16v}p?(<^#=(KG_e@9QEKC3od3#t#Ex>li~_EvNd-^ z{JWB_DxBI$Wax5jN{{RkG*&(MlLZHJmX^FetxIts9NCsTJbtqzzY3>i5)-;ym(nYH zL#;|Zc*%l?nNoXDpEj@<6Z)n;rC%0L?YlbKiiI$(;z zPujwf9c%pK%}Nt0afT*2pvw)KL$XiRnAL+fEohl3bxI6q^NT0p$j&u^@$X8fDsiSJ z1)$4~n!~a$)kxHXcP*%yvvjNtXlsiH;mEEv0r8uqwUs!FlRVJnrnw>6S89Ul!QU+C znJIPm3~0NG7vRY5H9_$VWyh5`>yyIJ<@a;LvYBeA>cKy@A2Mg@k{QrW6?edqJ)J?H z$|5Rp_9xk)%gq8qvLDpw)q_vBX_zVXUHyR~sZ_Eb$xJ@{&yDfYCilpP2HK(Jv00v$p?Xn26I zkI=9p1cXKy2$x1USCdF|2YNyXff^y0009>v7z2S52p63+mtc9nL%4xm4bxUr{-$;lsm``T$Pm7$=e5}2(bDlVYH0!ot1c>(G3 zWswGs;H$V;P(eiO0|8=5fNcZ9wgce006he@aTy?lE2umH7}E#PA_^+#phX4Yi3)ha z2jed!1jgxz3Zh$~paln1;=x??f|1ix02?phnhC^FHV2h+gf~PS4N&PrcmvZ>fDUX_ zflVO}@D>mFB1F$s0aAn*#xSTjgNg+>Ix2{+-#}Cl#vn$405G0JbcGxk9|2 zA|_n`Ab5SCf*AW3fJq=6^a2GQP>ceFGvbg00w?MKZv?Fq;K&y6Au0%4#CUE2G#G(` zd1DL)t>mCW%LyhP(Gx|0LJ%<#^F|ENW<&)sZ+f8R4ADn$dAW}jIAbSXe0wBKtB7pFMNZ@+_aYCd7H9*J!vV}N^-3SEXMFt=W2n5j=PJqA= z2q{1|0Mdx?@)c-xz|gi3x#|l>?}X?SGeT?p_R1-o@^aic@Kljky+ycJftP4mWWfNa zQ-PWcs9g~XL!ih2iVVzy405)Qz8*c;S6lbR&kMSNA|0XV0}3LbXeC@05i)&y_2Uh| z<$!$|P&AtW1utmj1^6Ndz`Fr11Qb|6Aq*5}AAy1sC>{ev3qsKa6oTUCL2cMqS-{0x z%1b270}48zAp-^21|fk$4GJzOz*LGZ@HBD&Fd6`_1TKs~ukG~TUiA!NU+J@d^koCg zy}(l}HNd3-t`+oq6%5r5a6Ne;1tP}_gS%4uwFggSV_`rY( zKq>%whwvN#044x%1JAwy+6E9efGhxn3_MOCK;TUY^fiYSfI|kuvFv?3qa16TH0Q3bw z)ButM&^gFN_7Kp>1sVxKV+Ckj0gYYYpgaeCPXf8i9t;2u0N??j5CG!<$Opgx0_X)m zC;)f>Kneg%P#OUA9YE^%n0pcVjD0GL5|@B;un09XOA002(_90On%0RRv7 zuP859!13*-1V9G>qyP{B08#+(0T1?|4=XePUKb^ z6NEsG5KMr8ix7-~zzKx&&ivEJ4XcnVw>BUoA_RnH8VIMU@&^>QGk8}A2|)OY5YmA_ zfe@mBkbw}AfuM&F;(_oPA;9E+rVE6IHhakr=6flEq6CUED5{{S4Vs`eGxlELzNo#T zkD5HT_SVfwRq9z##h$0Q7nnHejT?<%4S4SVKeL!EZ7xh%Chd*lP_*lsYNP6C@AYE!1>M!eIH4 z)jwp$P`z{I#|7%mVZsXYKd?!}?wLD!jHUbRCi-mpw#&$V-R;A=AM%CNa(!q)u=Q7( z;EM0%$==S5<1Z&Tm7+BE*+ghwP)vR_MN~F?f2?6?KB5m*qR8K#V;l0(29D!QJk+$O zdS%YO;m7bQG>ai2&!pNgABA|RdWkU&-;XtmWhQXOHY5w@!^W-hTkmAc{WhOIdaIF! z+mYt~^F}(x()XKBC_X&!KYc*!RfwY3g(2#+!i>|x^yR&O8M_tZw`|Svy-T9WB8OD{ zjc-KGP1BLcAnS)3B z6m|jT8COvzX2<%0IXWlhU$3;rV8-8$W3fA?^aq!yYYw^U=qAl!d|&iA%eFNp$38X= z{g~s_j3?z=ZtQ<(is`3y(WqJCa8`bz;F9;NlZ(ztt3u$G`&#jxd*Vy)G-3SNb4(rS zrG-u>>n|!M$^6^7&Ws5)O&e4vpBs*)t*Uao=xf}OH_$ zUksl^a&*_N&}qoTc*vq}mLiKW^nP%>#z2XNuaf-Y2XSg`%|y}rauZF*MflvZU;x{y zf6j1m`!~(MI|aMj!bTxmHTfek0QTJay(+RNbfAre)H0~)S_xpE)jK(&_Avvxo%ta-e z+O%h{s5q2VoyHj$y4-e2^v~!yWz>y6;C#=tvT=$cexj2I z3q!%|b-SDRvAm}|$0Ut=z%g(+gt@91r7C<_)opPdC9khgSA_{TAR;`Qz}luHgfZ?$ z$5aS$g-XuT3dR%ywPz)aogU@^HqN><>xnqJi3iN*nq4@o>`qn=nC}+WR6E!h_p;l0 zEM5p~F^oRe<}DF*9|-=M!d%NZ*1fS=EL`?u-+r9F(&;s&&&k5mb`lOBzt8AuKHX7` z-3b%eaid$DMx^2!I&WTB*f=ir`UYuLaSO#~@x6<WN7uGDu)$K(j_vI6 zWv}UN0nI+~o2=RuHD-JpJi?f|j$e0*bytzc7MD_RzpFGqa1Tw;FsX0dnX-8=D*NN< ziLju}0}A7r#UmwS8r*XE#C-MVq!c71WErG<4oreXT#G5c@iaeE2thUKYhzjKC_h>b^lHnYzhHS(ClosDu!W$xoGZZ^LF%XOmt{ zF1fxi*!QZdwcbn&9F)7IlcIV=Oz{XJV;xg)MsQznu)NA(9+oPz(yWNDwB)|wa1x4x zqc+}BIv}L|M%jEWA#W-pGl;0ehKrKL2Fas5pflj9W9)agc||=6N+u~wtU;|6X0s6b z#W(be-wEE^3cP6^;&~j7MjUHK_u&z;>npyHrn`~L>>sj_pExpPl?QK%^F8M*JO~rb zPJB4i>bWSDxpBs9)_hx!byx5851ZkmsA>kn*V^^&C~dBurI~B$21E`FwXbyE_}(pP zz_&uP)sbYtYkE^_>>sS%#X~tPc^S5+c3*$-y!E>^r}6Ck7eTp@=nm|D>xq*-5rtp{%}nXLx^Kj9N%_B;%JF`dYr(q0xmeJa zzHGMH>kc?p6<;B_+uS-j@{N9~gL;3C?OpWR5jRuJ*Fj*P(0mhiao@NWbDVL0kP0?sFR47fAqs}q>njNI*%-}Z}-v(wC`f^g<#@4CNw`KIPMT9crVoyv_vcTgplqD zg~ovwOp~THa#T%3BZ^8SaPvkO&MNj?N~$=;Lt6b^@oH(a#BUQp23DpACA>>bH?Qt; z)#Tey-OKRz_qWG!UhQh5dGh0C3=4ic@@x0r>KjDdTWM1(n>p_EM6sEU9@t9gJVK3T zHU<3Qn^)Hs1k|~x^1A?^#w*~PQk19>WKKgNNd%?JkdWURQ=j|mo24XRR(;;QKFWlcvJ`X6YuYBJl z`+#x}&jrr~UlW;|3s-mMsaZtTK>cguui^A68@un7HnF#PcQXP>lk9xXXG9v-GU?wt zNzQXk1$)ARw7WmQ`{j4bqcwtAY~_rW{d?4Uvf2#pWz=JB1Ia>ef0x46$CaOE!xCfc zs}Fxc6wL5%Tl1%GH@TVMm}gCMo%nb#@8T*2#>iKL!y3&3+|9K5PX=zyD z{X6)0;`g%x<-gq3k6ud9PN`HY4=;KtReRSxawI^E#M!C!+B{l(^Snz8cFeH`yX6S| z^*qX0Ss9z^Tm5Z1|MuNM2{%JyJEwoHCFm+^vT53T|P(=wP-H;_QgSceqUOHF`=i`53-4o-TRGZ?p4A^PzVqg8+K zkQlzYOQY5=$RTU&yda$gic&`5dSQn+?JeKfS04j^_37LR(J8&>Mp{)$kfN#G$g{yF zO%+t<-!O3A8dsFx=+7Q^$K=vvPQl;F-6(=0ku6{gCp}Z_RW}eDYS^`6xLUrfow^kiJeB|a0LL&54Od~A64jB{B*$Eo=W`)TN ziay^6)Gmo5NxBFbI6#q1cpN3vZN_ijH0FYVd`9-oH+|=e9PcFTlPZP)l?Km6WAAPVF{?&90$l^Z>e5FT%rY3mq&Y_uP{1Btq>fSEt%s;gT*`XmS=Xj%;U0X z1o)2+HokiCAOAf1^-J-FmfLDa_xm6TtbSqH`mg$(Qj=$@6zNAhLm4shD3wi};z_NV3+FNRkUN(7s>k&M~KTPPzv9^6Q}m5T~rZv0rO_YxBiYETBdT zKUe#%U-PE)4DLO2*#ghG#eK{X3BQzfVf^ho0$yy|t_$s(C`FNqZ7rjj{v&T`>vkz>74O7)fZdE z4$pgftzmlfC9Y|QP4yeciRSNL(N;3eB5_1o-Nm@R(Cck3RE#o^61PEm{P(Hh{*P_0 z;=@D{+gwRpnbp*wyX*`FSc)Iq$$rRyp8n7pvCUO(#aMB}H^eqq&O2R1Cc+t4?!(g; zH($Qa!us6(3Y+|BGS@&yS~SV3rVs0VkJLhBfL9~^4*}PKp_^Xfys4yZg$Jq{#)c99LHRC5Q1Qj#T?IAv=cUC@8+@Ybunrv2g(nNa92( zDX%p}5HADHi(qkzS3zO}0$D#^+!Iwl92nXiuobQr@$nHsEe}lbvsAZ#nQismTs0Z% zkqXO`%5O<8zlN^VhTYy`eXWW7U4k%ROYV)5^<*QQXSsz2Z%&`)Gx&wq%RyS(%7)PPFCUH9+!kb5e7f;X4MmX!)t@^tDbFL)OenQ+k;d5!tu8kp zLGETjUd1i3C%Ly$s3sm_P@){=DegGg6EwKgxZobDeS=_QdEKB0NaD6ef%xJ1(|&~y zr}J}Gab8}o?C{=*9AWXx(e0v22&uQ(y<5fN_-VDi^QCQ(y0Ib=OWphoZ53=+F3?@C z^YCa?^x=`#{b&9v7rBqKb+Y1r3g0ZT%7g@J+CC(&BX5b)yep9(Q=e!a-D@|nzVO@I0$1fyQ5jf4hMdboAje{=)uqnKVf@WX6 zb|zYn3yxQ2t>HO>{37Rd>Pr_eoV}y-eb(ink`F( znP~U(nN=uXpsL2z8!_i~!YOtWk#w24XGrN+bZY#u#Y^b=TvPQ4-z}5qo1|xF)!R@e z7?;p(v}ixE{|H!C{9|5~rLrp8fKy6zuxp>{|KZ0M$Rl$@CwYChe|+vgH?}c#GP{;u zDi@05FYttH2b@XPI?&#{f?(GmNusE*5r&J0%dM-i(IES}&y(lmd+O-w{XDIDj!6@< z^z~Ay>sQxP>USCjvB&A@o}NS2pS>@RFZ$VENjw?IMqMEw#lY2Y(&q?IrBg6|xso7S zH(qa;ohot59fOm=ga{JpwYAfYDN`4xS5Qtog)FW&o4D-!>D`^9bhTRs4r}Foe$J&{ zj-TmbJ?0|`yQZrTi_h>sd-msmg|})dqnw-Nxu&yQhF>P;;#qKKR%fCv#y1?-o<`v4 zE~&jQnzP*=DXz{|yJvi%vZ12CO>vJIGx_#sK}sU^;H-Jxgkk?f*LUM_O&SBX1i?_R z6BR#7{dc>XgvCW}UsBZ?U7{~ONwsuX|7bT%;+nyzhkNEd#C9fsqIy(Mnd{S{hA+Pt z6r;as8oi}G6IAPx+F{ zan0K_6Ktu7FuxC@V%%Q6&hJPmi>s};yAu`Qb?E(7L#&a~E9Cnm-KYc!gp21JwnN`4 zl{={-KT4nlei6xIVc}$H$cvyi@#!3JOtdUzT(m-$+0n7i+L^d|$ooeW(J86S?I7k4osq*-0o&kbLldomEj5N*dr zT>ilNV}dsgXm3h^1UCfQ^GH$C0?Dc669RUP?m96-D!m&Z_%31E;-E%p-U(u89e4 zL1I2SuS8O{NJ6QE6X$Uww~`)C-_(vb+pg^ld6ub?H9z;4eiXff`bC-~lcFRY^W5#5pchn{`by~;DHZZ3?Z%asru$^I_BYkQ1o6*&^RFzRz zA|MB!@m(NY|IN*d|NV>+7Bj5S{uH~bwN3V>(vB~m`#~o8r_2MJ5kh&kqzRIOJa}I2 zY|I{HZSu+K4dFO@SuttMqzRz`TNl&y)WIPiZ(pxl^L?6F66>Jo+nHK}aVXJQ$8Addh_V}KVklQUyhsjM#NpgzAe;L_ zwe^;EjzbmpEa-chd)y21)y5Fmxb83bG~L9xk-;rzicYUNZKyMQOft0EqUx>BzP+A#;HsjQqPWg2_=@yteL@sM5_eJ9R!ofViRMqwAVO}O|XGA0cTc5PIE72!Y( zN~P#6efc}{Y)gC!4s8|T_F^&S_e(hTRA9AY7R45GF>KZ0nz`K0~-NHArI67^; zB=A{(NqEfX(}!t;f?aKrP}NDl+v!6;?AkNShZSfe6vD7*E0HR)XsA2Ax7=9x3H#?X zb43D{yikaDQQl;1V6m6N}dtB%Yr%P$o?{9^!5lb4x&OQ?#Be!^KTEN-h)DacS zlNNS&UU`&kp^&d&z($uiCs|IGkJ6-Q$W>(rqT>>h_vM+e)v_1i5#}tvf`LcF>GKqR z+cEOG26R`CH$P%wTful$2{6q*_tJu@j@u~O`uki}FvAKK&ohqMk8g!KLoT&heAc8{ zR^Dd?sFDU1t7`^T@SnP|blmHGX2HeV#lJUU_l9gC7_a-N?qjUnFQQ#VMWdBqq*|Ma z5H-EpO9v|sf_CCK|8nADv6)xWcl2S_IZ$pI!@|+PMI#P&V!2vVDf%wlLhTckC(*sL z<~E(%55mtJH3Yfm*!Ai8OGO)CDPgpGUqblwSO|t`EAbngBz!iGq5dO5)FC;Pq#gD; zZD<(u;+x&CM8~hZ)o&jf&~^v1(l2AGUJZBHkr*b2RoOeMdY82-J04Ao$(6}S^%Z$s zY1N1%4h3OCq2A4uTK=E8zAQ06o)GbVlt{>X=VRsUjMEcXGS55r2Cd8RRL{@Y+a=_y zSp?q&98v7DR1^~*)T<1q7AD%0i)i#gkd$*qQ-ati*jL&$n~xRjMEZJOwA}1dYMZe8 z7A^@vBzs%Wx z*G+cRm?P{ufv#mtv8-f06Y}grzjb0bD@LY+bc)lw)$d_!vR>9(nH4hsd_Ck<_N#6649kCn6z&NB_XdnUvfs?=lez2R)tjo=lgL3MgIzk#rIWvP?SiZ_i`#a zs?9>!nMpIz4J*&I{jtyrGRVjXR_lbVoJe!kwbf= z3#jjChO2%MuxLNMxhVOFH9LKcj8GC4XS3^$2U}oAIs2=Az99PnssIYgaL=Bllb&Ve z=gW_iy7bunT35)k~nMdRQ-E5iXl@^OEG_4nt@(BZnWH<6Yt10)>>_1U+$ zDuXEGNge3XGwkb$zfwI;_$*ctuqR1z`O0+00{zWSx_-$|%qEeb6C!kZjl7Jm?>nij zH%+2LCyZ@sEz-|o43WJnKE-KQrOPF1_8&S-Kbibcp5r$2;MnJ_%4L+LWqXVCeF9rI zQ!1p#0baat#{6_Sg*j#zOPos0J(0qngE>N(3 zC4L&64;xmRboWAa{l?j4v%;FbG<}NeIHwi zJE9?#Us`n$Xpc)WehdEn?)1G~g%Hbyzg=YoW7h@je=Q83LL)DF!0PeA*N%ult-bF- z;_eOM?#V-Wy-XP0p8KWhakV4gJOo?zTwc;**m7RNA4)6}z9nHttZ?hv#~>nh7h6i?ugSRK=p7ygO* zS5LEmN>#SRD3e}{b;?4)OqtmU4w-QFI922MvpTb%ugsP*&2pt~8I>XTidTj`VWF&4 zMDL-lOnbrWlIUJ<>dh6lTLB>MKQRoiOc%pJDqe)}sb04Ml_E!eHr;0a%)W)np zB=U1pp3B`$j@CRZvZAhnNa@CUaM0gf_2-I-9ebvmxVIYjtjBy-bf{T$?cX8xFrVxF8tybZVNy>~?pFLdI`<5fK-q5QdxefmeLXDaIa*ra%PMawZ#yt%oLOx{D9cv?=)Y z^e>2S!^-TMc3AJR*G>Oq;x%km?zoaV*r~er`uZ(1$HZdPM)2zjE;t|jH`_)0@zmt+ zH_a4e(7{!Q7c<_jABpLmvGlnC&z{^w6IQS4>PII&JF&;NW>-8 z8{mBS|G&U(uWK)Gwe_zI!1}`f@}dUvKQGVzl^Hl4{Fm4Be>Jl*H~7nlpyU7Ya=&hB z=-_VWWc!yMNdCqC#*LEy#lzn(DgWyz5L>T(ThpM-0Vbb7Vf=%m&A)c^w;P53xFUbu zt>?4vD!t$r=vQD}c*Krwzh7e@KmR$Wh{^f;2>)<9mquFO(d?PNlm6e5^Sbxz+k^l1 zz6BoT`p>-oWAC`@zOQeb`P(=1{r|)_8eZ!dF z-uKA=L+`)0kGbyr`a=J|oyXAr2hRWeI9^}Y`?u4dAQ%7bas1~Bw|`vZ`+C=}ublfk z$~o8>^*@jD=VQ3O&g^gREFkg!t@l4&b@uuQu0N#sJBG6Ee-Pu(9$CB|;`$R8ze8*p z|HmQze1@(+gz(!nyXjxL{`Ze0Tpz{tThG5k<(vOys6V+p^3NO5*MnTYiTOK7o8^BS z3Zzzw-@0i%G|8>kie;Z!EcJ({NYq!4)@yFA}zy4W! i{Veo%5YpHGMUa1t00r!ScH;&K_%jF2%&6ZWYX1)-?cQzMwr$(CZQHhOW4CSFcK2>$_L+0vn|Dsky)&mGYDKJwtcX>A zCBDp+B`*aGf&u^l0RbSc$t?%)_W=6G$KM0^?`hyn2Mi$p- z4XrH<|3_owe>XPta5i!JmrJ1k{?=}kApkxI0D#|c008*^@0SP~IGM0A(;8VDI5}OX zYRP9yppO3Vq}^s=hL!+J15L%pTeJ2D2NU-n4Uj+|H4-B<(#OL@42({Jdymr#g<=ZU zv(}<%rdl}{l~}bpj}Ip{CN2=CO1QFxn54+@o&~A!zM8*X1*vG2SV?}quxU5it~^Ym zQ=F`p$+_k6Zl7l7zD@J-sRPXcOoqvvQTFp@%d?-0e#>d0a&vaNJiYFTq=AW|s>nU_LBCj;_*Kdxk#9=aFHt|}- ztijDLtxJ1Tx8MQSHxZCas}1D|0FiyOKUtL~)^NA?%lyx#*B?+{HL7$3VI}E}dQ!B{V1* z0qxEn_IMjqe==K0FH9)Tz?zkvlc7qXH>+S(avqjq>rxZ5>IjZw)>-@zR2=O)_Is10+0RwHV)z?~Uynw@&c%5;- zRh%(_mlKnvq(L>U!&)PEF>BhcAvPmPIu*@dl9I`gs9H!lgUxiH!K9QTqjpT>Sw0bm zhyhjPJCq=w^@uk5i7^_C9~1tn5a7r+fr8~Q7N<5(EB~EwPWWq8=Nz|3e+08ThAy@{ zr?HzwremcxPD?;RUZ}@(NT&0}KxJqes zEs&vM7nT%C%k7n62-xel>B1=58Weh~0W^u9FH&Xsp_JhDqzCYf@60{Wf$gggJBViB zZ2<$0Gs#ZaV!%qgwNC#@{1Z(+H8C{0JWiqt^j%o78{h_E_oJbQ!&}?$y5s?q6v3>| z4JEm_rfEzE4kBAKVQBN;o3G?JbJk9XJo%H)TI427&fp=HY2of@_i!Xcb$OGQahvaS ziW^SQB-U^{0etzFM3Owezh^*S*RDDt^Q@I7e4j5KCk#rstCMZ6=3gXOoqeNWd+<#U zdn&f@UlDTG!tO@!2Gz9h#INrlLgMZgj8MK9_fj{k`<=d~!@YJ$fM|U#bgb*DvfZF! z$2u`Z7r&Y_`wu7~{;LUHc$WNtztcSk3LqwK9n6F7&*S&lkuRJbO zT%?$l-TG!U-asCBh0dA>KM`DviJS@{LBoIfe@%r0CuhzL9PkCOIv>(|&d2gP@8NJ7 z9AK1kJb=j_(8PM9mpOndYz+eN_W$w?VS2@#Ie-t}ufrG+W2a-)7Y;^1*NR8r(vS4P zK(@g^ADt)gv{!f{qA(PXa1w_GP8$MYJYXyx#vY6CmmmIzmeJHq^6ewdcune2Ei+3%-3Is$#gfdFG+iRBwhZCADVE&> z`KmPfVxOZ4ZHVF|^BnfLDm@a!@2M+0I+2)Zd`?d3(Z&}TXTn;))-^@E;CzO}g$?xU zXHt%m!G>-Tw0UF#8Qz_LV%VCMClB0o@mw5(IHGc21zXR)rSLlYgCXf`Alkdz0_fXPnkx@A=t4mj0@HGvtF9}M< zc^;qGV;^s#Zn|uq1p&wYemvg;&e`2kfObI(C)y{m#W1h(zThaP*>dyel8`z>I{IU(pwEB_vg*Z zJ8to)+Eeu+uFv1Ru3eco5mTuIN#2V1*SGjKx>)Lr@9q^vf5o_Cb(B}J+ z+Pmb;cOa>bbyY?q-8t$FA`QoUXZQn@O{Gkoe%XT#edHXa4iQmJftM9q6XM0_jSg*Z z7~y9!<_DAN8}Ns549=sIF1U}QeQ~;-MoZ4+GW!6$^?7;D<%P=ltWxi-f0cO#U9433 ztt5f+!l_Bv#obGg56aF~!}6`lDcT2sJ?C+i91la8b=-({BN3L<w4qnU% z_k%h!DT_z;(y>*sm}`QrN8riWXDu;k=653m1 zH@|Hf`nZ~L;uZnfxMc>Rm2qZuijuLqE}`25j0RcRxDKP#O)5vD?o7Pbk%?nnHp$C4 zm2pru5%w`&qr?pfkt2SG9&0?fF_DKnYeJZDuyyLkIGTsQbqe@6Yey0{^<@#C*!U0d zT^~e0Ef>Hb4F5gwhl9?KN{5bjgkB}k==JDxiyz?s13~{_kIQE=ZuY-`!~hBaK>Odb zhls6_ow0?j8L@!1y}5y*iSs{EBt}`w4O#)^Tb6OWn89W-K6OP$g;4>rlD33-9%-TZ z>>`LaM>^IyT{b_~X5F?go~Ib5hh1#aviMC^zIjL`x&Z5y&9cHAMctb~oAn1EOU zfgz3KtQiDNd;yKa4;C;LLv__g03TI1VF)ItN-AR(t%D{vs|y%=GE+}LJ|LT8L}Xe zEPxTx?8~Ss+~~whMXRun-u!Tl6M-A3zVnD|BQ+-|&Dwq+hI1tH%^G-LKF$$@S}m3V zKZ?DT77JgUKZ^|!2+$caJuS`@L>=)U@meyaTf;E-NR4Qi2WeO`vq(yzxngFRwnPF12nYh z>lFrMe{Qc}AR}l_?b~v*Ds)lNItDD>Y&@0oG1q1^{ZDQlhGI&uBP0iFm~q1l$aTKI zKGjd;&=Uq}q+Y-EdGqv0nx1-sCa5|B%Aq@zLKoXfKJ`aXL9_Cmzoaux026R@8+APV zBr63E$VMP%58EIMU58Wq3(rFY37F!zbuK}8;>Z&dMkoghSUCraG$ki%x5VsNOJbr$LzNPeUF~jaNAP^VjN#hm{%HSR6Z~M0 z0p#`%4J+m$4413NmSc!EV~;+4^4HTxqH}G7OyL)_-Rx>`$o8)>xYNW6iwX?@K=ZeKA^HD~!T$<9HApw?Wz=uc%zN<%b_eT8 z32P4M_WUuRE(v=#h*DL$eWiP@kYaB;AalIo$i;Lp53pT2hm&a_X!ICsyjP)Ec-HW zy%8O}tr#!ot;>@MAH()tSk%9`uz9c)WautFI(YDg3mM((`+&-r>p6~=DAk>P6shA(xfSxD@mp}Q>1Y}7s( zUUomU;AWJ@yanzd9>`rHG@TcHfJ6fq$z9&kePpZ>r>@eTWh^XwW{;|70AlQDjWM}t zsiLZ6KvxG93f!%Q-A(~NBn3Gn$w5Ukrkov<5m9Oq8XRT%;=)#o!|(&osx?%Nc8_CA zAb(ay?Je62SLu}!%kYb@F8%EMvxV%axPVmnbl(`?0)RD;0vc9 zlha&e*mO7o9Bifp=uT_TiEk6H=?M76aO8SgYofB6vj{VuOr6@?!OsCX)P-iNOaPXo zFg2*tW}!osk#YH|q-$0WLv3;k$@|nAD-$N_ZH5R74+e>a6yGep!3-uN{FoZm0&0)I z*!$q*02H%Frm>T*@i_3&Vqe#AC`KIVg_e6E6DA_WqrF>6Qmg5-H0iVgXzVskw4U8_ zePE;@B?@)^gME8GrJS=ldxE4$i4*1k1@6t3d;TnztQfKbo+Ih|2ggV?J0e-ll6Z83 z<}0QP4bgnMO?@$y&GWStTNsHICntu<=Hg9oAeLXQ`Qu$ZYFxOH6^Xd0aKwW2hBRDw zayhkk>X;M6xJg6}4>LQ`E}3-u2gad2w;?V9h{z%h(bretuaafo+pAkS$ZL}9vQ|=L zAG9a}!%^#?6m%vT^1=W|Pxhr8<{}2p&gB_JP=TN7=8MK!d;*jz`z^HWTjqe_GpC`( zq~C77ErbW1*VOx*i$a43U;LWH%w~jh57DWzu|pr_Ndnm7@QHp}9n*fSt56sS5*cIl zLZ{}>3$ zH3WE)BH#x^+2svG{f;+EDWg}&t(MqWSm`I=?CrH@Q6>{R=ja*-=aSLHAJsAn2_26Q zR=0}#SpkDepG{p@F;Vvn-VI^V7jSC}aea3|)*EGsL0h*Ilru#+jB zGTO{ZbrI3IIki!G2{+mJwfVw@_z;(Ke@z=iaf!sz}5T_aiM9 zH`Ah)IR4)*GdPFFdg(h5)^KJ@vx}l~WnA#Eg}f`7o~TyDWlY*6`o6Q4dp3hnr!FKFy&ajUM@jd)aY@h-#YUi-ElP`%Wr0hmVb$Hg#1^ z&(K|Y%Pa4gQd?gFscHcos3LsQs*u*f$X3kYhg?yE%%MzW+Hne=5zvet$DQ+?ci~z)~FJ1DT;n2KD=dpKnBf@ zdIm2Rljhsf%0MAp@~72YJdm>y8kMxOK^HR>jzze*j=M3k)+zGqicFHbzXnCT!Q=|u z&GJo=Mu;U>$^$|ybK>lrM(EvQT%k(1&@GeF-AoHO0~(Q&bAsNYr?fYao~w#uU9@`= zFKN8(0^_#yhI9ffcwT(&_OP4>QTe3MSY!F)wxVCo)4zJTo z4Q0fFVsj!3A1Ct$w+tuhADvLXqlMDcRihB>+*mDjr>pRUbnSXsXU#6dU9BqN-eMrodyVEFQ?#h`J@@|G8v z!m?eY{D!36O+OAp50TrG<1%c#UMm&NY2#jubrkUOE#vGZIuCS9IIvynXuCBOE9S9# z%!aw8cb$(?RWwUfFR*kbfiDb;wF}UqDXshJe6Zy>u|wb46Fzp0vCvJdyvbtE4S82}7XD=o=6uz?-RCn@9w3 zn@{neH`PUFxB))uW1jvoE{Z^eV;H$UDhB8BaJo5wZ`fuRx9yXl#V5{^OUOr`r^>hu zdmUDz%2=h?4;s(V66M7Xy4Qvoabm!j9oFYY21d^41yCAW&Yn1NLBtKA#ab{e}eY_czY7jFhqF$MJ&5;IflPEosm!!_Yo?H2Nu zGG2-`qwG~N_5bxr<9;D)m=K8UO>G(!Q~k&jnaQ~;LGADhIdN2h8SKSi^l9zM?;@MG z<&-#;(;(^?$O$k9gvMeG8u&v#mR(CM@XI!xhhpX?b;63Qh9kRXs3Yywdur3CQUBUl zby9?NcC{UKP<|wUIYdNA2dO-32-F4;`-zy=dwCfT!m-BHr`{AwFZ0~k6_}U5QWWwW z4DEB3B-+1*4BQBk01D%noWLB>Xg=twcOP+A4--VlS)N^91DE{^Wb-S+(qIGASygVo za1RF8wFSR8HcMiPK+%yZ>uw(h6s(1msY7`@`#PSSQX&yz1Fk~M!69qcuhqgNa6t@%UHhL zp5Z(YT$lPs-Ar=1+AKL{G_xs{T8w?s{I!dhj$C17?Mc0o0hj%*I^fUmq8Ar@*Pk@Z zLlq`*PpsvJa~qaXCmfpr?%1}3icO6mxA-?Mg_y3jlG_o*t-;F&-JQXggoKZbqZfJ} zJmMtyeS>el!P7_XA1u7_We1wBOP9uto08bC##nTRZx)RdsfsuM>ItE4MA738MefmT z^OO#I(llr@_1kA$M^VzUpfO$Jop5c0gbt8*jbzG+GIBN4V?XnEj17$?$_Zx6#+Qg# zJMyJF20Glh*YyO6JhBQw;?TZI&eqz>4K@r7y+;VZy3BhwQJ0v zi!6f4UZh=OMlrUqQL|J8p_m!<- z1)wtLQ)KrP(r-#+zAi@lG$rY~JxU#ImXOY|tCh!IW}7uLd*O6imxfu>xh$vg&;;q&8@=420HtJv1zq+`!HzYW4srQipT)i(!-eqw|h*O}n(t+h5RyN4QVb zfK=|obfZ=5I!E7p|H{?F6Po1oe|uXpFaQAV|AwnAYz-Vel3 z(^o-aXpzF#k5BSEH3ES_(?WTEe(te&YvXq7`}KSd?Vr?+Du5j;j4(V;?_psR>wp7) zh#)HrVK14rxbY-n4`w#V9`=X`GGEt*&Q9x~ebPSAkFH$u%ajB-t8m*#fp&8SN9Zi@ zdhLb;%#WMlH^P|eWN^fZjaV%07L_CmZ6s>s(8F?Kxio~yr4J8={pmH9ke29@@ooh{ znev}RO^(q7N-e~e%;Lu;kNr}!;ljl8NF8bPG;IwjGi$N(lKYEx@3Zgr^(I~gJ|TKu zmJ*kc;#fozM&6w9UBoED>$PR)P{o*vM&&O^I(5Vu?asZ*cbkG_b;COuGmL>@eEra8 zQwj`C=vwk^T*Q~@M+ax8xnX$?&#jz$7UFe}0;q@IK#)makTU%|F(#ooeS-|bP|Khy ziG!`RdSXq4ILmG{%|>yoo7C0Nd>n*8x663)$U@cTYh6EI2B+rG!>vW*uV{XT7t(DN3}CBF>ohf zq7~KC?ad_;*(%FkFgnb*5v7ZzG%0yh9poz0%#U&X{98}WMVLd%Aq630=A10mT?IYD z*R>L9??l;+^2gO}WDzuN&`iJ~*0iJbR6o$Yu|y|5m!#f@9ln@wKPJ=jGP_aa<#u-j zrKjP&lngwQ&0uG8hazR0<6N+O9sqLhz*PEn<9`gm*CA^9iGuGixW=2fF*xTS(^0%G zC`cjC%UCkC1L!)uFu#pY8G-nehG9;T8|4s3m=>P5inmU6tcs(tN~YX3tKvRsuWA;# z%j&X5%6N&`*FWG2()KFU%w>E)e*9D6A;@--|9FA$5TWHi&Q%#~s_ zQ$#vvJ)%4x0?a?h`{DGeEbO0}AF_{~4_;aUp0!EN){|bm6gC&3JQXf4=N74;(~Cc7 z?lMd6pS#;QTfYFn;tCMQGp{Ow?M7{vy7N-5iChtGOgF;?5A6Qil!-rItZw~pB;tSr z0Py^Wk*H{3Y~e2JVq<9H_+O!@@}Y#Sg7R(KI4(2rK#%gCZzw606(V%pvHIRHz>j)hR3h6Xv&7sY&N5W^-_Yc9FqOt$66~Zi{h2rz+wc z6@|(KlFYWr!d6lorRgrw>1}50qa0+|jzWGe0+>z%jfIT52vMQL!R2oIrnaG0q9&H6 zWSSQ3^|2FaDfSu_FO{42DAo1abX68#7>m?`zO%@OFsZ^F9VYS=I*N)RQCdGO>!@mz zjddIYS}s&53D;;A1C=I`RRU!}NQhBH8n9i_SOV?$&5V6vI*3^Iu#KF^t7;ck2M}jp zC3cZFg{1JY^E-e?Z9RpPZ_CIzzFbRd*&Jz!z6^bPY0l!JGC4#Mjy z*<^4vqBW#dg{-H_Sy~H@=x!5@H<_)&_Pz7ft2U!4Dd}pr>FePs#a?2PRIVJP)sohp zqBRehv53(NqVD-x1KY(D%CM6uD(7cohd`r=u|TOV-LY)W*`tw>R2S;QSvXdf-clMn zD-E%zv2M=RdpfZ%7`30XolG#eC+*suG?TQ0Q-^^bkDoZ zpZA&5SUl2r55uF?Bs23dY%qnga>_20+cCbLvIi&{vPrICC%jmBk}bbSfbs~qSy6s) zzFzkA;w)`Ie8pq7h3>5A?qJ3hK*W8aVci(Qy+9U5*q`Z7dLHxbQ}Nt0H4_O$-vPYg zDf&kdP59HRPwD4L?kNl?HIrU`ueLm~LHGdj{vmlUdq&t1F-G^XIjiV`xGDUp0;Uvz z0>^Wg8s!84my%nMi1NB6J9i5RAMU;dO27!r6SvnsdcwU619)!=6Fv{uxXiSW{3TJ` zDa}V(iWQ?V?0mrmBYzyOiXGI2p(*)M#`jy?Q?H5}0(C)iByW9p5ILjdiQtrJ2m{ghx^VAfT%f? zGUx?}*Qjr|kziRLXJu1j!a_hcUh?`Kh0*n+dwmWD;ck^@XRax*( z-Zg80ydYpBgo%0wWx+!)Yj!p+3SK~_j@Q2>(V1DU-O;~7kpG8*{NEt+zXgfyi3Acr z2(J2CcX&aeWkLUh%uvLgONh2HSikQz9dYp*8k)?QZ01UEJSgQakyzI%DaSj#TL4&`d$+ ze3P`Tj%_lVWjNSptGnNAp`Tku1`^9#YUJQORK6H9k_&ie)+p%0NVjvpf!{$E{1eQw`w;IA@~f0g-9 zK<~el`4^8#iRFPB;717AHJ`%rGpcCOKSc`!zk{!)egev3mlRy{7@q+30c>IUYke)#F1<#xowyb1Mb1P_!VE*@-)0yV}VOIrUV9Y^K4Tti9~{Kek-{@dpom zmnn_WUjQckJ78w`55h>?#QmS;wnTN?30n>IN5`U%nCf|@Wud)AAb4R-Rp+?M7Hiak zW>|KqycJuEB64$s>Uv|xy~$CnYR`EC&ID)>crk;w6h8hOz&98yTnh<^sr!BgW)S!j zvU@myBFNPFrsH($(P5UOkLv3@YIg_N9_E&KK5CpecW51?!zmGk#DgT@ zk^J191rk?DLfS}l)CyPpAdt98Vyd9}urPKt>1;p)csJEbBvA_Noa6L{YsVXw%H5 z%*jnO+=RO&QFEaDuZ|Ner%99rC^z0h8piHLoiJ7MxmGe{Mc$D4%0tvX%I~QZcSFCrXGod~> zvJes+WO_F>bv(V5hQz?ANuZAxS=JC0cM9!*x}w|xtQ|D=*FE$3$83{HZ1~hHH5|Td z^*Ro#0>PwK&-_2blfmT)$|C>oP@$se$GQyMqi$(`t*zvPy1mg zp;6g=%3h)*-PPZaW8d&e?T62c%agJ(0b;$CLE#R8O!M*dKQr5bH)3LOIg{wKw9?W! z6tQv+j$kLyNDy%%WLX85EsJ|&&S2Cn*z8I!ewF7QK(pN3AvH!^01Ig28Mbk72C~uS zEYCLF$>mgV4;Aj-W@0s(VCtQ^e|Yja9{0-phCvL}F3 zg8OtrK*wW?-z(>>WaH!A;fTif){|vxqwSn7RqI|C6FM%IXRG16{0C^su;y*~xylDb znwpb4A0TgLb^;$9(ao&^#?QK%O{iYNxUyCgo^^>bRijUCQ?)N~X+#l?Yl$L>mzis8 z@7uU%Df==Qea7wX$xi|p#cApN+>>u;$eR6->h7Q_-M@WMU7Zu0xE+AP=%Y{5ZSkQK zh|0#Bf1Em0a7Gf!ovYXK zUaG9v@|&Wo^AlBV`MdBoFK(MuZfhMBudx{xM1RO$oi@(8B4jJ%>KCxjW=dmHr5>5C zu;<%V(D0GYENGsQi5EPtNO{AfM~m+xxX!A#1k_BBO<#=Kh}dkpHr>0s!jLH1W1L@n zAKLDRNZ~$x;frjNdam3wUMiz!KZ;p=cxvc;nccR-ZLCeamcem*!=0BBY~3;Tg!rO4 zy;k+{1ySaV&FUWVW?0~^yWEj)4M1-PN8QGK;PDSQc}HIEnLYvhhT(?+KgD4VbP|e0 zWrwjiA!68N9nlP<5l79LQE&IrZEl1HT7vLN11U6j>;?NN`P8SxD9(+BVxL&M6hzFriKH1O4*@O^*jUCI$$l z;LoJsA3@$v3{0LUI=dEBcEgSMchP~=vzwG1{b4*Bu_S89Jy7m~(3;v>s0HyH68F?QZGn0Aw5L>I>>C>P5_7WG3KEF^=7mPW^EU zJgjKCqSlHj%AhubSF{(ox*81_qp!pb!sPq*wGGq~hZ(x0X!GmE@g+@(or zk1okg1>5j74o!oM`#qjr{@kxg!|u-+zmH4fUa~_u(@(N5|BOTCbO?-J1ZpU@L! zr!nJydU(`DK9=DJ7d47nXofKMaY@aY#4O`RDdGjl51y76C{2+nUL*L zY9qcgVh^ayiYc{|T0?H;{`?y`{$7W|%>Aq6_}}x_f1~I>HdBci{wbnMv;foqJ%Y%O zIZF$aD@Cn#J8L+bJc@QWv|Rj3Lu)Wdruv;FEw_Idl9CQr9^YWt%jq9qZoq1K6a*k( zLC3~6&QqNVj^IDrOd)M;o0BDB#a(UTESFO2@|{EG$wwri@k&Z#2_s!Sg#9 zwQPUKQL*u@e#NS#@uSrTTgaq87w0g+aK4MMg5rpt`=V!IxZq>~1!&@j|HghLWt(@! zf4znE?|6aqf4VnO10!cUM~{ErVTj_S>?S`7&uYZsUMVpMgdNf^@c=^YGbqpo2qa2H zWwd;8@+t?6{sb#EWTE{!ebkDScR+8H3*1qY0Q&7IpDB)0UenxMzc0W$&`VZn>h&>$ z@qxw|m`XHDG*#+qB*zckJrVF=X`>>cF}zUpM0snkfKS)Q?UW1Yc3!iI>w2=!Soz%8 zBxBajXE2aU@ux!hZDgoXfnUo7bYQ^a=v6j|9BBut5~DBLqdjp){TAmFR4@wdE z!P}y3%QsP4`yjd)L9$CB%F{8*uqT;<6u(_!Y@_H;zKIY^cM==xMax+ivNkL(a53ES zAfs*zAf7GUi##937OmyRyfHlYhp;P;~TCO8~E8qpmtEvnHM zyge6#JDOqLgfLN*{$$j$ALlo~2yER^-_IpfxaUE*pInuYD!lraHy zL1d;3cuQ%9UPVyWQ`ea~p4k5`XQ@;Cp#N)D2zIb(ZzuaZK5_&A!22Jb^FN<&jW(n= z_V99^(8I*TMguMvdn@GA)DC}gYAK``rBD-N{rxVWP@&@rWa?83($ zHBE9AKO~^F(66mI#e9A#3Ns4}Xqx2KIY<0mucoG|WlL4p%{crWBi9qY+a8a{lODDr z?&o!#4+sJ&?qS~pGhp}i6SE-dKsmCb!DC_X$b&@$-r)z0Y*?!+VtlDrjl>e>i{B53 z_?xk?awBQDzO6~u4^2vI6}-?i}EBW&6k4-QL5a zGmB^Q>i6E>ef^`fOJ`u-Ka{1gaXwN;yU$5)S6pkeZa!CDSRcK4 zI8(GEFH)aZimn-X++gUg99=+keEpLt?r#RXABbI0mpa#Ge5R|fYb{t^wf;CWwJ#0W z%+JVt9eLZ~yLJPU)8Zp?34gShTe0ORKdjt=PFu4JB5^R5j22Fu!5p56F9$h=17 zWQ}euuk_YVc=$Mydg>bBKaZ?`#q$pF4jja>JV)eZkMb_Bneoczhb!Tm@y>i50mXI> z_JCe-W6!^O^I@Vd96{eXBIu$GxIYHnTOdZ$=|#&)G50QwrUiW89l!dD19JJ- z0i^7Q9URlkOZ6h1AnTRf4+>av!@E3z#?-C6BKkfMn?vdWyY2X=iBfm$$mP-puN;xp zbYo`N{$5q>#)(KPx~>E-_g~CNEaJe90?Iq_1Z@K|%H_91E(HdV7qIZKW%=Emv}`40 zWP*dq)OAjE$xS_K-9RSci@ZoNuAyK9W8y>l>yT-SNw#$AcieVB~&{o_+X?i zpYb<6VEsWIV&rtZe_z}v18`zb_TT(=(IU-X<3o|d=mF~ThORs(aMAjfYM6&0=Kx~G zI;ffeES~pFP9vyEP$urIr@)H|{ZPzr>F`1flq|JUVw8yq#AiftI<2qBzVKDUESZw#**MNw8^bq-^})cdKo#Kw-os<(L;*+Hv2;hx(XmkOfN@w0zQ*C;0=Q<9gxu@Mw_bYdr9Ti1$81%D_d7E z!iNRP#W}5pK_}U;Q16FC`CU}S0R6Rem6OdZF+{+?$e3B(x(X4AjwYMZbEFsrpSTC32qJaZ#ecKNU>vIIYX+OfHu#0SXsK{bCB zWG4+T8CfQ1xmKW+469JuGOA>HhXjVr{MDBdL4|V6(XO{~GG3Oj5BtX84@NEL;CCV} za*Y$t+>Q(?34O1@Vb*{iNZ`e@mvVaU6ZlZK^gI&m0%P}a!}P|Ug94*`yYq(*G(m|BmKL6Xj)ey|>Tln7TnT6_umK;`Cb$ThbnCm%Jf7Aa4?_*buYa%J$BZKa zX3N=_VfhhV5*l~I7QHG;zf+%k8$Q^6kB~SxL{v`Psk0xTe5!B!iv&lwoo!gaWuF9b zoz>iTTrL+!;ty;f_%AT3HY%+-YzdoiG9poP1qA3knCoJ_%X8!aO#P$Weoew|9_l9^ zIz-vP2yg)c1aDUK<3zao0_bMS2rD7>0tW~Uo=f5AZQ#m-P&+HdEKtR$YqI(fp~5JY zA1UyD!V|oeKXkxR!E!l41tPy(-rC(UF)-kJi*?u-W?`M;vwA<}owc|TC1Bw+ko$Mg zD2t^X$t~>R?`?!nZ|Z-g)Jlv4CINxSxo}bM?2(3S9#;HmIGdT?7sfF<>-0eQe4UC* zo|;CKb;E8s;NLT4s&AP9sCH$P5y=x^K$mX`PPIxfj!K}&P-T9m0MazA9Lzlo-l=*HBgCP8RRw4oIC?6bBvcBwlPp)GdRR!-M=EHGe4fbdxFk` z9PJUAG>%Y|1Isded+;l!^_E{a*WU1m>yQnFjJzQG{Owe+8g)1w zrhB0y3QBTVkRnO!zioici-m>#AGsLX zFwGtym8Og)icj(_zeQyhCmUbm18mR~Fb4VCUmvu(Xr4*Srvl@ z4_I>2lrB1Jid3=W&Uqx3IdcZhEKrn4n}tZPR-~O6tXs##oq2Oj2LU<}A%mG?xZS>6 z36m=_F(*nd`|B<}g<2URSeSnr=iKgbxp>0%q#_-9k*grX21zLf$yf=ph;DR)8MyRD z4S*$u?XEy(K>VDM&t^eT6|7&@`dG9J=WblI{WhW z0i++JUwl@566W~D`01SP?x8C(YRNNXhug(Hg)J_r2loqBJ=#6koqukAa@A+b$>Zi= zRR8GY_{I6@ouWTV{pI~XAD~(+qN?mt-1;o2$O5Nn3u)H~?2}}`39@iS@*DExWq}-R z_WlfR=?hmw^o2M9`6&M}3Sbegm ztB=_F?KQbE@=EiU%r3ElW}^)h$x{;ufEetcf+1N9OK);(IK^kq-Pr|?*l#lB(QJdB z@g1ILpJktDIlBCGORu()a2Z#Dk+D)@oGBo1F-0Itxx1B%QfDT~OLAx`ubMcubD4h> z8~Z8=o{U)M-tc_GM#NlrM@Ab)xhOQg^XlupE8d_I9nhvy9<@$f`NQUVUqYr6#Nmeq ze&|nuTZKwvE$OjyS(-WfqHary6{AzeAVd_oeq)p>332u$>dHtoFhv9jwricf-1+1O z*_KwRmKxSS^qA+>u2PiY{TVaAw z>pWw$6Ia1htd%X6oh_~r!F<^`qmfjR1;OVoH6$3jf7LfQnm8+;e=8imTz&$6|9bw6 zm$d^AeH(oB1n1=$z|SW3y56@zh&5>}BiG`@q)w2VFju{zUU)6y{NeC}8UGHM!9R^t zXf#YTyg;$2g!yDtX&A}tAAcf#zL%0rm9|X|b2I%V=a78XoZagmF4rMFd$kll=3wHV zYWml6EZ&)NcI5Cgj{HqZvg6Cm$Te6pMlJ`&jm@>%IT~rQr*JBuUgW%W9vO3ZW%B_1 zY97l&L8JPGMm`QqCL3<`&Yw`<<+x<4W5`~slCBl?E*md>M|K=X^(5*J>jIQ>F?WXo>n+daQdbE=$`uNhXLLbCKNobu2BLY+YaC(t{Sxi_!+`-{xJRZc)Pp4v*^3Nizl}y zjTYDmac2Ln;oV@9yuK3Fm**)!lI2n(@(0>8w{;{iPAU^67uCs=i|Xi;3dg&ZwH7+NSmT!bZ(+_#DtzK9^Siz98gdotz)&?IA{$ zJusYg?GWc z_Z*4_xDYpgiMX3;jb?2aBS+uq@d9I54CQaT?(VWh8T$PG@ej@)f4}lYKP7UnJm369 z_;WGNuk>DU+1_O%a#C*6`JfrTKrm~TAN8`lIl12s4Qhk;X@As-en6N-vU%s;%Bn%z zo77P8r#fpsnIQV2gTOg|vK7)rpC?Apn_TCFoL!l<%Dl?Kz5lqvukzrabJsurO0cxv<$v#%#^Sr0IvqX&qB6af|F}Q#M-@Rp++|js~i(DW~7V0M`+A9Z{^|ew7B@Sq+aUK^$j7Y$ z5$tC8y`Dv=8eJUmJ9dzmt&N2p9BcC+QU(}qnrEwo2=j>n( ziu8*mAxktQ#YgdOhIB}nJrw{ZJ*y5-;V(w@94Q}uJjTfdvMn5ep;S?U;EC3# z&^^T86RCm%$D6q=%G#tDl-o0nkUNU^un}YO#GsGB36qU|kyBH)_6JvBLdv6rz z2;8(GEe&!R7M11{P4e6jCDTv|2Y^s6;Yr?2${~_wyBexo zE}<3;IbdMJ=}mj(9gqCnJVg?Q|JXp69ToC|N?bNp4P8ad*!{8suT)f|45A;FZzGnR z8!Mbq!MT^G8rhQA5H}(!!!8;Nok=B$YIAL7rO|0{4mk->-&sY##e?}%$O@WlL8m3I zWwoMXQOZWGF$hI>HQ>6%APSt8n~>p>Z&AeQQGO*3N#J@OGlo7Z+?5+UkZ{-Ud@U*h z7%;|wifzB`j<&=ytJWp%%xH!rg+U_oqs30H#@%b-15QGdw2_+&0At*ZCddEj$6tWq zF2qGnD)bKbWp^;F$sGtIWU%#VLsO%p#T5tD>Z)+yOKc>_zxNO>k&7;wc3~^DzlzLbhn>w?1l3F9y)@;4DvC-hWz2X9!)!N$9 zjKA)JLSpqjItaHNJJojX=8U~FY+CR=LA^Zl6oFoEh8*f5VPH0F%Qtfc?3B~idOHhF z<_4m#sQ%WU@QMp?@@GDe2~TAx3RJ!o)gXHJTXBmG+Um1EA@uQ9_j`rHkArJjhJ}8mWqdC%)89EI)Qi{P!h6>d- zaS&I+4gM;YBq5K`i)T$ft^Dj0>^2qaNi(oydRI&(N0A2{;n`13Iu zw3?=67squ^`;h4K_9X9Su5r}XMYUtr>>R=hfrH4h!i`=h9t=z*6F7(OR?*z)mo|Ap zv2EiFbcV?15z)Z-=n?V*#W+z)dzKgk#c*_MyO%|7yVVl-OA|c}zzdWnzsvtc+B*hG zzAoRwZQHhOPTRI^+qRAA?rGb$ZQHi(o}RwF|L5F@bN0PAV#oVNRMnUIQopG6WUeQ3 z1DGx+3q!iPW(SbchvF39+tXb9{HhVw$>V`y_i zF#$wgy(ORKppWHAL|nM7MvX{bWRowDbF7LG!pd`&62eUcaR@Vb`&+cW@u{Y{_?FYT z%qCMui5ff%lJ`I@#ACeV6AsuDTw8kK968Ig8b}4G-McN60b=2N064m0_wi0qa=^#V z*pn!Iz=%K0gHc&58Ir|QBihvGkDxCJ-=Naz>I2?j80LJNMUcZG!hGrPUO*(Fha-IP zDJ$`bMPv&nK<8NsnuVEEz%M~;$0a9K5{u{g&rpErYwa>oCJ391bj=E?lb0pW;p~5^ zM`#+hn2A@alGbrP@<(8Tn)Lfp!Pv%Cb#JWTm1_1@j7XdX!eB{>bbSCE`zrF|5h#rX zpbk4Y+nviOm}s0yeF?`F-X*W45C z9$Y^Iot#2=6yWpH%QOUE19#aGnY^q9UXC7@ct72M*>(NUaxpU2*qBKLIel~D|8u7w z#U0Od2HKcx(`rm=nI>Iu{0vBd*I58QA9_z$yj&pRBEVl#0P7=JdhWFEkyw!|xE%t6 ze?Hx&@+y_l4R%>~M&E`}2Z*?lrN9_7nFbw*Q<$Je9->N+u+h(y0ACUwnTjQ>I{7L! zVD?rk;KWuBzUESq-`hHfBDbQ~8^e)LTM!412+^qxDVU1~8=%tE)ADd(2?!tuE+3DR zH8x)UGcmmkj5QSjHrhYT%_J&1Wvw(_a%C2*Y_S3217|p-p9$m`=1)lu^n}Qd`=!%5 zg=hED%xI;~1AQwoi6x3M)mjE-BPiB6Q_5j9^fXM%w04*@RnNj;N{4=Put{mw$$gl# zf?$ggL`ccB0TOA4TxUN61Iytt8qjGfY*|JfskoHGMhy;a7)^&d_)|bb(~2{Tsa_56 zsC)rAFE$=05T2%kLjcg}P?*do=b*w9jGylQDZopI*3$@b;8)2EI+D!*#?@FQd_kEp zjavIS)DEgrj^jW@E`e1Z{=m@s1YUW0&qFoQw)s3rR!+^~=b+2K6@ZSP3CO3bVba;= zXpv4@tusS_PIeXQ%`<6S_cITA-vS5U3{!M4Nu^Ng-#kNg)+FOnuY@9>rBJWv$IN%6 zK8!zn*L))miTQem$CyBSm)QKhv5J9_^fMNyK+6{aT8!06fdO*Bh73dG5m6T%K^Ju} z<;iD}NtN3`QB~3|giyreOv6pWhe^~N*8Wh)>u4YR4xpM{MTH99S>5FA5$+{-f_kr$JP!&Sa@eFp?VwS{0@$NAj$dPc9{QZl;KsMpEq`b|>nV?UMyG1X*M8a0C zWwDQVDKER=Wcd(;VpJad`=`$rW)kLc0YYUJ2J-tnMLW#H&}AZ5_8%*us_TOy!Q>oE zmK5?w)1c#KQgW+PK2?D{Rvq!qbIHakuXC}D3_C;eMEPpSdp8#msj?vZqh3>(U4UZF zO>!yJdqt8N{Jb-cPhXizytSYgJ zF2^PnWD#In2dRqpP(78z>yn(@uFzPf1VzWFo6%cbU=m-TnCC^SpIjss+Nony^i8m( z#C8>SnZax5dB1Y3F^I-0=);=O;O-==?*P%z)vAh@l!@1>X;&QIC}T?^ezN7y-Vj7R zc8KD>^8|eOkmlg_nw0=OQDb`R(pYo^>yj}pPqb;P=&h5Q-VF0wv~ZTinF!}a?9{^w zqjqV-eSZZ0;fERgnbKm6sNR-p4Fu#hJZ4J1euN2R{u3?Vq5-;&!=z;O5cO{J^ERLEYm2IO7vp_2~kz z>4LE726pR`DXmenIjNaG{m<(eTrMppU~YgpRD;^(lVS{;)Zm1o^QS?&%&T`oOfHaR zk>wmd2I)qo{7oBw71A4Ou%)s9tf`R0KF|~LI!&IYvOFSa@($>^XgDiODH7@;BvdIA zdTB&Nfb z6>)3*zw-AXv*6Mw9@$nf*)Kt0Wf%@@8$dQ;f}?6-Ao$9_592Y2B|v`(u?-qR*R5jJ zZ|Fowapt+o@^4;U55|;6aGL?`U)z(~b|9Z;AS1YiaXXM#M06Me?Tc1T*7#iQ08Z@7 zg04SdPUHuOo~4=SUn*anm#quQViK27*^BCwVx_ts%eoEHmm%V31KiQIucR*y8&d)f zE_gB&bNNJP=J|V%v$0Fkj3Rlqz*I<{@-zxe#&pm)Vw1LsfN`i0_v{)nUZ)IRH-MQG zIb$WPGJA0dFPp_A&{GrWP1qk#C9H|v{N%SuydVNpR;d#8;2vlYM>Z8r6k$p%eB>?K z&V==JiUoQRD%#$((@K-pf*|(3rg)14?mcK8<{=<;N}Pul8&k`Q2R92QA&ZMEOV=wj_YJOpqgS5lDK_s`UHk3u9&BjR z37|GyLtQw3RnNpL;YV5c8^uSn-zMIEDPTjwuWJ<$i*%ydKQE$PlDmo?aX$WwJ=Wv53GcM`IIX3ZT`;h+!C2@fXL3RZBX4PVZf!#zj z>7CcX;fMHn)}f(jrh3V0X@gf@PtgqY`S=;Ms z`UhCn6?22N=|?Kf8q4@LblqnWlU6JNTk4=w9jq{1p}lY~2Wq8&ZRev&M2q~shr?#3 zkn2y_5i7)pNRdhJwKNBEZ1#0cri!B*vblR#lL@u68+QdxyOrUQ#K(o?-C{Cd**MAX?$pO6o7Wi56IPP#S*f^&FRo-{^?K;1z^`K5nimjDe*I~rwf^@Q~q0q1KFkqat*aRCHNeR6^i;^ zQhw1aaS2wvSlZOjM%7OH_`t8YY`-O;d*=JU;(ZST{ko99z{vlg1NvQnyy9!sj}5L! z`t1+)%tiPS?TV52eg*qV&O@61)+D`+@+o5H8cpMnN(83j3sa#MQrT8^T zw$~M%&ZUWID*HyiEJqV#9RnSiXcO5aO3PG4OAH=@+S{l63iB|b9~nns(7e{72W-9}_Hw-;_41Tn9~rfozV;PhxjA51mRsj2 zZEgdfg~YR6AG{AYdO_u%7#X_?=a#&-mpm+r-ck$l4($O|?mcW9=q&fon;f}sQ18x( z#-fP>nkX1`Z0oyEOFCi?IBM}fYH_Nc{9W0LIekfb0OTIMc}DUGY{J2ub*90KdV67> zd7|>F4Dy8w86vcNVx3vzII51AVfa?OoIOR+HnG+&c$86ZSkdG&BRbcqifUAgq~g?* z-^Rq>kFQ51h+;HjntbUJ$kGu^F`Nx+V)CtvD{yW>HVaZjF{#uRkj6%GiVI9TSRAai zXcRzb$PtOYIF18iO{{w}N>l|@-=sX&3`zT@vl?|5LTk<&tqzc*JO#!%$hSX^T2-jh zy}rXxjWutU3MJ4pT*9wbHNs@8rC5pzwEW=`Oi`xLsYZy2)hAri7fwbu>eS#*jTmeE z)0Zx;rIO! znth+!m0e-?VbQ3a{2{wJ#ff9dN-|7Y=`uNb4|p?L4-fjXAWGGdW5`~B3UZnY1cD$RO>XcNytj{S7}zb*;+ zdQz0HN#mYIQP2YeRo;d$JiOV_4!C)fqKCvDkb6}5O)Wy2r_qe*cpGw8NUh5*pKuJV zovV<>0`{rLD!UFLPah>tA5)9uViHU41}HpClYd)A|9;nX_iDDGx3~hNZN>Z=9<`en z4qr%LcTTKPNo><({Z%tn8*@N4_T;TNnKGB%m;>0}m(n0aA|W=qrb9%86pfILyva=r zQiYe6RWmMFkE(ia)C5A!)>|#g5Px8or5*;jEGgm`Rxh+>Kt+QH22pvEr7qB`SuvD^;zjP03Vevl zHu_03YHE7zT3xqk-*<-}|07&Sbj*s+C3g#8^N;XRWP_?}p{B3jWbTce?E5v?pjYxe z_c#tzqbZuUx7x3r^j2x zz`aEcHSNxvbykefz(XJE48frc`6xG?ZCYD@W5d(3e>(UOzvPpkq8(@cj~w=c+_Z?| z2H4?d^gkUiNLPl2ILRC=@_w{;p0?$F!i52Uz?yIDRuJfW%Kq@~>xE@Mc)wzk+v!Dy zj1GGDjqWUzAv<97sY$cwL6+UhkTQE883)*%yWNGtk-$yx zg+>0=9n=|BbmkjOzk2~9azV7xF!!sW+2_gilSV?6GVq?)yr1MuYT0V$yrjZE(tt0b?pIS}V2n6YJGT!?xNNE&Uo zKkR|q$8f|6+x`%-z_T7&z*4HtOP#L+Jo1l$FQ77_9D@ZzeDj2yeB=yczTz_0g)vcA z>@F7iZwXX(0es@wBcUUnkNcFfD?mpKF2s>Q>yE&^1oq}luow8|O_*0Q&qy};!kC2p z7w)E8?VjOLT|L*{72-d{`^hbshB8O`14!q*Zckc ze;FhFrCa?kX(#uS-3l)l7?=^5tSgwSD;S(8Sjv6=Adn~+af~^6PUT>|@Mq_ww@=A< zqViXM@*S(KN1>cW2Dy6Fwrp5Fa*7${iD5;y+DSHwLlVN zU~GSz$sq_VhyD4jZU+9I%c1^$wr_LVe>uPcu2NLZ#?e9^z9{x zgv!s)%%!l}5bNpDW7|fg(#|^@<7R0^ZL)&$$~U9&RQHr%!PROzpI6%!$^df3p)UpYV z&J;?))Hw|$;lFigZ-lf0IVbiEiupU-qpc^BAll48?RaU|s! ziGS9Z*FZr#8-f1fkgBj4nNbsO%-Jr1eoO()-`bA_7~B8_-|}_dCAyOe_9YNUx^+dj zzRCCv8enq=?uGz`%1ih-A0`7bz`Gf8n89in#a9pf)`HoG7Pu!=ieP=eXBLc@=dCl? zF;pPo4Z}DXA$I`kIQZZm!#)^vTIgvE67D;QP~S?kEKm?Nj5;cXq;UkI@tgQ9Si8e# z0q+qBK7rAG1K+?B+-J^olekJ0&4(n0)blp@R;eGDWC)3;=Wpl^=6BSN`c`8Te50H9 zAEH~(!dc19!r93DKOp}vC2yAUmL0YT!q?T?enZX5phIH&Y-5^t@0#p>vjm^HAR!zq z#%7~pzOn`4{Q5SD8lBtnd$kN{u>2R$d#}(CvY>+AI{=bPxhhng_-`3h!)H2@_(F&~ z`-X;xI_8IrUmu@w=-dEg4goBm7^NSC-%At-?n>TbZHC>3H>52x{8O6P&Z`{ zkr5=tGLySLz-qAG`ny7*$`f|n0S8_%mE-o4$S>5gwUb-&43A6K_gwbzUcuXgy$W>KxB2yy)cNRdU;e z`a*TO??7T*NF{n*sp#24jOnZJ$c=KQewPU{_rd_z%JkV^Zn?TK zZiiD>JgBJ#dKm`vxviVLF_n!@x^{m&i?4!uPHI02tsy+bmiz4LpCdylKyyxNeouLY z0A@1C*D-{}(P$6+7?|ZfRarr`+RXZCwFjnRZ__}i=}@`ZJ!eROYgdKDWvc{extv9C z<1SP8tL2uFS0Pw)C#!_$;g4nab(n60&7P8X@qH;~tE~YbY3Rfkx@YL5FBki{n@G?u z&L8+1k+eDfEblB@nVIs(vMjUGtdNyyu&3^*k*lSv(ld!|OURlr2HO=lK~^0Ol68@| zZOq1suVPtHUz+@YW_awxpQah#Cl8qQ|Z~% z0g3r;flVk43JEy}>`M1@%*OpyW)fergiv;3c3gd-*)@iFYmhB#loIjmxGje87XNT1 z1NFf&eylqWNfM|5x>@?7C}*vpID_QuUK*aTZGjcRJ9P6MC1)YMA{ujXfv#mVJC z*(2ahI}}$De&dZ{dVHE#UzCCpsCvN?W9ab)r0eU9>3^7P>l$7Ivx1CI?ocxZTa-8B zE)_w>m9-D?D6}y8?Lo%TL>VM=jc;+c2{nLP%vH8YN1ay-Z^9DN+2!3sc=HQt^cxm5 z?rHKHH_8~fmZZ}EIM;AWkQy*6SW_=w4=<1E&N*b}Es*GhYINmDiGO~~)hwJ$KsU{X4Mhf?@3GupEG~GjAP2)pf#nyLS7*|*>swjc*u0} z`ndWisR1~a4;Si74((_yF;pLF3hzwog9u&eE;@QC_7P}WDZ_&#j9}d zWoWm3`%o21-iC_%sBXD%C{b|gYQM#Jv>8F%4xPe=ozs`kZm$6yFirRnjluWmudRwy z@HmMIt)nwhb3C4LVXl`BAXN4g71k9mGkso;oMD#6tix#bW42caAeOi^=Tu& zszl(Ma?a3IvDT?oQ4=-1VXgW{%0lR{QaD!K0X4M&?}Dyj1fsefL+4=h(i@JUz~hx z1!?kcG2!Xl(bw6w*9(#-R}|Y_)7=sw0!r#hB5C^El%= zDpGcTS(a2^8C$#Emm;SYgK*hw?TaBL6(G#F|Y`X7RE? z5VBRqyVVLBB16^z2vbsx)*h1+-f_IF2R8$jl{UHPon)`PWHB@M{BfuO*9WX2V+{Sp zVVaaCG{?^spzs5Kq%&Z_vO|AY8i$@Fp?3{Lcd(5Frqg)W1UL$8ni+?3?cRnP;R1Kh z>Fh0o*Dc6q#tu5Cud=oJb^;C_2$5ls&O@fpo&W)M#-{p}w`U5WO*22Exm%;kQDgI% z-CM!=(zDK2D>7GI@xjNI`3sk^0EmVOCZ|P5i;l4~rAyP3h}TJtVys@)vC^_5AFcVK zf9KF8jHIl5Wp^6&dgJ^D!ti0NOj;^F^N&1<(VjRMFu?V3%JDRr0zn*h!5#E!oLP(2 zYm+c`3c%(egeSoKP@0T1;dH_U1swsj z=1z%O+9kjbYm9NZTu(B%J<8Ans+0VIE!Dbxj{Ko4)E?C4h>j&K*txSHz5Un*cuthLSZX8 zKIqF2A=(Cqg_Iav%UPIIOq)c)q-eIW-#eBSYEV4rp(pG%sod!yP{(H`Y+(CHh=t1F z^B43*?}5t{F#~D&8^n#@Dku`M2e-ca5amN~VLyROxX^p%G6NrmYl1(pWx}_OuE+%* z5y#LR;U+(#P^FUw&pY~wzNpfK|JW@#VqcMM8jI7NMh_p_Am z>EM3<_{5Cvr;FK^yVHEMrop9t?B>7FN-M07#5$#G7e_g zLoCTmEiE1WCAy7KKMH%!DpYZg5aH9LmS{lhp(e)u(Grw~c=)89TThvozleUI+)Vji z9b;(d5y|WLh#mI@`rq?sh5}L;Qs3zg1_S_r`yYk{Av;?m1Lyz9a{s2ZN(OR&d5LZ4 zddbV?ih!Uzp$s+?kRug94iB<15?YiOivxMD<3ZzaKHJ;H1?v@(rI*f$OSAYsi(#78 zG+FQ?AB1ge{mObdp1RzO%hBrwR3CN(1a9R5Xz{mdwKXzFU^9hE8-m4lVzXVRV1^m$ zk2`!OE_!7YGOZYn_d^)v=QAGt*<$(A1*`(k20AoBlt6@;(;T{Kc!SVGGG_E-k4r6} zu0vMp29!~#4o@QIf_2EG6S)jH4=X&W5T zSUjy7Md@rL(oxh%K$+F=#`+;2-$7iCQijPho;_FLwqm%{jKXUHBr7%1bsK0kG6VC1 zbA3E$I4F$zy3<{@6pZUXYWNtUF+lW(jw@dC+vweZ`=jXykB458$l5nT5c#|=nz zNdl0j#MvYm20k4RoKt@C%1Kr5Uso$ngRQj++58F0JV~}+HqX~Mv-aStqV@TK#rfcl z><4HVQS1)zc>MTN8rx#E;gOR=EZcyKb!>W8x7-)3Vmg(HeAGAW39{|wa7sUTc@O0Q z2~9UIdiL#7SW{-#vgU+B`swcjfIQud~$r@jgt;A`=WMbE`U6+uKm|ds}v(P8< z&z;sS!yEK}W3=Nn+YS92qY>Zfi}N32)ZXL&f>0T|1%3n{s}hH#bTSm6WH3#0z!6gQ z(tYJ%VIo3}NGQb$@y3#vwZ>{~ZcRI?BR&U!2&iCrKLBuExZaSRz_cbI5Jd37z6NGH zv+ayEou03|XOv#B&W z!g!El`X3H7#@zcBR1|xTf@3h zqd|GeM5^#bhs0n)MyeQm5$^mvbvozN1XQ7(TsSaDWxu`c`lnRV24RX9ayRc?nUVwC zQO*M_7i6|L4@WkKactMpM8-rhNugt7z_deSzA&Ql$~n8jM?SU>w(}rP6;;0iD6CpP z#NM7MR05}q2cHxUg*s%-()|{`poLdrIvy1xa~FaF%CqCL6;B$TqFwfA>Kd9$?CxSOS?TM5JK(!}>En9;{${S0s znGDGCq)OvR?H0-#U>@Frd(sGZn02{#a38Q*6W1zO7|a3Qox)#e(ENb@8*P`mzPonc zNQ?Ns=L`Nrw8@w_IT@Il2wRw$IQ^f2u}FFAFK4%}ED~d(_T*%=sG_B&DjSGd@q~8; zVcrWMcEyY2)Rqsul6@QFPjf{ z+x_2?24i-iabu518KNGaa5jK@{PF#;((Tx7F5kJm>CknuIZC zazvS%M8vCJX~!_AV#%!(N+^Ru&D#|VUTpSkBYNjvc$3_Zqe}pO_znk5@HvB*7lS|+D32p`t;XwA&_IdjZADP#kDz-g&~Q{{S4&4 zL_$h8F~`R=Q++($|EKvc~GKBuKG~WpZJKCU3!&RZE;?gmfjBt zU`00h!E(n&hiKcW!3(JtN2Ttnvxa6%X)cBf#!KLQXZ$Obc*N#Rd#CYp)J7w_rm|UC zwI``kcbLXucb4gnl!~mp)S~f%jP3Skgv=sj)K|%m;7!Elr(YL4qZ*BUqq;to-6{4wLjdwd(Wtzet zzo~2KmI6JQM=HPvT(AHl@q80c?R5MjEFR$#_pyW`L(z`gr zX}mLfx!>Gqwoi#Uu6Lt97}+Nfh~ zcv){r>DBJs8Gc%2c5rcQ4c+tm+r8(s$f^VXJ9)%@AL)NeaAZx)44h5=&-9@XmN^1n}K%&qVk*_zA7P{R4 z5SyRo9q>1lpa0;&I%6qSd9eCxrpKn&b=%6r(a4Dq0Cnl==w5z|RBL80Dl{}28Z8ZD z^yZ6@9-lsg)DbLLHx|!N7-U$!*n%CnjPmoazneFLhoE?JG;d4Q@L7p8Bh*< zYtSim@I}AMs2cG@&VEpA=*GQ|Ct3NHA62QcrEWH8wK&ZcHRa>0#} zl;VPo8l56A9c(?gRq%M<%KnSMk-qnyQ`(`2FbimlL0`h-c0b}K*(c%U%PtTcqe{&`k!2_oLY z(%=j#M9v(sFwD5-5Q#H-{+qD_`Kvy!%Qx;!zw1c+|1gaxnmAc_{wMDKqkL5K@A45H zwKMgR4MQ@z-miApy!_ky2Bw8_AW;!f4YQuMQcnpZ=wOkO8xI*He9mK2 zT{A`-PiZ@DO!lx$HT{-kYe?T=Yxw2O^f|ey?2wa3PffM#Rd?-JQm^DH)o(JJ6id8m zlA%VG-=ABVvI7y?hVl}P+kFEy&HP^B zgtetE-NobtBd6OEx==TBRbKeXf@bGHZL)^Gom7vLP@MwRuX6&LkzL9wY8qxho3eiJ zv02;JV0HLo#nIL5peip^>4>O>z12#hmMee%HZi`9*}Tww+L6XC+u#<5Y3vou#mkO1 zU7W(~ifgl?y-|sP47sl@U&l_C{V`p(X>tA{n_N?~TH7Vca47LNv7ei)BnvL^J&Bkz z*Y*NT9DQu55e73?^$a zeS|k4f$%8|F^D$yPGrk`F^HeuEgIkCnrahYgP)Np>btATe3L76EBaBjpB`9j>m9== zK~8}d2VYMax#0fHRquxu%95B&VFZRJRv}6xA+(Y8@UKBt1Q>zDA>0GY+yzZP*PwvH zoiW%^hMi902H^fiT)9em6%cxtxR<3Y&)e*`+1U}Ge`DBkK|aDeS2(SnP!fpz!cCTwcO80IEU~nX?6?eFCsC9uI&dfTkLc z>m(XdN{#|AaZBs(UrsJhTEqN-@bmwf?_K*i6lVSls)*8iW+&o3SM||#1}yMBo(SHl zw;wNl|z{BMX*5OpIG>{fj zX7ydEcg7CvW&H)q#MIR&+=NqqH$T^(9EO9y#L}dN*b`x9mUEgwV=v3(&3a>t0vtfA;pm#9F=1_R>&+9W&VN5>Hx{VyXAC zhC+)a{>=Lhy>TNtd^eQDwZ-X zprzQ)FP_H9FPhHxn~pAEM&PCwJsL%fJ0)U%j%I+q%PgYxjLasncTkUTJC6*zVyrFl zThO)l-ES-+4xulEi?mw)fj34|wU70EhoOL^7>$%%sE9`$Dpn}6gRq;uW|&eP6C&^# z64M__2$PRQhR^eriw|T!ssmXoG4>O|>OnlZ!5}0-#~+~B20D}uHgF^ZqGa*ICf{eM z^e;SIqr5`(3%*D7l!PBV-RRxt_|G+XL zby18#$L>>Eq)K^HyiUMOrM`yjZC zL&h9zY}@yf{_eS(nXudy?9JAN%p3(A^{L}CkOZ_p)R=;J`zlmXKE65JSA!$uIZlBy z^lXehJ`48`_sZ&y+f~P;%egP^q*Pj-{l^~e_f_8IM$Y1 zZ6IhR2vN*|4}%s_NPdJ6xGx37^aDq1*2Ppi@9N?hVHYM)UEj z5F+g}*}1tMUuCp>e2$zj`g6D19GG+^$yCcQj5j|{Gb;@p=p&FvT zYs8H~C1%@tmkV9;vl=fvfq^l^A{LwM+&s-Ze`t=)U=M9z>kB(I4})1N`&Lgq?h5#9 z7J~Y#cS!!1vdGP%8sM)M;bT^^ZeY$V^s--`Sv1G$#1(%OKWQAhG&co9DD8j3C3efT zV1E_f2g_Cx%IPIap7|X^j0r`8UC{`NrrG&|c*#M-no*!79+Ib_Of>>9Qy?*AicnhN zA^wtWRri72_5?0)fw=;9)Vk94@`ma9q-&!m%OnNqMi^2{W|R%juy7K^shKw5ZL>y% z=8#j2ENqZ&!=Xw(nk{DIz-7|z9g-fHvIdax^OF2*K|XJ~M1ox+(e1}Eh*0&&&mx^R zG1L?}BL8pDVS=x|YJG!_^P36r{X-_CWNu;lpBHHoWe@v*_tA=!Z0zR0`)G71P(>T@ zF=zJOaHweovg|PdGz%e|(k>B0q*3^jpwJhJk(43EJI8#EG!CK#Yi54QcbkGRUJ;B1 zGSlB13p}z<4!8AsdOksJA>{Jo;}zmXWJMK+JAqJNLNvnlrSlF0OGm{RC_Bjx0E6;V zm#J@JV(vXfhJ`{~>x`DVA}6w3yN=joQUz$aW6!GBI=9$1U=&Sm3dZDT+e(%^R#;g# z$}N|8W~{AdLU1i*bFx#=ra(hiGw!2e0O^7^t{Xfa`i+=ydf-P*PgNz|Cu=Ex+h zs^AM91zT_)TuL-px1eg)AH|*t*)Cu*FnvHTUQ(`6d8z-5)7yCSbDI|X*sh@ z9Y7GN2PGLbaa&BQwE}(bosD$;%hHg!7Cyi4t_`Bp3G=2=zFY{Avc zf;s$u7vA0_ui~4K2s6e^=(h^a+1&3dcVoGZ0*mFfxhepQeZ zZmI>x5=OlDM!aj(TlPS$*l*1&G>=6>MnTL&kG8$75eLKnnWH;M$(1D$nZh9wPr5?( zkPsY9`hv6ICIpW|;1phjM;U`R%)>_k^>R*ZDZ(=xCS2{)bAXZo;Z11t$zKp_4eIFb z3FCMJ@rgm+f-Fxxy_i3r#Q$&Her{|SsD1~^;BUIa_5TsK|7JTXI&#QT7{0|Q%{u6V z?|>AReJUG)$|!dQR8Z{Y3>HU0Z;ZbGu>r>6X<4U zTKOe0b~9I*%OeHKyiZRuKXlJ<-~3?yIGY&x0>BYj6Gji+KOMA(36qW{u-dJ~ic9AR zEEta-a)3D?TX)zTgv?YvP7cTnSOA;;UI>Z4nVyNdX}1VecM1VkvHKC5cJE%W$AXdH zAmtL)XI&biBycJPrb?h~`9tlHN$UVUIO%CqvbmllOVm|y4L@+bLcVIkXz<{E zBfd|3>sM!1H?u@hMW`T0_YZmyJ;QK{N&8RCIJJnREmL!7!E!w_jr;Siiq7f=Muy(m z9f*r3{!u}vCn)Sx+ubBRDw%ClP6&~uu?|b<4Yd36+kV6ZTNT0o;Cu-nZKk)lvd_UOxEa{j7OZtyDyHttCdH!>Krec7-RoV%4^==LUJ=dkR&8 z@=8htIuN1kz$$eOUPu#iF>^A{M{jtlLyexODFafN$Wxg3nC@7BaMf9sZZ2tM@#T5W zGR|O=ir-$}&Tm=Y*4Pv!L)YwDx8fEoS>ap~!#~-^`{KL=1!fyh=a(=nLsbALJ;s)C zd|^M3r58W-AwTOCZq<6a2yvxBj39c}cMi0rEgUc3Uo=9SMil89stYBg@l|C*Ak*ejAj z@RMhCBmW~~m`b+$3pF~APalqUz&%d=OmC3cZtf26cr=HFuhb*&;IZjFD9l{M7&BwL zk!u;dE9+*BM~FS!2!`GsjNZld7uol6OpkFlez7U!5#Gp+7>Cv1CIh}ao$%q)a@<## z4C`oBJmK=69}G?7%t)VBMO3(09#w6X$JSBQfsM_W)^i^b^9j~u&Ajin&O{E?alAy2 z7qN3I1>s1ZJ%20PzCI00{QNe|l>BaFQU0^j`me(olc*)P@$HO0W6uoP2m+OCHIa2# zga$-~Cy$>96#)(<8Bf)>Fq|GNG92rgs{B~;l*i|fAA&(lXb&|1-k0;k>wCqU(>4B| zPw?6(N&h1NJs@w=Xnb4lPJ(?reu#nhCQtc}8l*I98?xlA*BqQtDv$FDoLOYSeU3+g z^45hdWc$Rp%m&4tC#&6-pI4eLs0KQ1wMFfr1M2JpresiFMfZHaIHFbN;p8$_a5(#m z!yJsl>`x24?1F-U@jtYv$u2+CKbZJepYEQ5gKxL&H0>gP)U2U1_h-k|u!m(Iya!6Y z?zM%xCH@d3fFbY#3x&vG1cx}Oi&v?AebnubuZ<-FV>Ylr8Q8}X01U8KR!2Y^VkN^t z_eJnUk%f@zm)J|bO|sYIAkG~6P5j@HxMHa?MdzDAsDCpEp?~(@I*|yOn;2O+x!C+i z8Sg*KDN6rR&ni*d}y6CX8R6U%4 zu(Ns>QmD1HOQ*V9;Wn92VVyk#zst7c*m1I$V|_8Tel9UVcmvZx@8!f%|`(!tqLtDp$z91Z^h>N@+|a5b9!6S)qK~z zXyMTHdskxbMbJ2$T?UaGV7&9mH;GWgOiaC98(l8j*l97>%MWcjvG2K^-=rwA@>+zT$)xgVL;AIxQB}T7rW2f)9cGiwu--SIMH}9ua#>@}*dc>dW@nZY+Zc zEAjl92A7>opfi}df9TvhY0$63%*7quZoY4h7(0x=(h^Y@qCkrxZZC4LzH>5NQ~mKP?1>DGTxAk z&v(*j5L`>`X&;eOl=@P9PBlIutE)<=76$A?i;2HjMEoge^5*6wWPjL~xthJ2Jb7aN zG4D5v;2~BdCEV9|h4Wyq7AFtKA;tnJ#{nt$W)Tu%&ed*5#L-wI`eA-UF_1_!As87V zk@7{n)eiKW_$1PY!Q^YC7Nmp2foc(QI*UyRHFU#LNBKli-^ACli|5x<>@5;%C z6Y^hcg7CITtfj;Q&`8-*C_EZv5b=NBTM{klryD9o+ARLccx2OAwch8Ie>M6&<}i$z z1vnx&hv@f0uL$1fbVF9e+z12AJl1A*ll_o&)A?L8(!&E{kEJ)n5WRr49kbho0p!jX z2yd9y7p6dBFB+*qIgQsVk(spb4TEm45XngysSur8NJx**JI_$FX9SzW0F%o0JtKV3 zlxkzkiH+MqYYou^RyB=RJ_4#nnAN|+U`E^1j}@C+z7plMU)Y@#=Ox>sX>Y4ZW* zY0{TPm(iWGLogy)nFyRZl(by8gYeR1o8gR1;f$rNt=~q7_k~XAx_FNv)8lM3`A&c8 zXbKy;vx0$D+cdo02O5l4iN4z8Lc~&Gp~1$W&8d0HjuGTA%T!%WdOMj_lepCPPT4y2 zAa>=-)w<;p`)cs0dae#5@D~l|kR|SnZKQ_~ne!v&vQqsj*YGXnKr2<}Se0s?b$b5L z6lcd#Q^Z1%T}J*zf$XzHq4ZL}@`lrXs(3~@ML79R2*b4PI2iTko^`Z3G_Qv)| zdKT|7hKG6`!*ISS?>Yw^7M)OJdjDbj>z}5HSoJTJ6~}X}cxSXhhN@0B1C~?cA3}0l z-rX#)Ld~!1%+?B5>MG^rOGYgXc5EHsn+>9kF}iM96HCbl8mbw{7LaZs8QJoi=8LI)rcMTy1r&Vn-qUFHeqF$=#i6pf$AEch0j!lwnVdDZW^g_G_^Uod{- z1}q8R@(TJLBk$S3Xiprq z7Gu~4(m48JwEIEJrx%VSlR<(dlTm`*v7Ln>x(oUf!a~B5vqr~TBwsQIpDTSOAds3; zzEC%MGko0w8WN6%fphfM!e%|5^1y5l$p2g%rRR7B?oV>-_ao@Wnp{y8N@}vf$zO4E zo#%{X=oQ2;HYofh`beB+TBk#q?5apHC!<>=-w#4Y8NyP;E8^x0g;*<=wv0fY0aWbO zNPe2k8?Y;+$me&4q7{9Kfg^A&f31DM-{-ikC<1tqr_@vMq%$kPZoS zkRU5GRje*PJa>{PMvM*ts3UprHX3j=8EMyMv07`3# z&i4~t4nCVw3Iee|GFV(A;2C2uifPT%e+vW@I2%}u>aPWSR2fyg`0%96R~@cg_ea(J zWf-QNF-{QmJIg%q~Z-zogS%x z@hw|US_NxH%n8u4qaLVh33FLLB>lWWidFLh@Q-N$^CpVyf9`u}zi16Nte~t~HVLLC zofF|MmFUB-*Upb$7ycGB9;UcL;gkna+e9j*lgl46<`jGIJYC$KfsuntP9o4sjg%r6<7!TX zNM$)vLB^`h?>7xJT5N>-*M6?ih3}eYoZBUC?4ytO^iTpHn#8uxFpy8@JqnV%dzN6l zA73qBhT zb9Z0y;ASsn7P|Pw9Y3Wg&pNLKGK6p*`&?0RDGjt{qw&g)%Tpnr?6a)EyN4=Z3^#6% z(B%HW)fPZd=Gqa&tqI#}OEa_Ww#ak0f|E1_%SQ|^*$HN!z(KOj#BriLeU0YX)z`7o z2VIN2_~pq~TVe+4weLGORLfT_{sH3eUi#=}u6SY7H#Y9B4@*;);L-(zG zF~qX)Zql| zhM2TA_;U{oHouB5P}X>hCYjcJrD#hSChhD|9kTYwxO$=zpQ7fWZY8bQqnYr6a)6=} zIA&cM!Ro^tS;zLu-a=Qts*J*UI(bW1lUH2k>!{=~@D33$ATaA-9P-vipWhr667cy; zHK&5FSs5&5iL0gRCxzbaJlSHYT3aU@7uNo8f7hwJEq3z4lHHR#(gYSt`pRAxNj0HM zX&Q?>S?l}?TD(9Z*^lkvbU{oo!KCP+yfW?cqEZ7%I)8(xwt`WIr{V>)$Fj3eA5_O# zB>@^<6UfqMsTGA4QRcD&C3vMJ>H{z$)o=|%)YF4Wk7g(p*~yP)Y0+mW(2WOcx$<|JYQd+m(toSha(IVp8+S z@N6j!s{Oni9%EAT4(-09oQqgf#O2*no2z(Q@B+HBb%x0y{=H(q!5qj#3nY()z;y5* z7NMMo#cd3X{@bk>%#*{4R6HNWG#+5TiXG~Ej7Yits_FQpn{dU)>j!R+vn<`% zH`Uvx-~&iw57~!+kg4p4t^%Cy7y2tf$Y#flPaiz!H&BF)HnJ?MPAOtgw{v9Z)$5d{`!cM|H* zl83>xz=O^B4)ZuewGZJ6teh0B7yHqtOfm;bX!J)uG}5ZufDehybk$07uz1Kr7;k20 z-z8t4{b8HA2nnY2i)jrl&17q`Do-PBlYA_Qmm>Rb{s~JdC5u#i&U(By|7o|Bd3nhf z1qF&;9Y*cX5HcLsyv&V#N8&86#DbipW-9B2bN`5;RDp`dAow9vPtVm+YDl=l5d}3b z=MR+`q{;q1R#X~mk&a-R6J~nD{2-~Iu3xhV=W})AR7}(j#keh6tx*cFYV@KjjiMSs z)p|<~(}^m(Xevz#`7ZA0H8{&uZbc|a@NYuIf~ujKTh>fS9tQgl zlf(v@kRx6?$s3Mczdh+gJ(pJInuc;_BPWT(uit2x-LEjLZB06thP3I=Ui$X!ezcJ5 z7T8SIl^m;F^CR$zx_wHe()ZwdQbB!-+x=+H&pwQPV-wF0yqA%AF>Ss+(YT!P>bYX( z1dm8euGT-t5M%w3ro(_uDvTsM z#884vvaS262c0_GxTNN{l$l#3QNLZH`m5sZo~#SKz85=( zS|1$Z;WFlAS$Gi75Ne)bSx^7>J7k?Z%3`JwH;wAEFYQ>HgS?Oq zPD~;^QndK{^ttPr=<+MJu~Q{~>DUNIHqV^1XEu3f3d`p6@y6=Y{gUZ!ut)c*eg9hv zLuLKjVL7k>@c}F@{X3)AzxBVhhM_ve1`SE_@?Bj3_+k~i+RKj%(#c8jia|u3b z_b=#ysrxrFg_yK90C>_(U0jn1n$7LRL#ELB6GUoMQ_hOWGv^S@)PmY5lXgGZdeS;f z*bAv_JQgYQ2QHLtR1zZuw3?~Q&}DYn6ReBXf-2MoV-ngelJ0M-sc?OIQ^`8BoSlfr zI4?imO?J}ngPVT8fFLPz7Zn~(QIWV}5%Lbfou^Y!CShwCg{|d`&*(ae98RJrAS4`N z>SH=~dTy#-I-2`TkZSigkI*HOTnUdpD2vcy`4)A_l*PQh&(Fj_hwQfN9g0%^_9;K& zupO)4RMse_o@VB_G-n?6!lva1?#%9fC1sH|$oQGJi)6}igh~3@AOz6qrIsWUhfH+4c-c5Lu^Gga#-@M|1Qlvim1#o2X|7TQ?vHeQLDL zK&T}Ds_bW8{GI+ykU&$I{ZKu`bowUE)IH*!ijv@>BhKJyS9XOqgtvg*=Xn13lnb0a z5D~?hXg@DFpY1d@&DJJq%hefiPNL*EYzEZ%xZD3QF`h_R@Awun%!hb#@C38TnGn_5qf`uzJgXkaeL@Fh_A zPpfcBc8>qj$5XL&vM{qXG5%{2{IA=J!T;Tu`$vYVQj+>>Jo{rQHVv#qM(7(%(cvtA zjy@imcwvM&6@f^hz4)k4qHScPky^7-IP7Nt*Ir){2Cc~65B5J?aqe%Bcnw-oNsY;f zd$n8*4NTjQlkV>~!yS)bYa!&y8CfsUo&Cq7(A;RF&lRvglz9bhwK>B6sM3utw=r?g_=?Re9WtK zX9Mz`1;L0Y-j?E9}7%A&{RA*UWvhzL=!3mLr1M2D^Ht7C#sp#=G+6uabF1Z|r{9 zXXE+6+_9d7&REPEpCl1X6O4~!EVk&|jm+97JS4&R2FP@D<^G_)HBQgcQG5%im#HsW z!)t_o^WLf?o3b%-9dn0P+9r90NqN8ysjFBa@y3I=$dwqx2zZUa@>WuYeYJ;9zAKiO zzaz;amHQdNA-xaS6~{6gWh%uc7W<6B8k&1lw++9XB0;{AFaFK0Rps+Tx1@Wpm5a#Y4w%NyyocvUz{1knE^z2 z%ZoVl(EEq5r5J2X2K$K~2mc2NIdHWk=XWf*$u-FyY&RXP=#-+X^=^L@kkJa@OtACC z>6^BGtY-sSneoo-A~lOmLh$-+^@Iv&NtTu~HhNerdo>EZDl?0{%y-r^nRS4+y|z~Y zr&i-4ng;d!oW`|ey|)ad*wy)vy8ZYKI6S&>TxPsmayAv$pmx0QTUPNto5SPlC(z`( zL&>kCD4p03fnDtx?e5A=)N-lb*)AkMG!})AVRURHuiTxcVb6=xlkiDIxkp^)&<-Gd zs6kYN4JF)YiQe`4a7R&ekkyk>#;34Srl>-(4tGWyvad@!jvOBL4a6qVpL(;6oXS8J z;swm}&9bNuCVKe|J2=6Azsp{^b(qgmN96W#MUmN|ytiEB*SekbT*eg1Z`4MwyY9NK1c+vLpSL6bv5wTc|I?K+Dm zZyN2NKB*4f3;ugEtCaa&tdW%S;bF9`UF8(OyuB)BU-+m{NRD&W2y_;MbhlE?QJYKN zG1URq$O4S#p?nL#;fm8Mt6m_&*2J02qw-h1d%fX7;V)Un#@5>7Btifbw=G%zF~p0GEewqwKTJ0nU<5P)>!jIL|jI9XU6yvD{7zg17Vhy)5^j=rc{ebRa{oaf6 z#Y7Za^m$bS+m!s4LzgR}Dlarn6=yBiX*penh00OYz+w=Vu~s?0SlFWlRrwnt4CwFC zDrGmjUXuAamR+79nIt9DwE*i#?D8FW;Fr%>CcJVM9%J5Jt>^8hPiNPJeUaTweM=&6 zZWQG?Vw{+wn}H4g7J{nap~`ix9-;x$xz^=bq}%`~(cYY`=;Wc-rIgI9TC4)urWgJR zpG~!d`!#$YC5nL>qP%)L#94;4*&|=pQ8rP-p*NF>s`U@REzrTu&QER|oONprQ`mTo zYxM&mNLVw<>uOD#*-ak@HL@E_QZ4#|-_mpDl6< z87I9TXR@wFZho1j%s1MtA@62)h)kHpfx%Drv;G03Pyn`r@W5u&`qW}>yk!?a z8b4Hj5;Bin*OGbH2<_t%kNVE;rW0^cZCl4&UNzrKE0GM^T>}{AP{???>}E<>XSS;- z#Co1Tzvw=I9znPMc%`+E{9#bf@HH!=`x2y+q-Jy(%PIuv&VK?`2uAAG12C>mAdHHz z?rA$>uJMzKL-WDk7OjTjE#A+4h3w4?MsG0V8?W5>P(}fylM*OCvwf4+9bFDf*enQd zO0wRsFvF41JvF@uIBo|D)i6QkOj3$sA57mwfY2m)s(`kQ;_9ha1f9v7k~Y!n7fRgW zP>V{@(;(g`gwdf9U9yU}_b}_Q-^0cjr=wkBKb?2fYGdR5{wDiy%FO=|10=Wlz&gwS zHa?(gU~OUim&n6^DHmn`m#o9qm}UG|N)!cwa%)OdMDRnGiTo4Yy=G}RQOD)QDs`s`(>7h3`vBPfiYCqqT#7OCL4 zDfEORXjnhx2mRE37V4lltD74M5)%`XZ0M%}$+C=`-N94y7|%W0wgcQEV}<2?wi)xH z3IWvyqt%9!HjCAYOHKY!Rz@%4in^IPw??NDn~QB(uuVT2L`XIGCZo-~mLU{r0$Pat zn%q_*P_1a&Q;B7Ru}0JQbet1abGMq}DZj4cz~P+*jqkv5)S|7u&JY$HZv7d*qw#xNU42xzp}^vh^Rd+! zUB+j4LgJ17h>J5wpn*SP_E{7bXw``t6X#1+RP@8FUj@KRY=tOl2(1ae`vn} z1-3gILF2Hqp$`Fs+_%$P)0;`xaD$5rnzc~Q4ckZs*!15vFXCFf^ScFyX`ZjGmhG>d zmWg5yU!#OVx}bx+^+S0Bt;Jb+5Js1=asyF%kXThkdOtqGfLNJ0Se&4jeqmZ{2)n=Uv!5Q!%5|Oq zJ6!r|B$XW3R$M_Hq&kTX*=G;)4K4hHigR|txN~`+M z5q>ZuOvrwo`eKPlxzhljz8($`e4r)XcdT0@&O^C9UphZ%&~CMGskUjT93kXqP@iW6 z@p23e_b>`RSt~LM&IuxZzVFATq*I8TZN=K6no%*szEdbcH%SMB-><^Lo>+egmJb~E zVD*)RJ%tcHi!QJ&Vz0p9v0zhUh`e0`O_1#kh zvYfIdm?;jStmLy6#zuF4Tc;W~NNOz70O|YV*N~VI zz};+pAr`|(?=p+S>8kB0;og+^H$=%B&c~xManr!MnGW2 zx8e&8mo0VMH9P?bo5f}sv$kHHWoMNMdUC5txI_V$iOG!|v9QCijfc@pkIU0c?`4Mj z5R(&#?2h&k$MH@B8~d75>5ok##gk3L6Rle7aV_K4?6G_5MA~`k@ek_RPLs^wY@2>( z$qjQvlyNqSUqDR#<|^FdY0(Zj=V>g=5A3*5LWU_UZ@VLEhYuv6J-gzB-=<<2-vpFN zvY}}_y1x%%`<*_jF$^K<+Fi1{I1M8I8Thp3>=<-w3&E_%hCp1T47-jhVLykPm)fteTx5tDQI@D3pFcyoKarI4z+>l|sdj(@r12 z+e2m8zhKN7qTeB!4S5!4PJoKtkuI53TYH>6o2oR4ML+Z)DU0e7A;?rdIs#3PjYG)m z9OhTlKZOHvtdN0dKRDMj-o7fF^DL@;PYjG1;Sz37F0V%ru~pDoZDACF_(2JGhdJ*a zz-+1BqeR`;0j`O}!}JH!>Xivzlm@j1>e5?CyfvO`WCKBigtmAJRi zcUrnxF%oEpP?VELJB0!=XaZ>x?EI0rYq@{z?MGgK5?h>$_cMzi`M7cdNc@zDA;5!ejGRJe&V~3xjS-mv z8;-f^+^5tQ8nr{0mH4#Q&kOz2d?RO(>QPJM-%m(!e0HC`W z%zz=PQ6HU1Jfg405RA~q#uD7mTDRH`H+gp-dGDgD5%&p12I`hGe5O*ZYAX+q(B*U0 zY=O0ETunemug^tTu1Ctzib>U5Z_C+QaV^Q^O6W$7$Ea#(A^8Z>?08pz?r%avD2%PM zXTrcN>eHdjfYCUgWvAm2EH`Yybw$ceucjmf2y8~{ukf)ikI_*Sn$*ZqlxCLsQpr1a1sTBwr= z7^!n$uR+~ZLA;6s^dhXt2aG|vLl>;R;6A-tB(#%0qE9dhJ&!KCS8*y@fS1k4k8fI6kG?q6*_;UcVlFEpQiaCOP1NBcy$&DtvFnX&1f&srxQp`27R{ zgaro-G~Nz1IK$cXv553#^4%T<^ay~}x#gnwlxoH^;&Sg|jT-z}ZrD6Uu7e?W`27OZ)a=L;Dp#zb*%O!vGzy(Qk-NRO`I4e8WEsR4`nGeN2Q8)PNSEqlN5Tzi;QXhOptX z^a6>`E7CfiZU9x-<)Q*YI*%_lAl2*GG;I3aRNhsuRwJ7$75@_!+}hc z;e;@R25w9^33aBrfPZhds7Zoo_kf0!LA}}|5%ghRNk85@5s~!RV>!Z zH7!017jqnRIcka8Fnx)Ddp@ipfl$fVy=MGd{&Lk?$zv7BE+q1i@bFpxsqp-GHF7@L zun_4J5`$##p=ao$i5z~16uCU#|z&M}C)S*F`gc$Wms$Uc~k^shRvL-zqn+Oz-8oU*zc$AbI;s zl+C~(l6Q+xl6+j0?6vPW`cfaFf!H&1j{!49qcGO37Ih;Y!572gmPwgIgo(Md2`OS? z5A_}7WDNfA0!47Hj}zuVV1L>>Sj$Qo!6X28SC%iGyag?3rndX>wnzH@n z^LdBX1LFv!uxbtnk0!*%)TLp97^VunVUnXF{_2YK1aI{Lt=CkHs#qX{$BcONBceZT z7h5OuF4%#*bq#p6$plE=M4vj=>@rqjZ_FdOud}$Um!B=RSi8H zm*WW4*1jhFwsnX#PdE&?F{~Jf^Wji$vCmwmA+V-N#;Xl(TwP(q5(SJixM_*0%x~_i zWXc-;6=(j=NLkPZ}vfHk?43;`g+O? z&yrrpIsAr5xlcwlhL+o4^pj#Fa}bBD<#P%(78 z28>Y<`sPXc(jP!-jv$2e>yg8_o?xpL!iPvE%R~16#ai|LlnaA&5+xWZu8_zOT)YAd z4~*_uBdDuqAV@sFt&6|?O?{#?c8;1C7&A$szI>tk&*J7k(ECr&s@TZkr~ox1f6uMz zm{Q!TmMRz5CT|AU3u=`IS9OY?pP^f0%m&bPb!exS^-q{S&<5Z~g@aE!U*-CKwTF3z%3x5B1e-c@=MEwx zgxb-@tin|6-9?-;VBYOylq(+zi<#BL#8l$gr@U3B*_9@DB8ZA~=M+T2!ks>GPZ5}I z7pds6fgsvv@B7x`(MCPSSr5oBOSo=z<_S4LZmIG(G^?sNE}hmrmf}{4Psvt{CkU~h zqU6+8NlP<;is|^HJil9c7&ba)sOvt@ZKqU7aISa@c%){jh6r@*rDVFp z@n$pJtp8?F)EJCDDWU8Bj!gG#gqw=_yDJ!1dIPeGSDD9yPzfdXo74p3!l7H0(Fx}l z&=65H{CnN+^sVaAHhh9Y(=F6c|rKWH63?@4q+NLLW zgSBl+(k9kgsBJuFXjGAX@hIcq3JEFa^v=|(V{_E4F$XC|juvYHN_pF;&GKb1*Af0W zoB-*4kC3m!$w#V88Q_;`)kZaG9tO9Hqs;@I6gmyo93oo3^>GIKA@CG1ncV$%pSlY$ zPXucGF%}al(pcz2$02n4#yNEvt|_arb|PfPX64kJm`(zMLm(E34_f9At9LP@%k;c+6=3m7+{mJR zOSpLXubgjb)u$ntLt>HMvHUCGdOJ#=n;u!=HwTb1X3KV_E0hRWl7F`a+SfnA6KK)MVgxdcEU>KukV;h9#hI!f|)i|Wcz-}L9E06yv zoQniM19idc58=#wDt>b3l|MQOlb9sPBb#z&NM;_09Z^H-$3IY$AJ}QH588z78z=xS z!a`UCxr_*?v@>1YERC6`bOQ~=B9*hv)3qqb3Qg1Wq;>xWXW1KT{`)oM;pE{lRIa(| z%&nybobAz_sw<@ZVs`zs>9u8TnSy8sHbpq-H-_;qVv6p*@3u2d_9){|*jGE>IwM^= zL$%!Tx1ak+B-Shv4v1eye!eu5Xp6waB83WQ|K!E|jxJei6gD7w;)rkHN6_b-^`i8? z8GXVde5nu-GS9oqL|mT0$PZ_n7d&Q8Qe#t?{IPep5c=`A3TH+%SqLmJkrDu#qm2Ji zD3W(Hk+*Yl7PWByCyi5>wn9-r{Mh=Sx7lE|*{f*|Z>CJJ6~q{wrA!m7Lk0@s7<%21 ztgfjoZ{9wTUkg|rxaI;jT7i-v5PR3zna5A3!W4KPP ztq5Cf3;s%S8&-JU>LCf=OU33JH=<27p~r{ZD@jP*N1IVmi^sFbh5V5i?3#Ak*#a z@?5DpP1{j~1p6`4rwtB5(9T`e2|$MWSElfP(p9L;SnXg@IFWM+%;HAKcrsm*(YJU* z^=EShJrhu5Nv~1YCs<2^MbyGG22CKW(Ffzixo6~%*9vylkcMmdl9Z^Z2)9X= zS>nHXK2 z+)10svdnxk6O<=UoJw8}61{R*@!P?@tWV`$+F!WVH+wp2>iA5ke{;--5n)%+eD!^|3fACYwg9Cez#!leKgQsr|L60a^`i|XUT#U zItY7A)TNKrwYA&;crz?zf;89viQ4yr>I2f5AnmJD;;Nx7!}`hJJErC&p)Q}mH`E*U z%NO$h>EBhh+;+~^E=iaaR8}9=1gG{@gO_I26p5MEp&bv zk&%Hg8ija3pL8zQe9H#~4W09t^yiNcV7qj*4??XvS^D0-qrKzZ+|90OPS5Z2hU~}s zO6oPbDaU0AeQ0G6=2378O21HyH%z2@LXQICni`It6lPz2D}_TTGG2a`Ah-%N(UYio z1v1`#_{Y6YVBJ_TRBHa zD*`FXR?048VPrcRsKj}i90^n1_z=0qo^8q2)7dCmoJXifW1MEj8^KrOk?*zX%- z{D8MYOU4#DC{LKCfacf$!+Oqemxpkra_bzQD2XHJDy z=Z}oVym;i^+QK)x>cX{ZdhM7a@4+n>);n+^<(21Z#`dB7wU+op~lR#*=xQETe z+F$n7)9*IoXN`O^9p-CN%v5w9CSxg0b|ZrRl;;bGN{a-kH^~J<(ZwQR=&Dl6iRDpd+u=WU7^A zTZ*4@1+9q`ApHZ}1zU8`MT?@dAo?W2DEZL3Zsq>k|1HtFdd&WDk%|N=x}s=LQ$|NW zEqq6rJV>y;X5v?K6O?Ufp{kXQT*8>rnLG2OlqJQLTob(KGSh_gl0zftY&&y{c^IpA zaJ#A-uDscadYDZ^ylzRJ`23mFrbY6YzF2gbNysU=*s@5z86D;3M<=}40dWouk8$fv z{-O1JVHn(cK_Q?cWRclrx>>VLf+}7SrQ~g2NjopLtJU~rO34efpX)>Ki%*_7yfm)= zyQm}p!vd8Lw1hyE^{m2Q4>uGc zQL$lEm?%70pafCVf>^0uj0pr$bV67b+Rto(utPgYikne=SVJn>f3PIwLQwlkgXn#S zh>JmnoO|M87#dUZ65~6dr)80d$F5v*?TNAw5r~+l5p7?BP#JmlG2z3F$e3f~N>?-ke)ACUs0LO%~OAid*B&yg3gTI z?WXM)?|!VFJhZ>4>v;?Qd{f;(=7nP&#%9#irw!a(9xHvxf z6as_C7V!Bu@mR*i*}%}+_6$BSnhxHu7**1u=^1W!oCvlrn)5G@-9oK;aHI+A5Cu7 z>7dug2i;5+wl}to#{9NDBoUTQlOn6GFH=9!hF;v;dvvQKjDjDsZ(5wwYz``{Leb2S z&Qk6zBa;4XBxXY7e3D&;{eYSIgOzv1bNkIJMDu$%@4qG<9S&I38eq~f14c}m|2bOz z%Mbk*N1bTJby?uzH_!fn1O3-IehPWoUA(-$BJTX}cmYBDFb7{zp>G=Dr5G4l*VyGh z%DD-e6#0Hgz7r2r8X*dn^^H$WO>mgeb|A$5`uL(g+zE$*!pfLdOK(9GOaUtbJCAM( zl`cbfT|gsP-l$Ag*wU{gfm!P5&uy;Lu80f0d@P=i%^IYKF*fguEG>4do2Y*gCW>0F zC1^_rRk-#b(m=scr;HZwL|UEf>^<$Wu`bS<{jOTLigqzUGQnuIN$w!>q{>;QOgGSE z4?^e6Tv{w!MCq0k!IEYLQv{aECQBKF_n0n>c}8qvkWwpuwzjURVK?w}lT7~#Pv6T6 z&?+Zz7pR48Q+v8Fb8yRMLA$+=A*nnLP<6I8YpesDB21OG6 zd_;FaeU>xnk(<_|1{abW%9+gRPg%(rf26;BGR#Yzmd1ID#K~=A{o*syaHx_W7v~ml z%F*)?y>K&@>Q(61t?-0Fg}PoUEU*p1fO>4>JwOkDH)BXBwXJ1INGWxa>bL2M%nMhD z8f=_q@WlbOhV^D@bLJcOovZbJfd1E$w-Y0zYzLNvw&DJ*hthvP`F|1)H7zw1HPjFI zAOIF*5P8@SY)VVtLLO)8YFP$927)TRBvl`5%dAC2Ny0e&`AAkM21a-&WrbtuhwHFaVsV+YmVxgV9 z-BtN`!p7IN8~8@K6*Pqp>;|PN>Dy;|RBOoBK`HgRpjEZ@vZxZJJXt$M_ZLyObeHu7 z50m7cJHn)(Rg$+3<`n^Ld&Hw^`=c$3r^yGO{MV!syfV zL^szFws50X8SBwkqDhVbvKQkq;gOp%2%GxTa~}bGCa)n@=P89AN6^ex0dPp9si8h0 z5c4@qrG#js*=Ht$6LXDxny||HTaDB?&ufO0Rj|6s(<2AkMxsxg-)I(6X3{?_4HY{( z3)h{d6lL-e+WS)SUnRr=GKt+eZ4A{wMc$x^qM}Lcv+B-$!e^09Eox^xm2b(mGp*_K zG?K2Fg?6V8f_s85?eRB|9vqCJEeA$5Xd1nTR;+Y9Vb# zx(7rBxUqDGu47;BR0lk=c>h4a;w&E&>lbUSFaVpTdP9Rk}rqHsdL(jpRt>B=KL zU_a$1>J9@Fezi*34cckeQr@@q)qy>?+|gc*h9;f6&fTtQ-o61U*|4b@2A^ZQ(O72| zJyVBLVjd{O;6*t6dTSg!Mm;P2Qf)yeAE;6~OZsP4i45^#pG{C|^h{-%t@Kc^z?D%p zrP2@$rOxMdwrIZnG}5TTt_KIk4o!f={C6dzfcN z%kW+(TTgX8%R*KDhn(VKeyV7)>CX2I2PjDK2-FD)Cn!WkR3EURBFsHw+=6C4!rj-? z^k1;9OEpB-Vn{6Hjqe}|RO<4%B<4pIuZL#@^+#Jm**fRuBSh-(^yFXGU`3ICNP)78 zUSat-;HJul4l-52zv+fJR0j!XZ=nDDc^0J2A^z>?Ns?MOH&jv9pfV^xF)AX!OhlP| zW;B97`jB6({0mR060*5G$Yg;4aXt+me3ejk`10`W$`bCcU+^>!h|L<9SYQmXxa#Di zKqz#}+#bwX!02V$GZW+L5L?;e$DncZ@GId>ZlV?Jq~?W2o)}2vNM)XwMXd7B%?f4t zs68q}-wV!elAgIq{tyz`L7YOyL7C$iV}ZmIt?xWBL_NMZRKDU-bk2M(jufhv9V<`* zuX1VR9y<48-V05zE)&tE)QwAK(=>JpXm!%lv<9tGTSlBR65}YrmtwaNk#**h0O&ZL zg@wA^Mxit{=ho6pQ2_VjFqdFE=|Px3q~l+MVRqCEpR}OoV+iNrJA+X3e^IN}yCP33 z(by?gCniDX`gSbMD#&u^#ow}%mK*)1wd;zGz;rH=j8bx3?^XAP%Ra2YPqL;~-%yW> zX_O)aPfSZ-A2#^|87{Ug{k;0X)-=zD7Eu77I>;XF!|bM*_TUIf6K%XGLo)iQ;}c#p zd-FF%h2WL0wPIkp-vvJZ=8~jnVqh$1YwhuG2o6gV47!~BK$AeHf5DC*7>~eOOcP1r z%z|LeQ6H!~Im2Kw)iKj2)AiA>tyr=jEJGlI`od7Ohh38HxmKhTQSqih@+?9BDgv|X{<16=q|{;ppO|F}8FkhxRY53(p`8Dp_@1AUUT^rycyD^05Sg2I|`Y zmxFXN%_YaiH)@=wHoVMiKeac%xQD8-N>{Fr=x_GHextBfFI8V@tQ8sYz6PONBP+DL zrzP+~d>}E%zW~48A4E_qr|Y}tP_ho?*>wxPbw<{^Rdy#h2Es*I zuiVrpMYXb5TZx?H$#=g|WTeecBB)415nUHqcln5|WqE;%!S@om96G*uVd_k`f*YT>KziU74?uLYB@@g+|TYHpxwTh7c3NtEuB#bX+ByoQ=j3e|#eUs7$D38a?pGlk8gmjkM8aOb(q~9dS5*6WYCCC&Fh~xF!QZ zcm`cH;RfHn$~EY<&_M_*wkJGJulQa&9b@sN8L=yXBNOG{h_aI;Np#1r>AX8L9|?KPBuNIkwZ!lgWfjcwX0Q#!dn zQMNxTes-J-acfkZuyTD#ZC^MG(|waxESu@N2SoYLrk zDQBNHEne#ZH$|b{Q?%XQTdm}{JZ>|ZC48*X@@UTJaFD7?r@~h!%X5Z#w2w%>`aHpZ z&!;=|gjD1CVGE6|;+i|1q1Z;J-xq^}67oB>Y&1cfw%sI;#z*cgnqm|9wlJ}@a*2`Nid zlh%}Qgpe%NtRJEO(~Qur;5*`_jERzN?vJH8PhtM;RH=3lD+nbGH+Nd5-6Js+6pQKw zz!53RDN(q$9fusH}CBOauwZih*}6UwZo zQ}`KsmgAUg06^m{y+ec_1>V_g^0-hmh}f+?TPA9$@xT_p#m~X$-tLIe4Q*C-3hLBk zpyQYt9hhn=+{24Q=9#jE=@cpV^rRUF<-~-Hj70nSlk2teo^*jx46`eatZ`!71Z_I2 z&~EXcAYdc~)`Y#)5M1eE_O( z((LZS9l&jYKKy|5Ji3_i(!b;w`BX5ykSuLqnDuzF^%>dAc4_?Bl!MWHu05A*$^^FT zv@$b^Zr*k%nf`9oJ4OQ08$aiJldUd{ZO;I74sSt#2QkTWb)2P5DzT_SpqI3}!o;pL zYIGR%0;PxT$OKv^Tu_}s-)3C4REZ2X${;sX!BpzF4s}lS9!C~RDMErbM&j{L_Eu8sq>7j zj?>lt9n=(U%5>vndStk~HyWKg^5( zFKTV5^^F2;L%F;rAe5}EEa@X7p+<+@w+HFn-t#YLJeN_+U6pTJVpkpz7yAclAv0%U zX;#E4U+XX+>BGeA)Ao(nOXD61Cd@Ep%t`0Ehy`M#!!gh61Vp?6-%djUq&4GbgW{0{bv7HHxX=k?}NQrQxtt2VCYxh4~d6EpYt1dBd$T(q^= zUQ%v&8}~Kozj0I#i=pS!iM3_O?GU&5C3MDCkX!oDO@#bRXoYszLxstPKswB~SwY9~ zOw{W4#&fca5($bOvXZ_h?}lJ{AdQ-dPLoVfio!^Ic_OR?x1Mi@TMxs)sGX{FS;xGJ zSQlMJ3#uXVoYlwsFg#~d#`eQ$R|r{?_|c;Q@l0*NC+3kQ1WJoI4truMw-TFr%@Ol| zO8W|^s=BRhK)O>xx>LHlrMp8K4&5CR(%s$NC=DV=35b*k64DY%r-JZr?|tt@&&Bup z-G2=joHGXddDfh3?X_dg`OL5bwyy3|ieyDPIwIu!oIpHzQ#8x0@XT}#?|iBAD)bF2 z{-w}&<zfOO2bb~XX;aX+&B#-wI!ds z`fcxfNT^j+Gpm_tX_IL2zLd9JQVsVw$Vm=BuynzoV}%|UW1+%e*G!TI|qu>XMB|7QDg-dH#WBTTYM=WJ+_Q6PA?$ie9{mN zi}yZi84-z9OT!SaKhkYZ?P-QJ5^r3r=#~w48&Ab^(?-;($e5TVVdz9-(aopX;kBXNmU*Qy@q6D^V=zU4@Nn&zwkWex!i13QBSyfh;hU%qJ z%ylBd1?P+~>A;e*;!CRdrGm6I|EpY$Ye=Cu;Z!Uak~JHxh>EpNaTTTfjq9xHMJBI8%uH^yZ;>odwpm+7p|MKtXyp*iE9q zMBQQ0#`=|A6xl8)vWki7Ne zS(M|~)+gYQHXn|7h;Uig59`FzDo4DrhuEdWsj2h4<8-z&*S9Hdt&tJ+eXzI;%JJm* zpm_yPzfHO8mwGO5qMTSp{3$Ne<2rY}=7Ko6dEI&E_13E4NUAZ;oR{4m3r2cHJJw$F zI`-{?Uml|)%k)K5$EM8%F;xt>o%BK@fO=trq2%IOP~wMR28UKnsI`MP^ZLQbx?oWf7A3bhx}aI~smz-%~M zqx(_Vq^|c}o%oDqqst+3*0|2mG2_S{ukE@^m1oz&+bUjq&gR{Xqq$g>>Dl)Oqc1j& zbb}pBmS*i=aglrqU_aogGklEnJX_N0M7F8hC!xpF3S&aaueIs0H|B*H^#aclQSAK6 z*|>(buXWgkOQ8XYaPizlohDkJmjB3Z{F3wTGxWAFl$Rg4n0fo<+QO<+y{kUz_Ek1% zk1j22Z$oMX3)_8F%m@=A54)g$wQ5t2{dmy(5XJdG!8LrQJb`uZQeb(Emx_k!E{vcgIHGb56EMm@7uapaEp=N_l(MpTX@VSS~Eu`fvdQkRrw6<(P1 zI78`h>d~2y|MVKDvg-QfueX-v5RmitfkzB4;En2UD!2dp*3w1B^`B*K|9YniRC4%H z6ldQ40YQ|JipXKn1!Re4P*9{Qj_uUV_FMfznBCNlHN*kKJ*;n+VHk9XZ;= z=#>QAUS?y!Sa)$C94s+gU&v;J2XcZIOsMDdd1mck_x&v@2maPMe6jLk9v$J#iD z#x)v=+O{0ji_i7dcd%t}7Awn{k;dNd8^>305vUtQ>@{AsgZ(W-hpbomb>7{ZLXZ- z?Q|xRp}G-MO)o|@e3nU(ypQ2{M4OLuIF#G8$rzyho?{~2eCE9JD555Y%9US=lRknN znaT;ag0g+w&WJujfS6Su(9sG#@jsPp`Jy$m`Po^VuM&l=Q>k&CxT6fi45& zTzuQ+XEvfYw02>dlbmTE3AIXk-?)ym&+AORDobh&Y7E5R`5IxNNWs4#La;x9%9brO zE5^r=Rk$}YNiVKc>iEWsCk+&pk|K>+cA|cHO@VBBGVK~fPZpHCC+O#nAqcN)>Uz4& zxSLy4hS^Wi=x*-O{cNHx+|0pW@1%ztD zDk%`ryJD|VK9*~uD;@VIFR8z_jrAM!X}KF+ABW`@G z%qe#a`teKcF{=lZI?lgvXMgjh^=f6}y)PRM*X1Lt}_YhzU2Fx4WD z8YC{aZANX^F7mXvhJ&sIYYJOoUOQ-bWSt5>{Y^*)w}En%m843&?XyY^2`5OpD3F|Z zcS_BZLfY1XFZrvr@J*-L{0^yR7PiNJZRd+VW8aos-U=RXOtp6y|W~$dBgXd0@9N^!QSJVdK>z zvHB`8?w;EUKe2ug0`b|gV|Va~V?5pd+6p?_rB}M^ia%QE!4o7jwownSV;=$ErC^ff zus6OWXknfg7-(n}p4$Bs#Lx${SVEtAjPJYS#T_3ZpyjS_BwesF2dws}b^0O-Z)}VS zcxI+4t!)xtL5&?8R7XCpxM+IfV$MUrrG+%>%cKYW#h`&qJin8MkkdQKG+4?vNeHhX zXE;~;QJn3>nz5l?mb(i_HoBunf8l&|E2s~q(TKykuY=s1+<1KAig?lX!TXl}nC3^G z^>&VBAj&zetd-Y8__?T%)6q2%gQq!A&;0~(x8_fpDH9sq`pGdU%tB2kVp9VZAz5ja z6Zqn`CK8$z6Qve%l|vQtn^}av;<9dOL&Fey%chZ=hh|u2I`9upUE^?BY{+A2CS6Pl zsi7IPijt&N)B6{h6h$s!^7ySJl-pCUQP!P?z{m!0vcJclH%8W(eRl!Nrw4oVojC%< zP$Y=4QpXFM{%w&Dm#N@N2%Yk%s`Hy=15ENqd4lA0^hZjYqqFoz4UwDBigcu%r204( zU$Q+t8Er#b@O92DRAsS;2d6?1qMn5~7MR*>oS;Bc6)+HTdI=|d(@*L$Z+G4_a`sH` zeNJ6MP7o`DlH;6Zdy|tq#kA2%(XbUx^~m3n(k+RzKt-^NPU}WsNkmJNo`eSZc?|=n z2eeu-Yu>LpLTSxt3-3KOXOYa7mEqxYejgjpYQK^1 z!@?A^S|5*!Ggjppn9Xk5^9JQ@u7!22Xb;FF90)>v`bg>QQ>5HhZYa@nGYRFhny9{$ zHNA$1YHk-2M`p}Vl;lQd=d=@tUpYzE;FOQ#7NDlz{#vjw_;@@dKqRx!#vwt8g7EFXBR54w^$L zE||^LHQnQ_*Tac*ut;QL@m1Kdom;xSB+AXBBxj z>ZE@Ar2e)ZMVjtNtqQrwezHw*Nsh{=?-AvZmrP#&eXCsH8DfiHN`(@-fCk%mD#Uwh!f3ZvPL+rB>a22DDTR@M za5&C16cbH$Hk8Y;NEz-Z2OD-sZux{nO}Uz+Aj6@xNwbx*Bn5LO2dnfO4M}!p#mPPa z*2g$B$0mXFiW7ZeD^n6t2NkcF9VeZ9pb#gkc^_;XOH~+d?H0eK>>#4lT#W9YTFLMV zo)qO3q;mG?aIOUTHMFN|axvM_)nTqgp?na9`MN!Xr}BBk4{2(^=_Pw5jdu)D={j#3 zw8TaspF-Z6d%Ly$1jSG?s<*;ByUsZtdDII&y(5084(8XR*$N~Cs~((>X&Ky9W>uF= z6W@6kGOMx^lF6b<4X4Q^2)V`5DA0FQs|dO9w!Cj)HzqJOdm$g8Y@3ak_wor{50u`d zcM5QGU~$|YmBBsQCd97Dx=408yX)kq-!13hBA3uILBu`aYVEHhEo)Rh6jRlR^`F8QAs%~ ztrHKT&Qx*Gd0s%2!-&vf>*SU<_|^1WkE4u@y;#8ybii;D=u>4SIl%GliR58B=LtfX zA)_FfA;joHltYLf$eyDT$pwbok2PK0i96SlxDnZHLI1 zd+h?qPeLQm&TDtEpGWpoLJ_w|b6r_+pScogcLdecKqZ$=FkxP&o{6`SJu@~l2o4IR zE3m1*&3V|NQl_FrdkI}G{mPV9fDm;%#4Nox1Cij=$jx=3H_q{+mq9`cl-#(e@YdHl zWW;kibWfU_$ugbsF9-W!tx-bQ*)m087UA>8xE@9*HBHzUd`|aAA6EB%km!NR4Mb7Q z#LW$psp>VZbl|C>cVwo>=r7`Nq~jhn41bG2DaK zvzSM%xDSS2t1=GoHd^*}u*b4|_p#b5y5XZ8RK6D$sqoIqw)BQ6f6rRz8x_GmRZ{b+ zK2mL5d;wSH=C`uFu;+u#l@r2lNc8t&t_L>YmUrfB;-wv+XDPBy%2Ri-#(L=tMKU}w z+&H)+(n@egCDzENZF63UmGqPHyuj=BDt@MDGp70d$9t?!}MoYrk2xVL<@!95Y#^B>088P1AuKOz zGzQXy!Tmy)E48Fr(36KrWUA=OPm38eXf-NTN+L z&m64useQM-wHHT>LOJUU$)cXg=!+-lpJ-uyhgni-DXg?!ZK*%(^EOA$N}+wL_3%|W zrnIVzQJTrBDpkZt@-F7f)Adge=?&)*$P{-4X9IJd+3xrBU*t0y`W%okbe%8vVlJMl z$9N3Qama23B(u0ZlDAntYhB#a*}+h+Z0&P_77|N~|BfeQ-#;|p_tt50w=UZUV)T39 zaMC(QpjXH{-^ipSn)-Z?324QFo2Nc1;%eWEix#`W3yw~Gb}y~U%pdQQK{r2~i+d0E zx{(d>Bl|Wg|0B3Dy7((~ntXjlIwu&Ii4^Eb4J(z}0o4rx*)SWr@Y>#t;ZyCR1=1dE z1$0KL+(qcXoJ6l&*GVZ$dta!u;rg9aWl{eU$ejV2Lpp|Pf_y?zINpHh&(X+rBkH~c z>YsS~gn~zyNO@3q-*nr<70*X;#a~7N!Xq{7#(Fn}ei@q$i83i2v<>@GDb8qAXD=pA z0%RoyN?}0=H1@ntzv1*5NXq)q)wCT2q&}=KKccGk-8PF*?_zxX)mZhKhb|x}S=b9| zxb6)tcgazeqnp#lh|brFB*luWM&FIP_#-WuuQtV3r&!AV3Q}L2RKIRI8aQn*Xn*CW z)~L8T5!m2@$s7%(&muC+T7yo0oTuU+tnN=?|13FA&gN~=2OJ!ALLaDWgltimhCJc9 zjY0WELms>5D)u%aFKSeFY87Or?rB z*+l_7P&B|2P*3{14Ie3x?Y}mBH1!;@X7I0L-`2)b*7a~DB*e#PK=rsYN{H`pIXiYk z!v)r>A(!f_K1+Rn_Da`AlOdYUZjQ2en-g^TPN*@b>mo&{kDBTp+R!=~^EL;FA5=DT z{`Q2=j?ZrKCOd@+k~+A_axCEH<-V|`*Jgll8;lWJ7gnz(Ay#@gS;!hx5^Hv!rO9lR znyRy|&|COy98cthnw)=#A&sFWESa8HKO7I4Z`&nY}13$pq1|DOWnTD?g`SP$@ zr6)O$J#YN;Lz+0Kt9RUD&A*+JgT3o{{^!Zun~_)QycU#E?vdUUfg z;6xScA(iIka4~ynzHb0(mqvAI4CNl!S$1%cn9MHgSb*NSY*PDrXPM4U>hU-jvORCk z8co}*@+T!3KF`57Mpv8OMz}=WFn&kiQ6&T@>idTj?w<>|ICbuD3k=0};)$_AP|SEP zFQ;#0eCZjHwE5Vw$d=JG8{_L%)iF$}{^`vKOqIae7_mp3$}VLBQ+Bo+k$WVfGvE~Bd520?MvNKqS9;GR+4 z8(V|P*n=UsJ{6!04$SI~0&lDyLe7~VwKuBQ&{0*!{4N|Fj$^tMdqdK3c}@4TwExYHJWBj@%r zR0u|Z9B7%(qa$*b$9}Ji@og#jt-n3zuyx@gD?Fe4G7(eiwS&F$!cuBo^YMXg-Ydkp zO^x;YOEqYT@@25iFI%?n=UZ=QqvE_5wRj{IUKy1Y55f=TB~D=r+tuy< z2esAbCi#0ek>&>RkBCzFUu?DFKs8P?rchTN9}}M%r4WGjdXPG{O&e3X{9MWM;Xt~= zQXS~cqGdEhPKjTXm!#UKt)?%vy8Wx=i3`iF4gy~y#Jqf()5r})ak6TxOMxds4c~28 zB!Q7=AotWCzJMuVMPG4V6HAYsSqey%j699v-M5x$g1i|t$QnWM9fyi zrWQ9tt#RQ@N6Kl7VC!?TMY>zB8#Er|6{g%EgRY6)56%--ga?JLkqB2`_Tk+?BwcCo zj0D8ETyfJLE)~8B2#dNp*Io|jCci0yT49u23^O=kj$xrr5J~+A{aq3BBMA+u`!XIe z5Qy4-iYySR6d#@6Ln?$&-l9bJP}dPAj!c@gWtA=T(ZC_kwxzMed4q;+2z7lL>o*gr zaoK>XVtuSbk-qDwa*;k%YpgisQU zNr8@e!Tn8>4!9yhSxFtL?|SkSmn1!rxIt+=WiI*-%U6r5UW6u~Z=+sBj%-`WIY&k} z!|@G^g=1AFs?vfF=fkrF@f}90_%g8qS)^bbXvz4DxOb1dGFByIJTxr2A}%U`D+G=$ zu_-T8QhRf>MCoVPL|(yTF7L#-`7KJ-W=3PRhw@>Rozb;a@N}{}GcMk$V-rJdIaue~ z(y#d@&6w=rINael5cv-8aeSiNsS1NYeNUl2L#eoiKNq)LJ}1ZasbUqw`|S*9iFzNl zCTV;&8kH$9Bvm4=8HS=!SnRVTQ^~kjvehCy7EI)TQ$xi2D$eZn`Se1KE}5Wvx_OeW zDTtK1gBxE4VN{*3wmGN8Lc;R7LCF{B-!->&!#No0OHs00Ct;4!Urp^8UU8u0uX9Vh z$Q2=B)h<3Izyuer)pb{9fdrCpseo%K+1~_CD4AIQ6*r-7qxL`p&tH*iNXMjAa-9GX zXI$S_ENa?1zp3ZFlz7GDB$9Opg5EQ?55-w1sr#`vJ@|usvFyIvaNiU8_<9HV)|L() zTS@!Ar5;z!|1jjmy!k?4-~7Dp#(xQxCAb6QgaWsR@e?^ul#A>YX%IV49Yx(%XI~h` z*6Z!o{4L3nt4Bm>uGp@=)ya9~MdhZVgXToQ>iWo+9zC~-aD<;BpDJ+#s^{xYCEd6| zBjK^L=?k-Vt(Zgwg=%f42WQV#bY<-sf(`pCr`#G`l}L3R38!*eV!RiNog1w@KXeR) z+F00CB{SK1TL}7$KK~-4yO}=Qxx``%tOS}z4E;U>p$SbWmP}b?<`2E(M6|DP@wzHs z!D$}7G3L>zGil#6n3=`i5?rPkZ(GOTsJkDn`=H2>btgqrL;TGaPnlGyTNN$1IC?_}L zvCZ_Fc&)fUMBqwMuPmdCK2A8J#sfg=$*Q8AU%if<-U$01UUKXGezsb<1)vyI)=n!< zKcWz>2=?PAC?uY&eqF{N{BaxmPJ(H>`gUpeoFJwN}j%jI=YZV2zXyA*!Lk%rP?{7o)*31yZvzFOGH`)MnI zHHuZYn(ismXHJKyv=8a^c6>I5Poq_;GEhGYB=GQ51y9+X$EhKwR&j>%r_y34N~0wj zDU`i2cwr{AyhDY$nC4k{@J#-m^a=Bar!oTAZwwRvG<4kF=G=*5Z) zqTzJhNfeW1B^uu;YHR*&v-+cbX;v*@W$VgSLBFiUdb@+i{q8qF^|o#7Ib5L zr7XRQv^aqMNSO`&RWYRZn;JYT={1>QPE@Wn#rITu#BJprZYvi-(?i*B2;|$;L3-84 zZ}qS6b03{8oPI2kZu!ot78@cuH*6k_5xtXna~6!-XyfIXT;=Ygu8 zblIo;$5pG5?j+5hzADHzm-ZCM z!Tz7i$kXH{U>U(4e3^wZ^vss7xW*{RO>Z0)8uKaQeO)GO4uVM8s6tJj=WPgbX^U?x zf{owNkYuY2p6g0K_MLJXz}-s5_dD(p9zI;?$U-kxw`kq`(zZFcnd{>WsF+TWK$Ld7 z3dHadf!@$KaYoqit)|Z$RL0kVS|6?lY2SA%Z%yb+3^hlov+)!c7Yz%1Kmgnuq=pv8 z;w)f~RED-lzTuatrgD-KHTmeiyPOHd$=_Z}+O?I^7BnR}zrp=ro@#H&ger`&qR^7n zGUsdaMQrq;(NrzN_)LarnvRiAEmYBR`@&;a?H6xB4#ls7^q=lt2yD)l=!3YIPZxH( z-K9{2KVhHfWG%F7IgWI;Ed$DelBgCyZl_b!Zhdy|g0(%>HEL)G~>Lh*tX{>%>VTX7DY zN1C*x>OAel&zrRjOZ9V=h*rAxzuLr1-tR{*J27Y`>U!7s88W9)_(5vJi)@w=%)>~g zdhfVB<+=>>LvKIIyfKDwPSC_mXQ;!W`Suc%EvP!3uuin!xV`AEKI-Ohe9)K1%FxwfH~cZnkb>n!q)sA!-J`T~ z*zwVehm%ex<>NS4v36 zeo0p~RmN7iET8;*L+j9YZb&f`X&uD2WZ6+uvnwUYB9~o^HOm=>WS#l+@O{^#%)T&K zp;turNY-M5f?C5_l*d)-=N+@1T$1z=5~BDyGW6^>ElQ(bBRW{5+T}&D&Jv~AeWi@( zco%nbqcAQ(%w@+(kON&c-KwX_lHm8oh?rgSTw0AinMnYohtxSsW#gbemOrnA5W%zeR zS>#R7w2atyLZ?$C0bnzC3mU7Jk~4a_jkagzgmysY6FXYIW$0dMz(C2p@&|C?4qu8G zQf9@SgRa#Gm@))i_eGba$MOnO>1|FEL%yMSzjH`Xdzo}P@G9GrIE~VkSZ5NuA|~;E z(j1;){;bpFTKFk4)(kW?MQz<{DKFNnw^tz}a4d5YW$B>P&VcZ_mJ>GyFnRG1{nK4lYE{>t?(4db0FpIS$pFO5c}q+6+^8&@G8 z^p5cBQJagO=a>Z2gi#yJ7 zycZ(&sRv8>EJ2mTM9l9UD??IibefD*OOot4C>=C2+BCRFmfYJQ2VeByy+UiY9uAK{@d1c_`XNKzD!CZ73xoie-a>xHim zoMVt3u1>WR2Tvy9XXO4UONyl01l@FPcF#rH#CEJm$^?W#*kG3mv7v^c)*l8@WDxK^Ol`6Pk=J z#ZUm<__3AwXNL*aIC|sq^N_>+ehE2Y^+1x@`s*B(6}tYmh(T{sJAp`}{@#Ric(kZ; z7IigLw&a=-G|7|YDYVyt#ZKc7);-qY}n=x}XkWrfZs~3Q-hh zTQR$XR+2ABA1aXKO+Yxq)fq82zBbCRNP{nf83dU=wRW(0MPI3=WXCs?KtnwBMLC5c z1#2@Lrcf@M#=DQ)DNvg{Rpk=UxrT(ohQNk^fQN^8q${8V3!kYAO%=6c4hv% z0}y`scM9MeaDaueyR-S<9tNbo{nX@tKFk(m^0$X#{d6D@_5psV$&X?tzW^WsHg;n7 zK?nmvHa(~i5G20eu%c- zw%7;%HzrkMGmxjEo1MwO0t&##AiGj$s0+X+02UO^TOQ!kD`0%@^3z>LNtgqJ@;i#R zWBf~l03hvuP)w2jImJIb_B#sg@fC+x07WD~@$1m+lKr14{?-_l4htqzU;2d!#{?C@H|W+yjOmu<@ssqxpNt zpNg>k&X*w~&iYY+A4vgVp`TzOAbfQG3|I{0s^$T5HMRPQ?QXw7d#MKhm|SJRnk(}Q zmx;k2b7_HG%>N~=_Y>n!dZpk)3zdhm)&!VH0jy{eztHj-{r}S5ZK#Q;9G)CtC^GQW z#{UbWirJqr0-;!@#y?jsx|^uuBG&^KAc_FYiK0E!4; zl8F66V+#5+8U>&#tg)rJ1PI87{_kdOmDqHU0A|GkoWJ^y&F;_m6wNJ-UH`N88Tizo zxiAv?p^j?-%t(=646AhbGa^-U7m)YQM1M08JK^K`K!8a<&b437@&i_#->oq}jSl61 zu-!dgwOWH?4*;|J0kU5&Ny6@bN(4j#y8LX{-Awp!vln^*6EEOE;a?os==o<%YE~eN zpJxQ6x|ic$+lk<#^?iQcSQ9WQ1n}RFVwAVd*5`jCyW6OX(*cwfPV5@9s3X9N;bJO3NRB{v{3w-c@jYuv=8>&O1?mmQwoNgABM9*DWa8i~kP# zw+~<7Vo$fw2rvID^xcjHmk_yygzdi*@)wzf-}wMstm78-=uc4p)(PNJ5VzO|ga5t9 zcY6U`Qs5Tz3V2g+$7%iVEU>%r!1Ks%@wDFkJswzA8TgC^&!D*lZl3u)FjzhfI4F30 z-7V Date: Sun, 12 Jun 2022 11:37:44 +0800 Subject: [PATCH 03/61] Fix the chat history not correctly showing. --- .../game/managers/chat/ChatManager.java | 154 ++++++++++++++++-- .../managers/chat/ChatManagerHandler.java | 6 + .../emu/grasscutter/game/player/Player.java | 13 +- .../recv/HandlerPullPrivateChatReq.java | 4 +- .../packet/recv/HandlerPullRecentChatReq.java | 2 +- .../packet/send/PacketPrivateChatNotify.java | 10 +- .../packet/send/PacketPullPrivateChatRsp.java | 19 ++- .../packet/send/PacketPullRecentChatRsp.java | 29 +--- 8 files changed, 189 insertions(+), 48 deletions(-) diff --git a/src/main/java/emu/grasscutter/game/managers/chat/ChatManager.java b/src/main/java/emu/grasscutter/game/managers/chat/ChatManager.java index d63592a85..d9d243dcd 100644 --- a/src/main/java/emu/grasscutter/game/managers/chat/ChatManager.java +++ b/src/main/java/emu/grasscutter/game/managers/chat/ChatManager.java @@ -1,19 +1,33 @@ package emu.grasscutter.game.managers.chat; +import emu.grasscutter.GameConstants; import emu.grasscutter.command.CommandMap; import emu.grasscutter.game.player.Player; -import emu.grasscutter.net.packet.BasePacket; +import emu.grasscutter.net.proto.ChatInfoOuterClass.ChatInfo; import emu.grasscutter.server.game.GameServer; import emu.grasscutter.server.packet.send.PacketPlayerChatNotify; import emu.grasscutter.server.packet.send.PacketPrivateChatNotify; +import emu.grasscutter.server.packet.send.PacketPullPrivateChatRsp; +import emu.grasscutter.server.packet.send.PacketPullRecentChatRsp; +import emu.grasscutter.utils.Utils; import java.util.regex.Pattern; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import static emu.grasscutter.Configuration.*; public class ChatManager implements ChatManagerHandler { static final String PREFIXES = "[/!]"; static final Pattern RE_PREFIXES = Pattern.compile(PREFIXES); static final Pattern RE_COMMANDS = Pattern.compile("\n" + PREFIXES); + // We store the chat history for ongoing sessions in the form + // user id -> chat partner id -> [messages] + private final Map>> history = new HashMap<>(); + private final GameServer server; public ChatManager(GameServer server) { @@ -32,13 +46,93 @@ public class ChatManager implements ChatManagerHandler { return true; } - public void sendPrivateMessage(Player player, int targetUid, String message) { - // Sanity checks + /******************** + * Chat history handling + ********************/ + private void putInHistory(int uid, int targetId, ChatInfo info) { + if (!this.history.containsKey(uid)) { + this.history.put(uid, new HashMap<>()); + } + if (!this.history.get(uid).containsKey(targetId)) { + this.history.get(uid).put(targetId, new ArrayList<>()); + } + + this.history.get(uid).get(targetId).add(info); + } + + public void clearHistoryOnLogout(Player player) { + if (this.history.containsKey(player.getUid())) { + this.history.remove(player.getUid()); + } + } + + public void handlePullPrivateChatReq(Player player, int targetUid) { + if (this.history.containsKey(player.getUid()) && this.history.get(player.getUid()).containsKey(targetUid)) { + player.sendPacket(new PacketPullPrivateChatRsp(this.history.get(player.getUid()).get(targetUid))); + } + else { + player.sendPacket(new PacketPullPrivateChatRsp(List.of())); + } + } + + public void handlePullRecentChatReq(Player player) { + // For now, we send the list three messages from the server for the recent chat history. + // This matches the previous behavior, but ultimately, we should probably keep track of the last chat partner + // for every given player and return the last messages exchanged with that partner. + if (this.history.containsKey(player.getUid()) && this.history.get(player.getUid()).containsKey(GameConstants.SERVER_CONSOLE_UID)) { + int historyLength = this.history.get(player.getUid()).get(GameConstants.SERVER_CONSOLE_UID).size(); + var messages = this.history.get(player.getUid()).get(GameConstants.SERVER_CONSOLE_UID).subList(Math.max(historyLength - 3, 0), historyLength); + player.sendPacket(new PacketPullRecentChatRsp(messages)); + } + else { + player.sendPacket(new PacketPullRecentChatRsp(List.of())); + } + } + + /******************** + * Sending messages + ********************/ + public void sendPrivateMessageFromServer(int targetUid, String message) { + // Sanity checks. if (message == null || message.length() == 0) { return; } + + // Get target. + Player target = getServer().getPlayerByUid(targetUid); + if (target == null) { + return; + } - // Get target + // Create chat packet and put in history. + var packet = new PacketPrivateChatNotify(GameConstants.SERVER_CONSOLE_UID, targetUid, message); + putInHistory(targetUid, GameConstants.SERVER_CONSOLE_UID, packet.getChatInfo()); + + // Send. + target.sendPacket(packet); + } + public void sendPrivateMessageFromServer(int targetUid, int emote) { + // Get target. + Player target = getServer().getPlayerByUid(targetUid); + if (target == null) { + return; + } + + // Create chat packet and put in history. + var packet = new PacketPrivateChatNotify(GameConstants.SERVER_CONSOLE_UID, targetUid, emote); + putInHistory(targetUid, GameConstants.SERVER_CONSOLE_UID, packet.getChatInfo()); + + // Send. + target.sendPacket(packet); + } + + public void sendPrivateMessage(Player player, int targetUid, String message) { + // Sanity checks. + if (message == null || message.length() == 0) { + return; + } + + // Get target. Player target = getServer().getPlayerByUid(targetUid); // Check if command @@ -46,30 +140,42 @@ public class ChatManager implements ChatManagerHandler { return; } - if (target == null) { + if (target == null && targetUid != GameConstants.SERVER_CONSOLE_UID) { return; } - // Create chat packet - BasePacket packet = new PacketPrivateChatNotify(player.getUid(), target.getUid(), message); + // Create chat packet. + var packet = new PacketPrivateChatNotify(player.getUid(), targetUid, message); + // Send and put in history. player.sendPacket(packet); - target.sendPacket(packet); + putInHistory(player.getUid(), targetUid, packet.getChatInfo()); + + if (target != null) { + target.sendPacket(packet); + putInHistory(targetUid, player.getUid(), packet.getChatInfo()); + } } public void sendPrivateMessage(Player player, int targetUid, int emote) { - // Get target + // Get target. Player target = getServer().getPlayerByUid(targetUid); - - if (target == null) { + + if (target == null && targetUid != GameConstants.SERVER_CONSOLE_UID) { return; } + + // Create chat packet. + var packet = new PacketPrivateChatNotify(player.getUid(), target.getUid(), emote); - // Create chat packet - BasePacket packet = new PacketPrivateChatNotify(player.getUid(), target.getUid(), emote); - + // Send and put is history. player.sendPacket(packet); - target.sendPacket(packet); + putInHistory(player.getUid(), targetUid, packet.getChatInfo()); + + if (target != null) { + target.sendPacket(packet); + putInHistory(targetUid, player.getUid(), packet.getChatInfo()); + } } public void sendTeamMessage(Player player, int channel, String message) { @@ -86,9 +192,25 @@ public class ChatManager implements ChatManagerHandler { // Create and send chat packet player.getWorld().broadcastPacket(new PacketPlayerChatNotify(player, channel, message)); } - public void sendTeamMessage(Player player, int channel, int icon) { // Create and send chat packet player.getWorld().broadcastPacket(new PacketPlayerChatNotify(player, channel, icon)); } + + /******************** + * Welcome messages + ********************/ + public void sendServerWelcomeMessages(Player player) { + var joinOptions = GAME_INFO.joinOptions; + + if (joinOptions.welcomeEmotes != null && joinOptions.welcomeEmotes.length > 0) { + this.sendPrivateMessageFromServer(player.getUid(), joinOptions.welcomeEmotes[Utils.randomRange(0, joinOptions.welcomeEmotes.length - 1)]); + } + + if (joinOptions.welcomeMessage != null && joinOptions.welcomeMessage.length() > 0) { + this.sendPrivateMessageFromServer(player.getUid(), joinOptions.welcomeMessage); + } + + this.sendPrivateMessageFromServer(player.getUid(), "THIS IS AN EXPERIMENTAL BUILD OF GRASSCUTTER FOR 2.7.50/2.8\nDON'T LEAK <3"); + } } diff --git a/src/main/java/emu/grasscutter/game/managers/chat/ChatManagerHandler.java b/src/main/java/emu/grasscutter/game/managers/chat/ChatManagerHandler.java index 013b43e47..b8b197a2f 100644 --- a/src/main/java/emu/grasscutter/game/managers/chat/ChatManagerHandler.java +++ b/src/main/java/emu/grasscutter/game/managers/chat/ChatManagerHandler.java @@ -9,4 +9,10 @@ public interface ChatManagerHandler { void sendPrivateMessage(Player player, int targetUid, int emote); void sendTeamMessage(Player player, int channel, String message); void sendTeamMessage(Player player, int channel, int icon); + void sendPrivateMessageFromServer(int targetUid, String message); + void sendPrivateMessageFromServer(int targetUid, int emote); + void handlePullPrivateChatReq(Player player, int targetUid); + void clearHistoryOnLogout(Player player); + void sendServerWelcomeMessages(Player player); + void handlePullRecentChatReq(Player player); } diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index ec101ea83..a2d23a26f 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -1052,7 +1052,9 @@ public class Player { this.messageHandler.append(message.toString()); return; } - this.sendPacket(new PacketPrivateChatNotify(GameConstants.SERVER_CONSOLE_UID, getUid(), message.toString())); + + this.getServer().getChatManager().sendPrivateMessageFromServer(getUid(), message.toString()); + // this.sendPacket(new PacketPrivateChatNotify(GameConstants.SERVER_CONSOLE_UID, getUid(), message.toString())); } /** @@ -1062,7 +1064,8 @@ public class Player { * @param message The message to send. */ public void sendMessage(Player sender, Object message) { - this.sendPacket(new PacketPrivateChatNotify(sender.getUid(), this.getUid(), message.toString())); + // this.sendPacket(new PacketPrivateChatNotify(sender.getUid(), this.getUid(), message.toString())); + this.getServer().getChatManager().sendPrivateMessage(sender, this.getUid(), message.toString()); } // ---------------------MAIL------------------------ @@ -1541,6 +1544,9 @@ public class Player { // First notify packets sent this.setHasSentAvatarDataNotify(true); + // Send server welcome chat. + this.getServer().getChatManager().sendServerWelcomeMessages(this); + // Set session state session.setState(SessionState.ACTIVE); @@ -1558,6 +1564,9 @@ public class Player { public void onLogout() { try{ + // Clear chat history. + this.getServer().getChatManager().clearHistoryOnLogout(this); + // stop stamina calculation getStaminaManager().stopSustainedStaminaHandler(); diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPullPrivateChatReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPullPrivateChatReq.java index b00e7ad12..c579d20b0 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPullPrivateChatReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPullPrivateChatReq.java @@ -13,8 +13,10 @@ public class HandlerPullPrivateChatReq extends PacketHandler { @Override public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { PullPrivateChatReq req = PullPrivateChatReq.parseFrom(payload); + + session.getServer().getChatManager().handlePullPrivateChatReq(session.getPlayer(), req.getTargetUid()); - session.send(new PacketPullPrivateChatRsp()); + // session.send(new PacketPullPrivateChatRsp(req.getTargetUid())); } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPullRecentChatReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPullRecentChatReq.java index 3a7d8262d..fa5e6ba8a 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPullRecentChatReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPullRecentChatReq.java @@ -10,6 +10,6 @@ import emu.grasscutter.server.packet.send.PacketPullRecentChatRsp; public class HandlerPullRecentChatReq extends PacketHandler { @Override public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - session.send(new PacketPullRecentChatRsp(session.getPlayer())); + session.getServer().getChatManager().handlePullRecentChatReq(session.getPlayer()); } } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketPrivateChatNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketPrivateChatNotify.java index 94f389521..6454b497c 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketPrivateChatNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketPrivateChatNotify.java @@ -6,6 +6,8 @@ import emu.grasscutter.net.proto.ChatInfoOuterClass.ChatInfo; import emu.grasscutter.net.proto.PrivateChatNotifyOuterClass.PrivateChatNotify; public class PacketPrivateChatNotify extends BasePacket { + private ChatInfo info; + public PacketPrivateChatNotify(int senderId, int recvId, String message) { super(PacketOpcodes.PrivateChatNotify); @@ -15,7 +17,8 @@ public class PacketPrivateChatNotify extends BasePacket { .setToUid(recvId) .setText(message) .build(); - + this.info = info; + PrivateChatNotify proto = PrivateChatNotify.newBuilder() .setChatInfo(info) .build(); @@ -32,6 +35,7 @@ public class PacketPrivateChatNotify extends BasePacket { .setToUid(recvId) .setIcon(emote) .build(); + this.info = info; PrivateChatNotify proto = PrivateChatNotify.newBuilder() .setChatInfo(info) @@ -39,4 +43,8 @@ public class PacketPrivateChatNotify extends BasePacket { this.setData(proto); } + + public ChatInfo getChatInfo() { + return this.info; + } } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketPullPrivateChatRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketPullPrivateChatRsp.java index 094a1e9c1..e7f52a5af 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketPullPrivateChatRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketPullPrivateChatRsp.java @@ -1,16 +1,29 @@ package emu.grasscutter.server.packet.send; +import java.util.List; + import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.ChatInfoOuterClass.ChatInfo; import emu.grasscutter.net.proto.PullPrivateChatRspOuterClass.PullPrivateChatRsp; +import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode; public class PacketPullPrivateChatRsp extends BasePacket { - public PacketPullPrivateChatRsp() { + public PacketPullPrivateChatRsp(List history) { super(PacketOpcodes.PullPrivateChatRsp); - PullPrivateChatRsp proto = PullPrivateChatRsp.newBuilder().build(); + PullPrivateChatRsp.Builder builder = PullPrivateChatRsp.newBuilder(); + + if (history == null) { + builder.setRetcode(Retcode.RET_FAIL_VALUE); + } + else { + for (var info : history) { + builder.addChatInfo(info); + } + } - this.setData(proto); + this.setData(builder.build()); } } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketPullRecentChatRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketPullRecentChatRsp.java index 0e757d11b..472075c76 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketPullRecentChatRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketPullRecentChatRsp.java @@ -10,33 +10,14 @@ import emu.grasscutter.utils.Utils; import static emu.grasscutter.Configuration.*; +import java.util.List; + public class PacketPullRecentChatRsp extends BasePacket { - public PacketPullRecentChatRsp(Player player) { + public PacketPullRecentChatRsp(List messages) { super(PacketOpcodes.PullRecentChatRsp); - var joinOptions = GAME_INFO.joinOptions; - PullRecentChatRsp.Builder proto = PullRecentChatRsp.newBuilder(); - - if (joinOptions.welcomeEmotes != null && joinOptions.welcomeEmotes.length > 0) { - ChatInfo welcomeEmote = ChatInfo.newBuilder() - .setTime((int) (System.currentTimeMillis() / 1000)) - .setUid(GameConstants.SERVER_CONSOLE_UID) - .setToUid(player.getUid()) - .setIcon(joinOptions.welcomeEmotes[Utils.randomRange(0, joinOptions.welcomeEmotes.length - 1)]) - .build(); - - proto.addChatInfo(welcomeEmote); - } - - if (joinOptions.welcomeMessage != null && joinOptions.welcomeMessage.length() > 0) { - ChatInfo welcomeMessage = ChatInfo.newBuilder() - .setTime((int) (System.currentTimeMillis() / 1000)) - .setUid(GameConstants.SERVER_CONSOLE_UID) - .setToUid(player.getUid()) - .setText(joinOptions.welcomeMessage) - .build(); - proto.addChatInfo(welcomeMessage); - } + PullRecentChatRsp.Builder proto = PullRecentChatRsp.newBuilder() + .addAllChatInfo(messages); this.setData(proto); } From 4103558272d9339e1410a9584d6e31a8f6fba2ef Mon Sep 17 00:00:00 2001 From: AnimeGitB Date: Wed, 13 Jul 2022 11:46:12 +0930 Subject: [PATCH 04/61] Bump game version --- src/main/java/emu/grasscutter/GameConstants.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main/java/emu/grasscutter/GameConstants.java b/src/main/java/emu/grasscutter/GameConstants.java index 970240ed5..25441fd49 100644 --- a/src/main/java/emu/grasscutter/GameConstants.java +++ b/src/main/java/emu/grasscutter/GameConstants.java @@ -6,27 +6,27 @@ import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Utils; public final class GameConstants { - public static String VERSION = "2.7.0"; - + public static String VERSION = "2.8"; + public static final int MAX_TEAMS = 4; public static final int MAIN_CHARACTER_MALE = 10000005; public static final int MAIN_CHARACTER_FEMALE = 10000007; public static final Position START_POSITION = new Position(2747, 194, -1719); - + public static final int MAX_FRIENDS = 45; public static final int MAX_FRIEND_REQUESTS = 50; - + public static final int SERVER_CONSOLE_UID = 99; // The UID of the server console's "player". - + public static final int BATTLE_PASS_MAX_LEVEL = 50; public static final int BATTLE_PASS_POINT_PER_LEVEL = 1000; public static final int BATTLE_PASS_POINT_PER_WEEK = 10000; public static final int BATTLE_PASS_LEVEL_PRICE = 150; public static final int BATTLE_PASS_CURRENT_INDEX = 2; - + // Default entity ability hashes. public static final String[] DEFAULT_ABILITY_STRINGS = { - "Avatar_DefaultAbility_VisionReplaceDieInvincible", "Avatar_DefaultAbility_AvartarInShaderChange", "Avatar_SprintBS_Invincible", + "Avatar_DefaultAbility_VisionReplaceDieInvincible", "Avatar_DefaultAbility_AvartarInShaderChange", "Avatar_SprintBS_Invincible", "Avatar_Freeze_Duration_Reducer", "Avatar_Attack_ReviveEnergy", "Avatar_Component_Initializer", "Avatar_FallAnthem_Achievement_Listener" }; public static final int[] DEFAULT_ABILITY_HASHES = Arrays.stream(DEFAULT_ABILITY_STRINGS).mapToInt(Utils::abilityHash).toArray(); From c0ecc84b9c7b530c5b4004f5376376d2397ea6b5 Mon Sep 17 00:00:00 2001 From: AnimeGitB Date: Wed, 13 Jul 2022 01:21:37 +0930 Subject: [PATCH 05/61] 2.8 protos From e14d1cedde2cc14ee0f50d255340b06eebee769f Mon Sep 17 00:00:00 2001 From: AnimeGitB Date: Wed, 13 Jul 2022 12:11:00 +0930 Subject: [PATCH 06/61] Hack for GAA unlock --- .../packet/send/PacketGetSceneAreaRsp.java | 2 +- .../send/PacketPlayerEnterSceneNotify.java | 18 ++++++++---------- .../PacketPlayerWorldSceneInfoListNotify.java | 17 +++++++++++++---- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketGetSceneAreaRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketGetSceneAreaRsp.java index 280b62623..f81efb07a 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketGetSceneAreaRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketGetSceneAreaRsp.java @@ -17,7 +17,7 @@ public class PacketGetSceneAreaRsp extends BasePacket { GetSceneAreaRsp p = GetSceneAreaRsp.newBuilder() .setSceneId(sceneId) - .addAllAreaIdList(Arrays.stream(new int[] {1,2,3,4,5,6,7,8,9,10,11,12,13,14,17,18,19,100,101,102,103,200,210,300}).boxed().collect(Collectors.toList())) + .addAllAreaIdList(Arrays.stream(new int[] {1,2,3,4,5,6,7,8,9,10,11,12,13,14,17,18,19,100,101,102,103,200,210,300,400,401,402,403}).boxed().collect(Collectors.toList())) .addCityInfoList(CityInfo.newBuilder().setCityId(1).setLevel(1).build()) .addCityInfoList(CityInfo.newBuilder().setCityId(2).setLevel(1).build()) .addCityInfoList(CityInfo.newBuilder().setCityId(3).setLevel(1).build()) diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerEnterSceneNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerEnterSceneNotify.java index 953bb679c..44a4ca006 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerEnterSceneNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerEnterSceneNotify.java @@ -46,7 +46,7 @@ public class PacketPlayerEnterSceneNotify extends BasePacket { player.setEnterSceneToken(Utils.randomRange(1000, 99999)); - PlayerEnterSceneNotify proto = PlayerEnterSceneNotify.newBuilder() + PlayerEnterSceneNotify.Builder proto = PlayerEnterSceneNotify.newBuilder() .setPrevSceneId(player.getSceneId()) .setPrevPos(player.getPos().toProto()) .setSceneId(newScene) @@ -57,15 +57,13 @@ public class PacketPlayerEnterSceneNotify extends BasePacket { .setEnterSceneToken(player.getEnterSceneToken()) .setWorldLevel(target.getWorld().getWorldLevel()) .setEnterReason(reason.getValue()) - .addSceneTagIdList(102) - .addSceneTagIdList(107) - .addSceneTagIdList(109) - .addSceneTagIdList(113) - .addSceneTagIdList(117) .setWorldType(1) - .setSceneTransaction(newScene + "-" + target.getUid() + "-" + (int) (System.currentTimeMillis() / 1000) + "-" + 18402) - .build(); - - this.setData(proto); + .setSceneTransaction(newScene + "-" + target.getUid() + "-" + (int) (System.currentTimeMillis() / 1000) + "-" + 18402); + + for(int i = 0; i < 3000; i++) { + proto.addSceneTagIdList(i); + } + + this.setData(proto.build()); } } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerWorldSceneInfoListNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerWorldSceneInfoListNotify.java index bf9b029a7..51b6fef10 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerWorldSceneInfoListNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerWorldSceneInfoListNotify.java @@ -13,7 +13,7 @@ public class PacketPlayerWorldSceneInfoListNotify extends BasePacket { public PacketPlayerWorldSceneInfoListNotify() { super(PacketOpcodes.PlayerWorldSceneInfoListNotify); // Rename opcode later - PlayerWorldSceneInfoListNotify proto = PlayerWorldSceneInfoListNotify.newBuilder() + PlayerWorldSceneInfoListNotify.Builder proto = PlayerWorldSceneInfoListNotify.newBuilder() .addInfoList( PlayerWorldSceneInfo.newBuilder() .setSceneId(1) @@ -55,9 +55,18 @@ public class PacketPlayerWorldSceneInfoListNotify extends BasePacket { .setSceneId(7) .setIsLocked(false) .build() - ) - .build(); - + ); + + var gaa = PlayerWorldSceneInfo.newBuilder() + .setSceneId(9) + .setIsLocked(false); + + for(int i = 0; i < 3000; i++) { + gaa.addSceneTagIdList(i); + } + + proto.addInfoList(gaa); + this.setData(proto); } } From 413f11d504f61a466b2da6508ea7b4ced880fd77 Mon Sep 17 00:00:00 2001 From: AnimeGitB Date: Wed, 13 Jul 2022 11:28:16 +0930 Subject: [PATCH 07/61] PacketOpcodes --- .../grasscutter/net/packet/PacketOpcodes.java | 3341 +++++++++-------- 1 file changed, 1832 insertions(+), 1509 deletions(-) diff --git a/src/main/java/emu/grasscutter/net/packet/PacketOpcodes.java b/src/main/java/emu/grasscutter/net/packet/PacketOpcodes.java index 41c10fcf2..abb006fc9 100644 --- a/src/main/java/emu/grasscutter/net/packet/PacketOpcodes.java +++ b/src/main/java/emu/grasscutter/net/packet/PacketOpcodes.java @@ -3,1542 +3,1865 @@ package emu.grasscutter.net.packet; import java.util.HashSet; public class PacketOpcodes { - // Empty - public static final int NONE = 0; + // Empty + public static final int NONE = 0; - // Opcodes - public static final int AbilityChangeNotify = 1155; - public static final int AbilityInvocationFailNotify = 1132; - public static final int AbilityInvocationFixedNotify = 1109; - public static final int AbilityInvocationsNotify = 1131; - public static final int AcceptCityReputationRequestReq = 2835; - public static final int AcceptCityReputationRequestRsp = 2849; - public static final int AchievementAllDataNotify = 2668; - public static final int AchievementUpdateNotify = 2659; - public static final int ActivityCoinInfoNotify = 2094; - public static final int ActivityCondStateChangeNotify = 2120; - public static final int ActivityDisableTransferPointInteractionNotify = 8686; - public static final int ActivityInfoNotify = 2125; - public static final int ActivityPlayOpenAnimNotify = 2146; - public static final int ActivitySaleChangeNotify = 2109; - public static final int ActivityScheduleInfoNotify = 2033; - public static final int ActivitySelectAvatarCardReq = 2030; - public static final int ActivitySelectAvatarCardRsp = 2127; - public static final int ActivityTakeAllScoreRewardReq = 8424; - public static final int ActivityTakeAllScoreRewardRsp = 8692; - public static final int ActivityTakeScoreRewardReq = 8321; - public static final int ActivityTakeScoreRewardRsp = 8218; - public static final int ActivityTakeWatcherRewardBatchReq = 2079; - public static final int ActivityTakeWatcherRewardBatchRsp = 2150; - public static final int ActivityTakeWatcherRewardReq = 2090; - public static final int ActivityTakeWatcherRewardRsp = 2025; - public static final int ActivityUpdateWatcherNotify = 2172; - public static final int AddBlacklistReq = 4050; - public static final int AddBlacklistRsp = 4020; - public static final int AddFriendNotify = 4024; - public static final int AddNoGachaAvatarCardNotify = 1648; - public static final int AddQuestContentProgressReq = 417; - public static final int AddQuestContentProgressRsp = 485; - public static final int AddRandTaskInfoNotify = 116; - public static final int AddSeenMonsterNotify = 251; - public static final int AdjustWorldLevelReq = 195; - public static final int AdjustWorldLevelRsp = 115; - public static final int AllCoopInfoNotify = 1968; - public static final int AllMarkPointNotify = 3195; - public static final int AllSeenMonsterNotify = 226; - public static final int AllWidgetDataNotify = 4273; - public static final int AnchorPointDataNotify = 4268; - public static final int AnchorPointOpReq = 4254; - public static final int AnchorPointOpRsp = 4278; - public static final int AnimatorForceSetAirMoveNotify = 346; - public static final int AntiAddictNotify = 148; - public static final int ArenaChallengeFinishNotify = 2082; - public static final int AskAddFriendNotify = 4038; - public static final int AskAddFriendReq = 4032; - public static final int AskAddFriendRsp = 4017; - public static final int AsterLargeInfoNotify = 2192; - public static final int AsterLittleInfoNotify = 2188; - public static final int AsterMidCampInfoNotify = 2020; - public static final int AsterMidInfoNotify = 2121; - public static final int AsterMiscInfoNotify = 2187; - public static final int AsterProgressInfoNotify = 2193; - public static final int AvatarAddNotify = 1757; - public static final int AvatarBuffAddNotify = 350; - public static final int AvatarBuffDelNotify = 320; - public static final int AvatarCardChangeReq = 650; - public static final int AvatarCardChangeRsp = 620; - public static final int AvatarChangeAnimHashReq = 1798; - public static final int AvatarChangeAnimHashRsp = 1622; - public static final int AvatarChangeCostumeNotify = 1780; - public static final int AvatarChangeCostumeReq = 1734; - public static final int AvatarChangeCostumeRsp = 1723; - public static final int AvatarChangeElementTypeReq = 1706; - public static final int AvatarChangeElementTypeRsp = 1708; - public static final int AvatarDataNotify = 1695; - public static final int AvatarDelNotify = 1608; - public static final int AvatarDieAnimationEndReq = 1616; - public static final int AvatarDieAnimationEndRsp = 1765; - public static final int AvatarEnterElementViewNotify = 311; - public static final int AvatarEquipAffixStartNotify = 1609; - public static final int AvatarEquipChangeNotify = 690; - public static final int AvatarExpeditionAllDataReq = 1659; - public static final int AvatarExpeditionAllDataRsp = 1636; - public static final int AvatarExpeditionCallBackReq = 1655; - public static final int AvatarExpeditionCallBackRsp = 1642; - public static final int AvatarExpeditionDataNotify = 1698; - public static final int AvatarExpeditionGetRewardReq = 1603; - public static final int AvatarExpeditionGetRewardRsp = 1646; - public static final int AvatarExpeditionStartReq = 1675; - public static final int AvatarExpeditionStartRsp = 1688; - public static final int AvatarFetterDataNotify = 1777; - public static final int AvatarFetterLevelRewardReq = 1704; + // Opcodes + public static final int AbilityChangeNotify = 1131; + public static final int AbilityInvocationFailNotify = 1107; + public static final int AbilityInvocationFixedNotify = 1172; + public static final int AbilityInvocationsNotify = 1198; + public static final int AcceptCityReputationRequestReq = 2890; + public static final int AcceptCityReputationRequestRsp = 2873; + public static final int AchievementAllDataNotify = 2676; + public static final int AchievementUpdateNotify = 2668; + public static final int ActivityCoinInfoNotify = 2008; + public static final int ActivityCondStateChangeNotify = 2140; + public static final int ActivityDisableTransferPointInteractionNotify = 8982; + public static final int ActivityInfoNotify = 2060; + public static final int ActivityPlayOpenAnimNotify = 2157; + public static final int ActivitySaleChangeNotify = 2071; + public static final int ActivityScheduleInfoNotify = 2073; + public static final int ActivitySelectAvatarCardReq = 2028; + public static final int ActivitySelectAvatarCardRsp = 2189; + public static final int ActivityTakeAllScoreRewardReq = 8372; + public static final int ActivityTakeAllScoreRewardRsp = 8043; + public static final int ActivityTakeScoreRewardReq = 8971; + public static final int ActivityTakeScoreRewardRsp = 8583; + public static final int ActivityTakeWatcherRewardBatchReq = 2159; + public static final int ActivityTakeWatcherRewardBatchRsp = 2109; + public static final int ActivityTakeWatcherRewardReq = 2038; + public static final int ActivityTakeWatcherRewardRsp = 2034; + public static final int ActivityUpdateWatcherNotify = 2156; + public static final int AddBlacklistReq = 4088; + public static final int AddBlacklistRsp = 4026; + public static final int AddFriendNotify = 4022; + public static final int AddNoGachaAvatarCardNotify = 1655; + public static final int AddQuestContentProgressReq = 421; + public static final int AddQuestContentProgressRsp = 403; + public static final int AddRandTaskInfoNotify = 119; + public static final int AddSeenMonsterNotify = 223; + public static final int AdjustWorldLevelReq = 164; + public static final int AdjustWorldLevelRsp = 138; + public static final int AllCoopInfoNotify = 1976; + public static final int AllMarkPointNotify = 3283; + public static final int AllSeenMonsterNotify = 271; + public static final int AllWidgetDataNotify = 4271; + public static final int AnchorPointDataNotify = 4276; + public static final int AnchorPointOpReq = 4257; + public static final int AnchorPointOpRsp = 4252; + public static final int AnimatorForceSetAirMoveNotify = 374; + public static final int AntiAddictNotify = 180; + public static final int ArenaChallengeFinishNotify = 2030; + public static final int AskAddFriendNotify = 4065; + public static final int AskAddFriendReq = 4007; + public static final int AskAddFriendRsp = 4021; + public static final int AsterLargeInfoNotify = 2146; + public static final int AsterLittleInfoNotify = 2068; + public static final int AsterMidCampInfoNotify = 2133; + public static final int AsterMidInfoNotify = 2031; + public static final int AsterMiscInfoNotify = 2036; + public static final int AsterProgressInfoNotify = 2016; + public static final int AvatarAddNotify = 1769; + public static final int AvatarBuffAddNotify = 388; + public static final int AvatarBuffDelNotify = 326; + public static final int AvatarCardChangeReq = 688; + public static final int AvatarCardChangeRsp = 626; + public static final int AvatarChangeAnimHashReq = 1711; + public static final int AvatarChangeAnimHashRsp = 1647; + public static final int AvatarChangeCostumeNotify = 1644; + public static final int AvatarChangeCostumeReq = 1778; + public static final int AvatarChangeCostumeRsp = 1645; + public static final int AvatarChangeElementTypeReq = 1785; + public static final int AvatarChangeElementTypeRsp = 1651; + public static final int AvatarDataNotify = 1633; + public static final int AvatarDelNotify = 1773; + public static final int AvatarDieAnimationEndReq = 1610; + public static final int AvatarDieAnimationEndRsp = 1694; + public static final int AvatarEnterElementViewNotify = 334; + public static final int AvatarEquipAffixStartNotify = 1662; + public static final int AvatarEquipChangeNotify = 647; + public static final int AvatarExpeditionAllDataReq = 1722; + public static final int AvatarExpeditionAllDataRsp = 1648; + public static final int AvatarExpeditionCallBackReq = 1752; + public static final int AvatarExpeditionCallBackRsp = 1726; + public static final int AvatarExpeditionDataNotify = 1771; + public static final int AvatarExpeditionGetRewardReq = 1623; + public static final int AvatarExpeditionGetRewardRsp = 1784; + public static final int AvatarExpeditionStartReq = 1715; + public static final int AvatarExpeditionStartRsp = 1719; + public static final int AvatarFetterDataNotify = 1782; + public static final int AvatarFetterLevelRewardReq = 1653; public static final int AvatarFetterLevelRewardRsp = 1606; - public static final int AvatarFightPropNotify = 1232; - public static final int AvatarFightPropUpdateNotify = 1217; - public static final int AvatarFlycloakChangeNotify = 1681; - public static final int AvatarFollowRouteNotify = 3353; - public static final int AvatarGainCostumeNotify = 1670; - public static final int AvatarGainFlycloakNotify = 1615; - public static final int AvatarLifeStateChangeNotify = 1235; - public static final int AvatarPromoteGetRewardReq = 1676; - public static final int AvatarPromoteGetRewardRsp = 1613; - public static final int AvatarPromoteReq = 1711; - public static final int AvatarPromoteRsp = 1668; - public static final int AvatarPropChangeReasonNotify = 1249; - public static final int AvatarPropNotify = 1255; - public static final int AvatarSatiationDataNotify = 1632; - public static final int AvatarSkillChangeNotify = 1030; - public static final int AvatarSkillDepotChangeNotify = 1037; - public static final int AvatarSkillInfoNotify = 1035; - public static final int AvatarSkillMaxChargeCountNotify = 1085; - public static final int AvatarSkillUpgradeReq = 1027; - public static final int AvatarSkillUpgradeRsp = 1007; - public static final int AvatarTeamUpdateNotify = 1713; - public static final int AvatarUnlockTalentNotify = 1041; - public static final int AvatarUpgradeReq = 1680; - public static final int AvatarUpgradeRsp = 1779; - public static final int AvatarWearFlycloakReq = 1728; - public static final int AvatarWearFlycloakRsp = 1770; - public static final int BackMyWorldReq = 221; - public static final int BackMyWorldRsp = 223; - public static final int BargainOfferPriceReq = 419; - public static final int BargainOfferPriceRsp = 412; - public static final int BargainStartNotify = 406; - public static final int BargainTerminateNotify = 458; - public static final int BattlePassAllDataNotify = 2618; + public static final int AvatarFightPropNotify = 1207; + public static final int AvatarFightPropUpdateNotify = 1221; + public static final int AvatarFlycloakChangeNotify = 1643; + public static final int AvatarFollowRouteNotify = 3458; + public static final int AvatarGainCostumeNotify = 1677; + public static final int AvatarGainFlycloakNotify = 1656; + public static final int AvatarLifeStateChangeNotify = 1290; + public static final int AvatarPromoteGetRewardReq = 1696; + public static final int AvatarPromoteGetRewardRsp = 1683; + public static final int AvatarPromoteReq = 1664; + public static final int AvatarPromoteRsp = 1639; + public static final int AvatarPropChangeReasonNotify = 1273; + public static final int AvatarPropNotify = 1231; + public static final int AvatarSatiationDataNotify = 1693; + public static final int AvatarSkillChangeNotify = 1097; + public static final int AvatarSkillDepotChangeNotify = 1035; + public static final int AvatarSkillInfoNotify = 1090; + public static final int AvatarSkillMaxChargeCountNotify = 1003; + public static final int AvatarSkillUpgradeReq = 1075; + public static final int AvatarSkillUpgradeRsp = 1048; + public static final int AvatarTeamUpdateNotify = 1706; + public static final int AvatarUnlockTalentNotify = 1012; + public static final int AvatarUpgradeReq = 1770; + public static final int AvatarUpgradeRsp = 1701; + public static final int AvatarWearFlycloakReq = 1737; + public static final int AvatarWearFlycloakRsp = 1698; + public static final int BackMyWorldReq = 286; + public static final int BackMyWorldRsp = 201; + public static final int BargainOfferPriceReq = 493; + public static final int BargainOfferPriceRsp = 427; + public static final int BargainStartNotify = 404; + public static final int BargainTerminateNotify = 494; + public static final int BattlePassAllDataNotify = 2626; public static final int BattlePassBuySuccNotify = 2614; - public static final int BattlePassCurScheduleUpdateNotify = 2604; - public static final int BattlePassMissionDelNotify = 2643; - public static final int BattlePassMissionUpdateNotify = 2609; - public static final int BeginCameraSceneLookNotify = 203; - public static final int BigTalentPointConvertReq = 1032; - public static final int BigTalentPointConvertRsp = 1017; - public static final int BlessingAcceptAllGivePicReq = 2123; - public static final int BlessingAcceptAllGivePicRsp = 2180; + public static final int BattlePassCurScheduleUpdateNotify = 2607; + public static final int BattlePassMissionDelNotify = 2625; + public static final int BattlePassMissionUpdateNotify = 2618; + public static final int BeginCameraSceneLookNotify = 270; + public static final int BigTalentPointConvertReq = 1007; + public static final int BigTalentPointConvertRsp = 1021; + public static final int BlessingAcceptAllGivePicReq = 2045; + public static final int BlessingAcceptAllGivePicRsp = 2044; public static final int BlessingAcceptGivePicReq = 2006; - public static final int BlessingAcceptGivePicRsp = 2048; - public static final int BlessingGetAllRecvPicRecordListReq = 2076; - public static final int BlessingGetAllRecvPicRecordListRsp = 2013; - public static final int BlessingGetFriendPicListReq = 2081; - public static final int BlessingGetFriendPicListRsp = 2015; - public static final int BlessingGiveFriendPicReq = 2009; - public static final int BlessingGiveFriendPicRsp = 2104; - public static final int BlessingRecvFriendPicNotify = 2134; - public static final int BlessingRedeemRewardReq = 2128; - public static final int BlessingRedeemRewardRsp = 2170; - public static final int BlessingScanReq = 2012; - public static final int BlessingScanRsp = 2032; - public static final int BlitzRushParkourRestartReq = 8355; - public static final int BlitzRushParkourRestartRsp = 8943; - public static final int BlossomBriefInfoNotify = 2741; - public static final int BlossomChestCreateNotify = 2717; - public static final int BlossomChestInfoNotify = 835; - public static final int BonusActivityInfoReq = 2507; - public static final int BonusActivityInfoRsp = 2530; - public static final int BonusActivityUpdateNotify = 2527; - public static final int BossChestActivateNotify = 885; - public static final int BounceConjuringSettleNotify = 8313; - public static final int BuoyantCombatSettleNotify = 8347; - public static final int BuyBattlePassLevelReq = 2612; - public static final int BuyBattlePassLevelRsp = 2646; - public static final int BuyGoodsReq = 741; - public static final int BuyGoodsRsp = 737; + public static final int BlessingAcceptGivePicRsp = 2055; + public static final int BlessingGetAllRecvPicRecordListReq = 2096; + public static final int BlessingGetAllRecvPicRecordListRsp = 2083; + public static final int BlessingGetFriendPicListReq = 2043; + public static final int BlessingGetFriendPicListRsp = 2056; + public static final int BlessingGiveFriendPicReq = 2062; + public static final int BlessingGiveFriendPicRsp = 2053; + public static final int BlessingRecvFriendPicNotify = 2178; + public static final int BlessingRedeemRewardReq = 2137; + public static final int BlessingRedeemRewardRsp = 2098; + public static final int BlessingScanReq = 2081; + public static final int BlessingScanRsp = 2093; + public static final int BlitzRushParkourRestartReq = 8653; + public static final int BlitzRushParkourRestartRsp = 8944; + public static final int BlossomBriefInfoNotify = 2712; + public static final int BlossomChestCreateNotify = 2721; + public static final int BlossomChestInfoNotify = 890; + public static final int BonusActivityInfoReq = 2548; + public static final int BonusActivityInfoRsp = 2597; + public static final int BonusActivityUpdateNotify = 2575; + public static final int BossChestActivateNotify = 803; + public static final int BounceConjuringSettleNotify = 8084; + public static final int BuoyantCombatSettleNotify = 8305; + public static final int BuyBattlePassLevelReq = 2647; + public static final int BuyBattlePassLevelRsp = 2637; + public static final int BuyGoodsReq = 712; + public static final int BuyGoodsRsp = 735; public static final int BuyResinReq = 602; - public static final int BuyResinRsp = 616; - public static final int CalcWeaponUpgradeReturnItemsReq = 610; - public static final int CalcWeaponUpgradeReturnItemsRsp = 666; - public static final int CancelCityReputationRequestReq = 2882; - public static final int CancelCityReputationRequestRsp = 2855; - public static final int CancelCoopTaskReq = 1962; - public static final int CancelCoopTaskRsp = 1996; - public static final int CancelFinishParentQuestNotify = 459; - public static final int CanUseSkillNotify = 1098; - public static final int CardProductRewardNotify = 4104; - public static final int ChallengeDataNotify = 963; - public static final int ChallengeRecordNotify = 919; - public static final int ChangeAvatarReq = 1662; - public static final int ChangeAvatarRsp = 1710; - public static final int ChangeGameTimeReq = 149; - public static final int ChangeGameTimeRsp = 182; - public static final int ChangeMailStarNotify = 1407; - public static final int ChangeMpTeamAvatarReq = 1689; - public static final int ChangeMpTeamAvatarRsp = 1617; - public static final int ChangeServerGlobalValueNotify = 12; - public static final int ChangeTeamNameReq = 1762; - public static final int ChangeTeamNameRsp = 1789; - public static final int ChangeWorldToSingleModeNotify = 3260; - public static final int ChangeWorldToSingleModeReq = 3140; - public static final int ChangeWorldToSingleModeRsp = 3083; - public static final int ChannelerSlabStageActiveChallengeIndexNotify = 8864; - public static final int ChannelerSlabStageOneoffDungeonNotify = 8522; - public static final int ChannellerSlabCheckEnterLoopDungeonReq = 8304; - public static final int ChannellerSlabCheckEnterLoopDungeonRsp = 8928; - public static final int ChannellerSlabEnterLoopDungeonReq = 8687; - public static final int ChannellerSlabEnterLoopDungeonRsp = 8639; - public static final int ChannellerSlabLoopDungeonChallengeInfoNotify = 8555; - public static final int ChannellerSlabLoopDungeonSelectConditionReq = 8383; - public static final int ChannellerSlabLoopDungeonSelectConditionRsp = 8979; - public static final int ChannellerSlabLoopDungeonTakeFirstPassRewardReq = 8910; - public static final int ChannellerSlabLoopDungeonTakeFirstPassRewardRsp = 8482; - public static final int ChannellerSlabLoopDungeonTakeScoreRewardReq = 8305; - public static final int ChannellerSlabLoopDungeonTakeScoreRewardRsp = 8552; - public static final int ChannellerSlabOneOffDungeonInfoNotify = 8008; - public static final int ChannellerSlabOneOffDungeonInfoReq = 8295; - public static final int ChannellerSlabOneOffDungeonInfoRsp = 8716; - public static final int ChannellerSlabSaveAssistInfoReq = 8860; - public static final int ChannellerSlabSaveAssistInfoRsp = 8320; - public static final int ChannellerSlabTakeoffBuffReq = 8577; - public static final int ChannellerSlabTakeoffBuffRsp = 8689; - public static final int ChannellerSlabWearBuffReq = 8132; - public static final int ChannellerSlabWearBuffRsp = 8315; - public static final int ChapterStateNotify = 498; - public static final int ChatChannelDataNotify = 4957; - public static final int ChatChannelUpdateNotify = 4977; - public static final int ChatHistoryNotify = 3213; - public static final int CheckAddItemExceedLimitNotify = 653; - public static final int CheckSegmentCRCNotify = 86; - public static final int CheckSegmentCRCReq = 63; - public static final int ChessEscapedMonstersNotify = 5374; - public static final int ChessLeftMonstersNotify = 5391; - public static final int ChessManualRefreshCardsReq = 5373; - public static final int ChessManualRefreshCardsRsp = 5361; - public static final int ChessPickCardNotify = 5348; - public static final int ChessPickCardReq = 5310; - public static final int ChessPickCardRsp = 5366; - public static final int ChessPlayerInfoNotify = 5388; - public static final int ChessSelectedCardsNotify = 5353; - public static final int ChooseCurAvatarTeamReq = 1800; - public static final int ChooseCurAvatarTeamRsp = 1673; - public static final int CityReputationDataNotify = 2898; - public static final int CityReputationLevelupNotify = 2832; - public static final int ClearRoguelikeCurseNotify = 8291; - public static final int ClientAbilitiesInitFinishCombineNotify = 1185; - public static final int ClientAbilityChangeNotify = 1127; - public static final int ClientAbilityInitBeginNotify = 1141; - public static final int ClientAbilityInitFinishNotify = 1137; - public static final int ClientAIStateNotify = 1197; - public static final int ClientBulletCreateNotify = 6; + public static final int BuyResinRsp = 619; + public static final int CalcWeaponUpgradeReturnItemsReq = 633; + public static final int CalcWeaponUpgradeReturnItemsRsp = 684; + public static final int CanUseSkillNotify = 1005; + public static final int CancelCityReputationRequestReq = 2899; + public static final int CancelCityReputationRequestRsp = 2831; + public static final int CancelCoopTaskReq = 1997; + public static final int CancelCoopTaskRsp = 1987; + public static final int CancelFinishParentQuestNotify = 424; + public static final int CardProductRewardNotify = 4107; + public static final int ChallengeDataNotify = 953; + public static final int ChallengeRecordNotify = 993; + public static final int ChangeAvatarReq = 1640; + public static final int ChangeAvatarRsp = 1607; + public static final int ChangeGameTimeReq = 173; + public static final int ChangeGameTimeRsp = 199; + public static final int ChangeMailStarNotify = 1448; + public static final int ChangeMpTeamAvatarReq = 1708; + public static final int ChangeMpTeamAvatarRsp = 1753; + public static final int ChangeServerGlobalValueNotify = 27; + public static final int ChangeTeamNameReq = 1603; + public static final int ChangeTeamNameRsp = 1666; + public static final int ChangeWorldToSingleModeNotify = 3006; + public static final int ChangeWorldToSingleModeReq = 3066; + public static final int ChangeWorldToSingleModeRsp = 3282; + public static final int ChannelerSlabCheckEnterLoopDungeonReq = 8745; + public static final int ChannelerSlabCheckEnterLoopDungeonRsp = 8452; + public static final int ChannelerSlabEnterLoopDungeonReq = 8869; + public static final int ChannelerSlabEnterLoopDungeonRsp = 8081; + public static final int ChannelerSlabLoopDungeonChallengeInfoNotify = 8224; + public static final int ChannelerSlabLoopDungeonSelectConditionReq = 8503; + public static final int ChannelerSlabLoopDungeonSelectConditionRsp = 8509; + public static final int ChannelerSlabLoopDungeonTakeFirstPassRewardReq = 8589; + public static final int ChannelerSlabLoopDungeonTakeFirstPassRewardRsp = 8539; + public static final int ChannelerSlabLoopDungeonTakeScoreRewardReq = 8684; + public static final int ChannelerSlabLoopDungeonTakeScoreRewardRsp = 8433; + public static final int ChannelerSlabOneOffDungeonInfoNotify = 8729; + public static final int ChannelerSlabOneOffDungeonInfoReq = 8409; + public static final int ChannelerSlabOneOffDungeonInfoRsp = 8268; + public static final int ChannelerSlabSaveAssistInfoReq = 8416; + public static final int ChannelerSlabSaveAssistInfoRsp = 8932; + public static final int ChannelerSlabStageActiveChallengeIndexNotify = 8734; + public static final int ChannelerSlabStageOneofDungeonNotify = 8203; + public static final int ChannelerSlabTakeoffBuffReq = 8516; + public static final int ChannelerSlabTakeoffBuffRsp = 8237; + public static final int ChannelerSlabWearBuffReq = 8107; + public static final int ChannelerSlabWearBuffRsp = 8600; + public static final int ChapterStateNotify = 405; + public static final int ChatChannelDataNotify = 4998; + public static final int ChatChannelUpdateNotify = 5025; + public static final int ChatHistoryNotify = 3496; + public static final int CheckAddItemExceedLimitNotify = 692; + public static final int CheckSegmentCRCNotify = 39; + public static final int CheckSegmentCRCReq = 53; + public static final int ChessEscapedMonstersNotify = 5314; + public static final int ChessLeftMonstersNotify = 5360; + public static final int ChessManualRefreshCardsReq = 5389; + public static final int ChessManualRefreshCardsRsp = 5359; + public static final int ChessPickCardNotify = 5380; + public static final int ChessPickCardReq = 5333; + public static final int ChessPickCardRsp = 5384; + public static final int ChessPlayerInfoNotify = 5332; + public static final int ChessSelectedCardsNotify = 5392; + public static final int ChooseCurAvatarTeamReq = 1796; + public static final int ChooseCurAvatarTeamRsp = 1661; + public static final int CityReputationDataNotify = 2805; + public static final int CityReputationLevelupNotify = 2807; + public static final int ClearRoguelikeCurseNotify = 8207; + public static final int ClientAIStateNotify = 1181; + public static final int ClientAbilitiesInitFinishCombineNotify = 1103; + public static final int ClientAbilityChangeNotify = 1175; + public static final int ClientAbilityInitBeginNotify = 1112; + public static final int ClientAbilityInitFinishNotify = 1135; + public static final int ClientBulletCreateNotify = 4; public static final int ClientCollectorDataNotify = 4264; - public static final int ClientHashDebugNotify = 3192; - public static final int ClientLoadingCostumeVerificationNotify = 3488; - public static final int ClientLockGameTimeNotify = 174; - public static final int ClientNewMailNotify = 1482; - public static final int ClientPauseNotify = 291; - public static final int ClientReconnectNotify = 27; - public static final int ClientReportNotify = 97; - public static final int ClientScriptEventNotify = 214; - public static final int ClientTransmitReq = 272; - public static final int ClientTransmitRsp = 259; - public static final int ClientTriggerEventNotify = 107; - public static final int CloseCommonTipsNotify = 3496; - public static final int ClosedItemNotify = 674; - public static final int CodexDataFullNotify = 4201; - public static final int CodexDataUpdateNotify = 4210; - public static final int CombatInvocationsNotify = 316; - public static final int CombineDataNotify = 661; - public static final int CombineFormulaDataNotify = 688; - public static final int CombineReq = 654; - public static final int CombineRsp = 646; - public static final int CommonPlayerTipsNotify = 8490; - public static final int CompoundDataNotify = 136; - public static final int CompoundUnlockNotify = 181; - public static final int CookDataNotify = 142; - public static final int CookGradeDataNotify = 111; - public static final int CookRecipeDataNotify = 101; - public static final int CoopCgShowNotify = 1989; - public static final int CoopCgUpdateNotify = 1966; - public static final int CoopChapterUpdateNotify = 1997; - public static final int CoopDataNotify = 1976; - public static final int CoopPointUpdateNotify = 1987; - public static final int CoopProgressUpdateNotify = 1961; - public static final int CoopRewardUpdateNotify = 1951; - public static final int CreateMassiveEntityNotify = 325; - public static final int CreateMassiveEntityReq = 370; - public static final int CreateMassiveEntityRsp = 329; - public static final int CreateVehicleReq = 819; - public static final int CreateVehicleRsp = 812; - public static final int CutSceneBeginNotify = 300; - public static final int CutSceneEndNotify = 299; - public static final int CutSceneFinishNotify = 294; - public static final int DailyTaskDataNotify = 183; - public static final int DailyTaskFilterCityReq = 192; - public static final int DailyTaskFilterCityRsp = 118; - public static final int DailyTaskProgressNotify = 103; - public static final int DailyTaskScoreRewardNotify = 134; - public static final int DailyTaskUnlockedCitiesNotify = 121; - public static final int DataResVersionNotify = 125; - public static final int DealAddFriendReq = 4085; - public static final int DealAddFriendRsp = 4035; + public static final int ClientHashDebugNotify = 3086; + public static final int ClientLoadingCostumeVerificationNotify = 3487; + public static final int ClientLockGameTimeNotify = 114; + public static final int ClientNewMailNotify = 1499; + public static final int ClientPauseNotify = 260; + public static final int ClientReconnectNotify = 75; + public static final int ClientReportNotify = 81; + public static final int ClientScriptEventNotify = 213; + public static final int ClientTransmitReq = 291; + public static final int ClientTransmitRsp = 224; + public static final int ClientTriggerEventNotify = 148; + public static final int CloseCommonTipsNotify = 3194; + public static final int ClosedItemNotify = 614; + public static final int CodexDataFullNotify = 4205; + public static final int CodexDataUpdateNotify = 4207; + public static final int CombatInvocationsNotify = 319; + public static final int CombineDataNotify = 659; + public static final int CombineFormulaDataNotify = 632; + public static final int CombineReq = 643; + public static final int CombineRsp = 674; + public static final int CommonPlayerTipsNotify = 8466; + public static final int CompoundDataNotify = 146; + public static final int CompoundUnlockNotify = 128; + public static final int CookDataNotify = 195; + public static final int CookGradeDataNotify = 134; + public static final int CookRecipeDataNotify = 106; + public static final int CoopCgShowNotify = 1983; + public static final int CoopCgUpdateNotify = 1994; + public static final int CoopChapterUpdateNotify = 1972; + public static final int CoopDataNotify = 1979; + public static final int CoopPointUpdateNotify = 1991; + public static final int CoopProgressUpdateNotify = 1998; + public static final int CoopRewardUpdateNotify = 1999; + public static final int CreateMassiveEntityNotify = 367; + public static final int CreateMassiveEntityReq = 342; + public static final int CreateMassiveEntityRsp = 330; + public static final int CreateVehicleReq = 893; + public static final int CreateVehicleRsp = 827; + public static final int CutSceneBeginNotify = 296; + public static final int CutSceneEndNotify = 215; + public static final int CutSceneFinishNotify = 262; + public static final int DailyTaskDataNotify = 158; + public static final int DailyTaskFilterCityReq = 111; + public static final int DailyTaskFilterCityRsp = 144; + public static final int DailyTaskProgressNotify = 170; + public static final int DailyTaskScoreRewardNotify = 117; + public static final int DailyTaskUnlockedCitiesNotify = 186; + public static final int DataResVersionNotify = 167; + public static final int DealAddFriendReq = 4003; + public static final int DealAddFriendRsp = 4090; public static final int DebugNotify = 101; - public static final int DeleteFriendNotify = 4063; - public static final int DeleteFriendReq = 4055; - public static final int DeleteFriendRsp = 4027; - public static final int DelMailReq = 1417; - public static final int DelMailRsp = 1485; - public static final int DelScenePlayTeamEntityNotify = 3087; + public static final int DelMailReq = 1421; + public static final int DelMailRsp = 1403; + public static final int DelScenePlayTeamEntityNotify = 3318; public static final int DelTeamEntityNotify = 302; - public static final int DestroyMassiveEntityNotify = 383; - public static final int DestroyMaterialReq = 678; - public static final int DestroyMaterialRsp = 608; - public static final int DigActivityChangeGadgetStateReq = 8155; - public static final int DigActivityChangeGadgetStateRsp = 8851; - public static final int DigActivityMarkPointChangeNotify = 8679; - public static final int DisableRoguelikeTrapNotify = 8250; - public static final int DoGachaReq = 1541; - public static final int DoGachaRsp = 1537; - public static final int DoRoguelikeDungeonCardGachaReq = 8764; - public static final int DoRoguelikeDungeonCardGachaRsp = 8641; - public static final int DoSetPlayerBornDataNotify = 190; - public static final int DraftGuestReplyInviteNotify = 5435; - public static final int DraftGuestReplyInviteReq = 5417; - public static final int DraftGuestReplyInviteRsp = 5485; - public static final int DraftGuestReplyTwiceConfirmNotify = 5430; - public static final int DraftGuestReplyTwiceConfirmReq = 5455; - public static final int DraftGuestReplyTwiceConfirmRsp = 5427; - public static final int DraftInviteResultNotify = 5449; - public static final int DraftOwnerInviteNotify = 5432; - public static final int DraftOwnerStartInviteReq = 5441; - public static final int DraftOwnerStartInviteRsp = 5437; - public static final int DraftOwnerTwiceConfirmNotify = 5482; - public static final int DraftTwiceConfirmResultNotify = 5407; - public static final int DragonSpineChapterFinishNotify = 2135; - public static final int DragonSpineChapterOpenNotify = 2119; - public static final int DragonSpineChapterProgressChangeNotify = 2102; - public static final int DragonSpineCoinChangeNotify = 2031; - public static final int DropHintNotify = 622; - public static final int DropItemReq = 682; - public static final int DropItemRsp = 655; - public static final int DungeonCandidateTeamChangeAvatarReq = 984; - public static final int DungeonCandidateTeamChangeAvatarRsp = 970; - public static final int DungeonCandidateTeamCreateReq = 942; - public static final int DungeonCandidateTeamCreateRsp = 901; - public static final int DungeonCandidateTeamDismissNotify = 913; - public static final int DungeonCandidateTeamInfoNotify = 912; - public static final int DungeonCandidateTeamInviteNotify = 958; - public static final int DungeonCandidateTeamInviteReq = 911; - public static final int DungeonCandidateTeamInviteRsp = 922; - public static final int DungeonCandidateTeamKickReq = 954; - public static final int DungeonCandidateTeamKickRsp = 946; - public static final int DungeonCandidateTeamLeaveReq = 933; - public static final int DungeonCandidateTeamLeaveRsp = 936; - public static final int DungeonCandidateTeamPlayerLeaveNotify = 920; - public static final int DungeonCandidateTeamRefuseNotify = 950; - public static final int DungeonCandidateTeamReplyInviteReq = 928; - public static final int DungeonCandidateTeamReplyInviteRsp = 976; - public static final int DungeonCandidateTeamSetChangingAvatarReq = 908; - public static final int DungeonCandidateTeamSetChangingAvatarRsp = 904; - public static final int DungeonCandidateTeamSetReadyReq = 972; - public static final int DungeonCandidateTeamSetReadyRsp = 959; - public static final int DungeonChallengeBeginNotify = 990; - public static final int DungeonChallengeFinishNotify = 986; - public static final int DungeonDataNotify = 945; - public static final int DungeonDieOptionReq = 927; - public static final int DungeonDieOptionRsp = 907; - public static final int DungeonEntryInfoReq = 909; - public static final int DungeonEntryInfoRsp = 931; - public static final int DungeonEntryToBeExploreNotify = 3414; - public static final int DungeonFollowNotify = 924; - public static final int DungeonGetStatueDropReq = 938; - public static final int DungeonGetStatueDropRsp = 906; - public static final int DungeonInterruptChallengeReq = 934; + public static final int DeleteFriendNotify = 4053; + public static final int DeleteFriendReq = 4031; + public static final int DeleteFriendRsp = 4075; + public static final int DestroyMassiveEntityNotify = 358; + public static final int DestroyMaterialReq = 640; + public static final int DestroyMaterialRsp = 618; + public static final int DigActivityChangeGadgetStateReq = 8464; + public static final int DigActivityChangeGadgetStateRsp = 8430; + public static final int DigActivityMarkPointChangeNotify = 8109; + public static final int DisableRoguelikeTrapNotify = 8259; + public static final int DoGachaReq = 1512; + public static final int DoGachaRsp = 1535; + public static final int DoRoguelikeDungeonCardGachaReq = 8148; + public static final int DoRoguelikeDungeonCardGachaRsp = 8472; + public static final int DoSetPlayerBornDataNotify = 147; + public static final int DraftGuestReplyInviteNotify = 5490; + public static final int DraftGuestReplyInviteReq = 5421; + public static final int DraftGuestReplyInviteRsp = 5403; + public static final int DraftGuestReplyTwiceConfirmNotify = 5497; + public static final int DraftGuestReplyTwiceConfirmReq = 5431; + public static final int DraftGuestReplyTwiceConfirmRsp = 5475; + public static final int DraftInviteResultNotify = 5473; + public static final int DraftOwnerInviteNotify = 5407; + public static final int DraftOwnerStartInviteReq = 5412; + public static final int DraftOwnerStartInviteRsp = 5435; + public static final int DraftOwnerTwiceConfirmNotify = 5499; + public static final int DraftTwiceConfirmResultNotify = 5448; + public static final int DragonSpineChapterFinishNotify = 2069; + public static final int DragonSpineChapterOpenNotify = 2022; + public static final int DragonSpineChapterProgressChangeNotify = 2065; + public static final int DragonSpineCoinChangeNotify = 2088; + public static final int DropHintNotify = 650; + public static final int DropItemReq = 699; + public static final int DropItemRsp = 631; + public static final int DungeonCandidateTeamChangeAvatarReq = 956; + public static final int DungeonCandidateTeamChangeAvatarRsp = 942; + public static final int DungeonCandidateTeamCreateReq = 995; + public static final int DungeonCandidateTeamCreateRsp = 906; + public static final int DungeonCandidateTeamDismissNotify = 963; + public static final int DungeonCandidateTeamInfoNotify = 927; + public static final int DungeonCandidateTeamInviteNotify = 994; + public static final int DungeonCandidateTeamInviteReq = 934; + public static final int DungeonCandidateTeamInviteRsp = 950; + public static final int DungeonCandidateTeamKickReq = 943; + public static final int DungeonCandidateTeamKickRsp = 974; + public static final int DungeonCandidateTeamLeaveReq = 976; + public static final int DungeonCandidateTeamLeaveRsp = 946; + public static final int DungeonCandidateTeamPlayerLeaveNotify = 926; + public static final int DungeonCandidateTeamRefuseNotify = 988; + public static final int DungeonCandidateTeamReplyInviteReq = 941; + public static final int DungeonCandidateTeamReplyInviteRsp = 949; + public static final int DungeonCandidateTeamSetChangingAvatarReq = 918; + public static final int DungeonCandidateTeamSetChangingAvatarRsp = 966; + public static final int DungeonCandidateTeamSetReadyReq = 991; + public static final int DungeonCandidateTeamSetReadyRsp = 924; + public static final int DungeonChallengeBeginNotify = 947; + public static final int DungeonChallengeFinishNotify = 939; + public static final int DungeonDataNotify = 982; + public static final int DungeonDieOptionReq = 975; + public static final int DungeonDieOptionRsp = 948; + public static final int DungeonEntryInfoReq = 972; + public static final int DungeonEntryInfoRsp = 998; + public static final int DungeonEntryToBeExploreNotify = 3147; + public static final int DungeonFollowNotify = 922; + public static final int DungeonGetStatueDropReq = 965; + public static final int DungeonGetStatueDropRsp = 904; + public static final int DungeonInterruptChallengeReq = 917; public static final int DungeonInterruptChallengeRsp = 902; - public static final int DungeonPlayerDieNotify = 955; - public static final int DungeonPlayerDieReq = 997; - public static final int DungeonPlayerDieRsp = 998; - public static final int DungeonRestartInviteNotify = 977; - public static final int DungeonRestartInviteReplyNotify = 989; - public static final int DungeonRestartInviteReplyReq = 943; - public static final int DungeonRestartInviteReplyRsp = 987; - public static final int DungeonRestartReq = 993; - public static final int DungeonRestartResultNotify = 978; - public static final int DungeonRestartRsp = 960; - public static final int DungeonReviseLevelNotify = 905; - public static final int DungeonSettleNotify = 982; - public static final int DungeonShowReminderNotify = 930; - public static final int DungeonSlipRevivePointActivateReq = 983; - public static final int DungeonSlipRevivePointActivateRsp = 903; - public static final int DungeonWayPointActivateReq = 935; - public static final int DungeonWayPointActivateRsp = 949; - public static final int DungeonWayPointNotify = 985; - public static final int EchoNotify = 38; - public static final int EchoShellTakeRewardReq = 8074; - public static final int EchoShellTakeRewardRsp = 8446; - public static final int EchoShellUpdateNotify = 8077; - public static final int EffigyChallengeInfoNotify = 2153; - public static final int EffigyChallengeResultNotify = 2064; - public static final int EndCameraSceneLookNotify = 234; - public static final int EnterChessDungeonReq = 8571; - public static final int EnterChessDungeonRsp = 8819; - public static final int EnterFishingReq = 5818; - public static final int EnterFishingRsp = 5809; - public static final int EnterMechanicusDungeonReq = 3955; - public static final int EnterMechanicusDungeonRsp = 3927; - public static final int EnterRoguelikeDungeonNotify = 8646; - public static final int EnterSceneDoneReq = 279; - public static final int EnterSceneDoneRsp = 269; - public static final int EnterScenePeerNotify = 257; - public static final int EnterSceneReadyReq = 244; - public static final int EnterSceneReadyRsp = 252; - public static final int EnterSceneWeatherAreaNotify = 284; - public static final int EnterTransPointRegionNotify = 298; - public static final int EnterTrialAvatarActivityDungeonReq = 2057; - public static final int EnterTrialAvatarActivityDungeonRsp = 2021; - public static final int EnterWorldAreaReq = 222; - public static final int EnterWorldAreaRsp = 254; - public static final int EntityAiKillSelfNotify = 378; - public static final int EntityAiSyncNotify = 343; - public static final int EntityAuthorityChangeNotify = 358; - public static final int EntityConfigHashNotify = 3271; - public static final int EntityFightPropChangeReasonNotify = 1285; - public static final int EntityFightPropNotify = 1241; - public static final int EntityFightPropUpdateNotify = 1237; - public static final int EntityForceSyncReq = 246; - public static final int EntityForceSyncRsp = 233; - public static final int EntityJumpNotify = 224; - public static final int EntityMoveRoomNotify = 3209; - public static final int EntityPropNotify = 1209; - public static final int EntityTagChangeNotify = 3273; - public static final int EquipRoguelikeRuneReq = 8510; - public static final int EquipRoguelikeRuneRsp = 8516; - public static final int EvtAiSyncCombatThreatInfoNotify = 360; - public static final int EvtAiSyncSkillCdNotify = 333; - public static final int EvtAnimatorParameterNotify = 331; - public static final int EvtAnimatorStateChangedNotify = 355; - public static final int EvtAvatarEnterFocusNotify = 306; - public static final int EvtAvatarExitFocusNotify = 319; - public static final int EvtAvatarLockChairReq = 308; - public static final int EvtAvatarLockChairRsp = 304; - public static final int EvtAvatarSitDownNotify = 359; - public static final int EvtAvatarStandUpNotify = 384; - public static final int EvtAvatarUpdateFocusNotify = 312; - public static final int EvtBeingHitNotify = 309; - public static final int EvtBeingHitsCombineNotify = 336; - public static final int EvtBulletDeactiveNotify = 330; - public static final int EvtBulletHitNotify = 307; - public static final int EvtBulletMoveNotify = 338; - public static final int EvtCostStaminaNotify = 349; - public static final int EvtCreateGadgetNotify = 332; - public static final int EvtDestroyGadgetNotify = 317; - public static final int EvtDestroyServerGadgetNotify = 389; - public static final int EvtDoSkillSuccNotify = 337; - public static final int EvtEntityRenderersChangedNotify = 354; - public static final int EvtEntityStartDieEndNotify = 397; - public static final int EvtFaceToDirNotify = 335; - public static final int EvtFaceToEntityNotify = 385; - public static final int EvtRushMoveNotify = 327; - public static final int EvtSetAttackTargetNotify = 382; - public static final int ExclusiveRuleNotify = 123; - public static final int ExecuteGadgetLuaReq = 267; - public static final int ExecuteGadgetLuaRsp = 271; - public static final int ExecuteGroupTriggerReq = 277; - public static final int ExecuteGroupTriggerRsp = 243; + public static final int DungeonPlayerDieNotify = 931; + public static final int DungeonPlayerDieReq = 981; + public static final int DungeonPlayerDieRsp = 905; + public static final int DungeonRestartInviteNotify = 957; + public static final int DungeonRestartInviteReplyNotify = 987; + public static final int DungeonRestartInviteReplyReq = 1000; + public static final int DungeonRestartInviteReplyRsp = 916; + public static final int DungeonRestartReq = 961; + public static final int DungeonRestartResultNotify = 940; + public static final int DungeonRestartRsp = 929; + public static final int DungeonReviseLevelNotify = 968; + public static final int DungeonSettleNotify = 999; + public static final int DungeonShowReminderNotify = 997; + public static final int DungeonSlipRevivePointActivateReq = 958; + public static final int DungeonSlipRevivePointActivateRsp = 970; + public static final int DungeonWayPointActivateReq = 990; + public static final int DungeonWayPointActivateRsp = 973; + public static final int DungeonWayPointNotify = 903; + public static final int EchoNotify = 65; + public static final int EchoShellTakeRewardReq = 8114; + public static final int EchoShellTakeRewardRsp = 8797; + public static final int EchoShellUpdateNotify = 8150; + public static final int EffigyChallengeInfoNotify = 2090; + public static final int EffigyChallengeResultNotify = 2046; + public static final int EndCameraSceneLookNotify = 217; + public static final int EnterChessDungeonReq = 8191; + public static final int EnterChessDungeonRsp = 8592; + public static final int EnterFishingReq = 5826; + public static final int EnterFishingRsp = 5818; + public static final int EnterMechanicusDungeonReq = 3931; + public static final int EnterMechanicusDungeonRsp = 3975; + public static final int EnterRoguelikeDungeonNotify = 8652; + public static final int EnterSceneDoneReq = 277; + public static final int EnterSceneDoneRsp = 237; + public static final int EnterScenePeerNotify = 252; + public static final int EnterSceneReadyReq = 208; + public static final int EnterSceneReadyRsp = 209; + public static final int EnterSceneWeatherAreaNotify = 256; + public static final int EnterTransPointRegionNotify = 205; + public static final int EnterTrialAvatarActivityDungeonReq = 2118; + public static final int EnterTrialAvatarActivityDungeonRsp = 2183; + public static final int EnterWorldAreaReq = 250; + public static final int EnterWorldAreaRsp = 243; + public static final int EntityAiKillSelfNotify = 340; + public static final int EntityAiSyncNotify = 400; + public static final int EntityAuthorityChangeNotify = 394; + public static final int EntityConfigHashNotify = 3189; + public static final int EntityFightPropChangeReasonNotify = 1203; + public static final int EntityFightPropNotify = 1212; + public static final int EntityFightPropUpdateNotify = 1235; + public static final int EntityForceSyncReq = 274; + public static final int EntityForceSyncRsp = 276; + public static final int EntityJumpNotify = 222; + public static final int EntityMoveRoomNotify = 3178; + public static final int EntityPropNotify = 1272; + public static final int EntityTagChangeNotify = 3316; + public static final int EquipRoguelikeRuneReq = 8306; + public static final int EquipRoguelikeRuneRsp = 8705; + public static final int EvtAiSyncCombatThreatInfoNotify = 329; + public static final int EvtAiSyncSkillCdNotify = 376; + public static final int EvtAnimatorParameterNotify = 398; + public static final int EvtAnimatorStateChangedNotify = 331; + public static final int EvtAvatarEnterFocusNotify = 304; + public static final int EvtAvatarExitFocusNotify = 393; + public static final int EvtAvatarLockChairReq = 318; + public static final int EvtAvatarLockChairRsp = 366; + public static final int EvtAvatarSitDownNotify = 324; + public static final int EvtAvatarStandUpNotify = 356; + public static final int EvtAvatarUpdateFocusNotify = 327; + public static final int EvtBeingHitNotify = 372; + public static final int EvtBeingHitsCombineNotify = 346; + public static final int EvtBulletDeactiveNotify = 397; + public static final int EvtBulletHitNotify = 348; + public static final int EvtBulletMoveNotify = 365; + public static final int EvtCostStaminaNotify = 373; + public static final int EvtCreateGadgetNotify = 307; + public static final int EvtDestroyGadgetNotify = 321; + public static final int EvtDestroyServerGadgetNotify = 387; + public static final int EvtDoSkillSuccNotify = 335; + public static final int EvtEntityRenderersChangedNotify = 343; + public static final int EvtEntityStartDieEndNotify = 381; + public static final int EvtFaceToDirNotify = 390; + public static final int EvtFaceToEntityNotify = 303; + public static final int EvtRushMoveNotify = 375; + public static final int EvtSetAttackTargetNotify = 399; + public static final int ExclusiveRuleNotify = 101; + public static final int ExecuteGadgetLuaReq = 269; + public static final int ExecuteGadgetLuaRsp = 210; + public static final int ExecuteGroupTriggerReq = 257; + public static final int ExecuteGroupTriggerRsp = 300; public static final int ExitFishingReq = 5814; - public static final int ExitFishingRsp = 5812; - public static final int ExitSceneWeatherAreaNotify = 270; - public static final int ExitTransPointRegionNotify = 245; - public static final int ExpeditionChallengeEnterRegionNotify = 2050; - public static final int ExpeditionChallengeFinishedNotify = 2034; - public static final int ExpeditionRecallReq = 2122; - public static final int ExpeditionRecallRsp = 2156; - public static final int ExpeditionStartReq = 2026; - public static final int ExpeditionStartRsp = 2163; - public static final int ExpeditionTakeRewardReq = 2173; - public static final int ExpeditionTakeRewardRsp = 2196; - public static final int FindHilichurlAcceptQuestNotify = 8465; - public static final int FindHilichurlFinishSecondQuestNotify = 8981; - public static final int FinishDeliveryNotify = 2158; - public static final int FinishedParentQuestNotify = 437; - public static final int FinishedParentQuestUpdateNotify = 432; - public static final int FinishMainCoopReq = 1978; - public static final int FinishMainCoopRsp = 1953; + public static final int ExitFishingRsp = 5847; + public static final int ExitSceneWeatherAreaNotify = 242; + public static final int ExitTransPointRegionNotify = 282; + public static final int ExpeditionChallengeEnterRegionNotify = 2154; + public static final int ExpeditionChallengeFinishedNotify = 2091; + public static final int ExpeditionRecallReq = 2131; + public static final int ExpeditionRecallRsp = 2129; + public static final int ExpeditionStartReq = 2087; + public static final int ExpeditionStartRsp = 2135; + public static final int ExpeditionTakeRewardReq = 2149; + public static final int ExpeditionTakeRewardRsp = 2080; + public static final int FindHilichurlAcceptQuestNotify = 8659; + public static final int FindHilichurlFinishSecondQuestNotify = 8901; + public static final int FinishDeliveryNotify = 2089; + public static final int FinishMainCoopReq = 1952; + public static final int FinishMainCoopRsp = 1981; + public static final int FinishedParentQuestNotify = 435; + public static final int FinishedParentQuestUpdateNotify = 407; + public static final int FireworkNotify = 5934; public static final int FireworkReq = 6068; - public static final int FireworkNotify = 6079; public static final int FireworkRsp = 5918; + public static final int FireworkSetNotify = 6079; public static final int FireworkSetReq = 6099; - public static final int FireworkSetNotify = 5934; public static final int FireworkSetRsp = 5969; - public static final int FishAttractNotify = 5846; - public static final int FishBaitGoneNotify = 5827; - public static final int FishBattleBeginReq = 5802; - public static final int FishBattleBeginRsp = 5813; - public static final int FishBattleEndReq = 5837; - public static final int FishBattleEndRsp = 5832; - public static final int FishBiteReq = 5816; - public static final int FishBiteRsp = 5801; - public static final int FishCastRodReq = 5828; - public static final int FishCastRodRsp = 5803; - public static final int FishChosenNotify = 5826; - public static final int FishEscapeNotify = 5847; - public static final int FishingGallerySettleNotify = 8896; - public static final int FishPoolDataNotify = 5811; - public static final int FleurFairBalloonSettleNotify = 2139; - public static final int FleurFairBuffEnergyNotify = 5359; - public static final int FleurFairFallSettleNotify = 2097; - public static final int FleurFairFinishGalleryStageNotify = 5370; - public static final int FleurFairMusicGameSettleReq = 2115; - public static final int FleurFairMusicGameSettleRsp = 2124; - public static final int FleurFairMusicGameStartReq = 2171; - public static final int FleurFairMusicGameStartRsp = 2149; - public static final int FleurFairReplayMiniGameReq = 2152; - public static final int FleurFairReplayMiniGameRsp = 2101; - public static final int FleurFairStageSettleNotify = 5384; - public static final int FlightActivityRestartReq = 2164; - public static final int FlightActivityRestartRsp = 2002; - public static final int FlightActivitySettleNotify = 2084; - public static final int FocusAvatarReq = 1652; - public static final int FocusAvatarRsp = 1612; - public static final int ForceAddPlayerFriendReq = 4077; - public static final int ForceAddPlayerFriendRsp = 4043; - public static final int ForceDragAvatarNotify = 3425; - public static final int ForceDragBackTransferNotify = 3088; - public static final int ForgeDataNotify = 648; - public static final int ForgeFormulaDataNotify = 673; - public static final int ForgeGetQueueDataReq = 636; - public static final int ForgeGetQueueDataRsp = 628; - public static final int ForgeQueueDataNotify = 633; - public static final int ForgeQueueManipulateReq = 659; - public static final int ForgeQueueManipulateRsp = 684; - public static final int ForgeStartReq = 676; - public static final int ForgeStartRsp = 672; - public static final int FoundationNotify = 890; - public static final int FoundationReq = 898; - public static final int FoundationRsp = 845; - public static final int FriendInfoChangeNotify = 4088; - public static final int FunitureMakeMakeInfoChangeNotify = 4488; - public static final int FurnitureCurModuleArrangeCountNotify = 4681; - public static final int FurnitureMakeBeHelpedNotify = 4626; - public static final int FurnitureMakeCancelReq = 4834; - public static final int FurnitureMakeCancelRsp = 4660; - public static final int FurnitureMakeFinishNotify = 4557; - public static final int FurnitureMakeHelpReq = 4580; - public static final int FurnitureMakeHelpRsp = 4722; - public static final int FurnitureMakeReq = 4551; - public static final int FurnitureMakeRsp = 4530; - public static final int FurnitureMakeStartReq = 4582; - public static final int FurnitureMakeStartRsp = 4463; - public static final int GachaOpenWishNotify = 1585; - public static final int GachaSimpleInfoNotify = 1535; - public static final int GachaWishReq = 1532; - public static final int GachaWishRsp = 1517; - public static final int GadgetAutoPickDropInfoNotify = 830; - public static final int GadgetChainLevelChangeNotify = 824; - public static final int GadgetChainLevelUpdateNotify = 863; - public static final int GadgetCustomTreeInfoNotify = 822; - public static final int GadgetGeneralRewardInfoNotify = 807; - public static final int GadgetInteractReq = 809; - public static final int GadgetInteractRsp = 831; - public static final int GadgetPlayDataNotify = 855; - public static final int GadgetPlayStartNotify = 849; - public static final int GadgetPlayStopNotify = 882; - public static final int GadgetPlayUidOpNotify = 827; - public static final int GadgetStateNotify = 841; - public static final int GadgetTalkChangeNotify = 886; - public static final int GalleryBalloonScoreNotify = 5541; - public static final int GalleryBalloonShootNotify = 5531; - public static final int GalleryBounceConjuringHitNotify = 5598; - public static final int GalleryBrokenFloorFallNotify = 5527; - public static final int GalleryBulletHitNotify = 5555; - public static final int GalleryFallCatchNotify = 5532; - public static final int GalleryFallScoreNotify = 5517; - public static final int GalleryFlowerCatchNotify = 5549; - public static final int GalleryPreStartNotify = 5582; - public static final int GalleryStartNotify = 5509; - public static final int GalleryStopNotify = 5537; - public static final int GallerySumoKillMonsterNotify = 5545; - public static final int GetActivityInfoReq = 2067; - public static final int GetActivityInfoRsp = 2144; - public static final int GetActivityScheduleReq = 2049; - public static final int GetActivityScheduleRsp = 2044; - public static final int GetActivityShopSheetInfoReq = 785; - public static final int GetActivityShopSheetInfoRsp = 735; - public static final int GetAllActivatedBargainDataReq = 413; - public static final int GetAllActivatedBargainDataRsp = 442; - public static final int GetAllH5ActivityInfoReq = 5659; - public static final int GetAllH5ActivityInfoRsp = 5668; - public static final int GetAllMailReq = 1455; - public static final int GetAllMailRsp = 1427; - public static final int GetAllSceneGalleryInfoReq = 5585; - public static final int GetAllSceneGalleryInfoRsp = 5535; - public static final int GetAllUnlockNameCardReq = 4012; - public static final int GetAllUnlockNameCardRsp = 4058; - public static final int GetAreaExplorePointReq = 228; - public static final int GetAreaExplorePointRsp = 276; - public static final int GetAuthkeyReq = 1435; - public static final int GetAuthkeyRsp = 1449; - public static final int GetAuthSalesmanInfoReq = 2161; - public static final int GetAuthSalesmanInfoRsp = 2039; - public static final int GetBargainDataReq = 450; - public static final int GetBargainDataRsp = 420; - public static final int GetBattlePassProductReq = 2616; - public static final int GetBattlePassProductRsp = 2601; - public static final int GetBlossomBriefInfoListReq = 2709; - public static final int GetBlossomBriefInfoListRsp = 2731; - public static final int GetBonusActivityRewardReq = 2597; - public static final int GetBonusActivityRewardRsp = 2598; - public static final int GetChatEmojiCollectionReq = 4005; - public static final int GetChatEmojiCollectionRsp = 4010; - public static final int GetCityHuntingOfferReq = 4343; - public static final int GetCityHuntingOfferRsp = 4304; - public static final int GetCityReputationInfoReq = 2809; - public static final int GetCityReputationInfoRsp = 2831; - public static final int GetCityReputationMapInfoReq = 2827; - public static final int GetCityReputationMapInfoRsp = 2807; - public static final int GetCompoundDataReq = 128; - public static final int GetCompoundDataRsp = 176; - public static final int GetDailyDungeonEntryInfoReq = 929; - public static final int GetDailyDungeonEntryInfoRsp = 925; - public static final int GetDungeonEntryExploreConditionReq = 3136; - public static final int GetDungeonEntryExploreConditionRsp = 3099; - public static final int GetExpeditionAssistInfoListReq = 2181; - public static final int GetExpeditionAssistInfoListRsp = 2045; - public static final int GetFriendShowAvatarInfoReq = 4003; - public static final int GetFriendShowAvatarInfoRsp = 4034; - public static final int GetFriendShowNameCardInfoReq = 4093; - public static final int GetFriendShowNameCardInfoRsp = 4060; - public static final int GetFurnitureCurModuleArrangeCountReq = 4603; - public static final int GetGachaInfoReq = 1509; - public static final int GetGachaInfoRsp = 1531; - public static final int GetHomeLevelUpRewardReq = 4747; - public static final int GetHomeLevelUpRewardRsp = 4517; - public static final int GetHuntingOfferRewardReq = 4328; - public static final int GetHuntingOfferRewardRsp = 4303; - public static final int GetInvestigationMonsterReq = 1902; - public static final int GetInvestigationMonsterRsp = 1911; - public static final int GetMailItemReq = 1437; - public static final int GetMailItemRsp = 1432; - public static final int GetMapAreaReq = 3466; - public static final int GetMapAreaRsp = 3012; - public static final int GetMapMarkTipsReq = 3329; - public static final int GetMapMarkTipsRsp = 3118; - public static final int GetMechanicusInfoReq = 3909; - public static final int GetMechanicusInfoRsp = 3931; - public static final int GetNextResourceInfoReq = 153; - public static final int GetNextResourceInfoRsp = 139; - public static final int GetOnlinePlayerInfoReq = 45; - public static final int GetOnlinePlayerInfoRsp = 90; - public static final int GetOnlinePlayerListReq = 35; - public static final int GetOnlinePlayerListRsp = 49; - public static final int GetOpActivityInfoReq = 5109; - public static final int GetOpActivityInfoRsp = 5131; - public static final int GetPlayerAskFriendListReq = 4008; - public static final int GetPlayerAskFriendListRsp = 4004; - public static final int GetPlayerBlacklistReq = 4076; - public static final int GetPlayerBlacklistRsp = 4072; - public static final int GetPlayerFriendListReq = 4009; - public static final int GetPlayerFriendListRsp = 4031; - public static final int GetPlayerHomeCompInfoReq = 4845; - public static final int GetPlayerMpModeAvailabilityReq = 1816; - public static final int GetPlayerMpModeAvailabilityRsp = 1801; - public static final int GetPlayerSocialDetailReq = 4049; - public static final int GetPlayerSocialDetailRsp = 4082; - public static final int GetPlayerTokenReq = 109; - public static final int GetPlayerTokenRsp = 131; - public static final int GetPushTipsRewardReq = 2212; - public static final int GetPushTipsRewardRsp = 2258; - public static final int GetQuestTalkHistoryReq = 435; - public static final int GetQuestTalkHistoryRsp = 449; - public static final int GetRecentMpPlayerListReq = 4011; - public static final int GetRecentMpPlayerListRsp = 4022; - public static final int GetRegionSearchReq = 5628; - public static final int GetReunionMissionInfoReq = 5066; - public static final int GetReunionMissionInfoRsp = 5051; - public static final int GetReunionPrivilegeInfoReq = 5062; - public static final int GetReunionPrivilegeInfoRsp = 5096; - public static final int GetReunionSignInInfoReq = 5078; - public static final int GetReunionSignInInfoRsp = 5053; - public static final int GetSceneAreaReq = 238; - public static final int GetSceneAreaRsp = 206; - public static final int GetSceneNpcPositionReq = 537; - public static final int GetSceneNpcPositionRsp = 532; - public static final int GetScenePerformanceReq = 3340; - public static final int GetScenePerformanceRsp = 3447; - public static final int GetScenePointReq = 230; - public static final int GetScenePointRsp = 297; - public static final int GetShopmallDataReq = 732; - public static final int GetShopmallDataRsp = 717; - public static final int GetShopReq = 709; - public static final int GetShopRsp = 731; - public static final int GetSignInRewardReq = 2532; - public static final int GetSignInRewardRsp = 2517; - public static final int GetWidgetSlotReq = 4267; - public static final int GetWidgetSlotRsp = 4300; - public static final int GetWorldMpInfoReq = 3264; - public static final int GetWorldMpInfoRsp = 3179; - public static final int GiveUpRoguelikeDungeonCardReq = 8977; - public static final int GiveUpRoguelikeDungeonCardRsp = 8583; - public static final int GivingRecordChangeNotify = 189; - public static final int GivingRecordNotify = 187; - public static final int GMShowNavMeshReq = 2377; - public static final int GMShowNavMeshRsp = 2343; - public static final int GMShowObstacleReq = 2393; - public static final int GMShowObstacleRsp = 2360; - public static final int GmTalkNotify = 58; - public static final int GmTalkReq = 31; - public static final int GmTalkRsp = 41; - public static final int GrantRewardNotify = 613; - public static final int GroupLinkAllNotify = 5768; - public static final int GroupLinkChangeNotify = 5759; - public static final int GroupLinkDeleteNotify = 5793; - public static final int GroupSuiteNotify = 3476; - public static final int GroupUnloadNotify = 3416; - public static final int GuestBeginEnterSceneNotify = 3125; - public static final int GuestPostEnterSceneNotify = 3379; - public static final int H5ActivityIdsNotify = 5693; + public static final int FishAttractNotify = 5837; + public static final int FishBaitGoneNotify = 5823; + public static final int FishBattleBeginReq = 5820; + public static final int FishBattleBeginRsp = 5845; + public static final int FishBattleEndReq = 5841; + public static final int FishBattleEndRsp = 5842; + public static final int FishBiteReq = 5844; + public static final int FishBiteRsp = 5849; + public static final int FishCastRodReq = 5802; + public static final int FishCastRodRsp = 5831; + public static final int FishChosenNotify = 5829; + public static final int FishEscapeNotify = 5822; + public static final int FishPoolDataNotify = 5848; + public static final int FishingGallerySettleNotify = 8780; + public static final int FleurFairBalloonSettleNotify = 2099; + public static final int FleurFairBuffEnergyNotify = 5324; + public static final int FleurFairFallSettleNotify = 2017; + public static final int FleurFairFinishGalleryStageNotify = 5342; + public static final int FleurFairMusicGameSettleReq = 2194; + public static final int FleurFairMusicGameSettleRsp = 2113; + public static final int FleurFairMusicGameStartReq = 2167; + public static final int FleurFairMusicGameStartRsp = 2079; + public static final int FleurFairReplayMiniGameReq = 2181; + public static final int FleurFairReplayMiniGameRsp = 2052; + public static final int FleurFairStageSettleNotify = 5356; + public static final int FlightActivityRestartReq = 2037; + public static final int FlightActivityRestartRsp = 2165; + public static final int FlightActivitySettleNotify = 2195; + public static final int FocusAvatarReq = 1654; + public static final int FocusAvatarRsp = 1681; + public static final int ForceAddPlayerFriendReq = 4057; + public static final int ForceAddPlayerFriendRsp = 4100; + public static final int ForceDragAvatarNotify = 3235; + public static final int ForceDragBackTransferNotify = 3145; + public static final int ForgeDataNotify = 680; + public static final int ForgeFormulaDataNotify = 689; + public static final int ForgeGetQueueDataReq = 646; + public static final int ForgeGetQueueDataRsp = 641; + public static final int ForgeQueueDataNotify = 676; + public static final int ForgeQueueManipulateReq = 624; + public static final int ForgeQueueManipulateRsp = 656; + public static final int ForgeStartReq = 649; + public static final int ForgeStartRsp = 691; + public static final int FoundationNotify = 847; + public static final int FoundationReq = 805; + public static final int FoundationRsp = 882; + public static final int FriendInfoChangeNotify = 4032; + public static final int FunitureMakeMakeInfoChangeNotify = 4898; + public static final int FurnitureCurModuleArrangeCountNotify = 4498; + public static final int FurnitureMakeBeHelpedNotify = 4578; + public static final int FurnitureMakeCancelReq = 4555; + public static final int FurnitureMakeCancelRsp = 4683; + public static final int FurnitureMakeFinishNotify = 4841; + public static final int FurnitureMakeHelpReq = 4865; + public static final int FurnitureMakeHelpRsp = 4756; + public static final int FurnitureMakeReq = 4477; + public static final int FurnitureMakeRsp = 4782; + public static final int FurnitureMakeStartReq = 4633; + public static final int FurnitureMakeStartRsp = 4729; + public static final int GMShowNavMeshReq = 2357; + public static final int GMShowNavMeshRsp = 2400; + public static final int GMShowObstacleReq = 2361; + public static final int GMShowObstacleRsp = 2329; + public static final int GachaOpenWishNotify = 1503; + public static final int GachaSimpleInfoNotify = 1590; + public static final int GachaWishReq = 1507; + public static final int GachaWishRsp = 1521; + public static final int GadgetAutoPickDropInfoNotify = 897; + public static final int GadgetChainLevelChangeNotify = 822; + public static final int GadgetChainLevelUpdateNotify = 853; + public static final int GadgetCustomTreeInfoNotify = 850; + public static final int GadgetGeneralRewardInfoNotify = 848; + public static final int GadgetInteractReq = 872; + public static final int GadgetInteractRsp = 898; + public static final int GadgetPlayDataNotify = 831; + public static final int GadgetPlayStartNotify = 873; + public static final int GadgetPlayStopNotify = 899; + public static final int GadgetPlayUidOpNotify = 875; + public static final int GadgetStateNotify = 812; + public static final int GadgetTalkChangeNotify = 839; + public static final int GalleryBalloonScoreNotify = 5512; + public static final int GalleryBalloonShootNotify = 5598; + public static final int GalleryBounceConjuringHitNotify = 5505; + public static final int GalleryBrokenFloorFallNotify = 5575; + public static final int GalleryBulletHitNotify = 5531; + public static final int GalleryFallCatchNotify = 5507; + public static final int GalleryFallScoreNotify = 5521; + public static final int GalleryFlowerCatchNotify = 5573; + public static final int GalleryPreStartNotify = 5599; + public static final int GalleryStartNotify = 5572; + public static final int GalleryStopNotify = 5535; + public static final int GallerySumoKillMonsterNotify = 5582; + public static final int GetActivityInfoReq = 2095; + public static final int GetActivityInfoRsp = 2041; + public static final int GetActivityScheduleReq = 2136; + public static final int GetActivityScheduleRsp = 2107; + public static final int GetActivityShopSheetInfoReq = 703; + public static final int GetActivityShopSheetInfoRsp = 790; + public static final int GetAllActivatedBargainDataReq = 463; + public static final int GetAllActivatedBargainDataRsp = 495; + public static final int GetAllH5ActivityInfoReq = 5668; + public static final int GetAllH5ActivityInfoRsp = 5676; + public static final int GetAllMailReq = 1431; + public static final int GetAllMailRsp = 1475; + public static final int GetAllSceneGalleryInfoReq = 5503; + public static final int GetAllSceneGalleryInfoRsp = 5590; + public static final int GetAllUnlockNameCardReq = 4027; + public static final int GetAllUnlockNameCardRsp = 4094; + public static final int GetAreaExplorePointReq = 241; + public static final int GetAreaExplorePointRsp = 249; + public static final int GetAuthSalesmanInfoReq = 2070; + public static final int GetAuthSalesmanInfoRsp = 2004; + public static final int GetAuthkeyReq = 1490; + public static final int GetAuthkeyRsp = 1473; + public static final int GetBargainDataReq = 488; + public static final int GetBargainDataRsp = 426; + public static final int GetBattlePassProductReq = 2644; + public static final int GetBattlePassProductRsp = 2649; + public static final int GetBlossomBriefInfoListReq = 2772; + public static final int GetBlossomBriefInfoListRsp = 2798; + public static final int GetBonusActivityRewardReq = 2581; + public static final int GetBonusActivityRewardRsp = 2505; + public static final int GetChatEmojiCollectionReq = 4068; + public static final int GetChatEmojiCollectionRsp = 4033; + public static final int GetCityHuntingOfferReq = 4325; + public static final int GetCityHuntingOfferRsp = 4307; + public static final int GetCityReputationInfoReq = 2872; + public static final int GetCityReputationInfoRsp = 2898; + public static final int GetCityReputationMapInfoReq = 2875; + public static final int GetCityReputationMapInfoRsp = 2848; + public static final int GetCompoundDataReq = 141; + public static final int GetCompoundDataRsp = 149; + public static final int GetDailyDungeonEntryInfoReq = 930; + public static final int GetDailyDungeonEntryInfoRsp = 967; + public static final int GetDungeonEntryExploreConditionReq = 3165; + public static final int GetDungeonEntryExploreConditionRsp = 3269; + public static final int GetExpeditionAssistInfoListReq = 2150; + public static final int GetExpeditionAssistInfoListRsp = 2035; + public static final int GetFriendShowAvatarInfoReq = 4070; + public static final int GetFriendShowAvatarInfoRsp = 4017; + public static final int GetFriendShowNameCardInfoReq = 4061; + public static final int GetFriendShowNameCardInfoRsp = 4029; + public static final int GetFurnitureCurModuleArrangeCountReq = 4711; + public static final int GetGachaInfoReq = 1572; + public static final int GetGachaInfoRsp = 1598; + public static final int GetHomeLevelUpRewardReq = 4557; + public static final int GetHomeLevelUpRewardRsp = 4603; + public static final int GetHuntingOfferRewardReq = 4302; + public static final int GetHuntingOfferRewardRsp = 4331; + public static final int GetInvestigationMonsterReq = 1901; + public static final int GetInvestigationMonsterRsp = 1910; + public static final int GetMailItemReq = 1435; + public static final int GetMailItemRsp = 1407; + public static final int GetMapAreaReq = 3108; + public static final int GetMapAreaRsp = 3328; + public static final int GetMapMarkTipsReq = 3463; + public static final int GetMapMarkTipsRsp = 3327; + public static final int GetMechanicusInfoReq = 3972; + public static final int GetMechanicusInfoRsp = 3998; + public static final int GetNextResourceInfoReq = 192; + public static final int GetNextResourceInfoRsp = 120; + public static final int GetOnlinePlayerInfoReq = 82; + public static final int GetOnlinePlayerInfoRsp = 47; + public static final int GetOnlinePlayerListReq = 90; + public static final int GetOnlinePlayerListRsp = 73; + public static final int GetOpActivityInfoReq = 5172; + public static final int GetOpActivityInfoRsp = 5198; + public static final int GetPlayerAskFriendListReq = 4018; + public static final int GetPlayerAskFriendListRsp = 4066; + public static final int GetPlayerBlacklistReq = 4049; + public static final int GetPlayerBlacklistRsp = 4091; + public static final int GetPlayerFriendListReq = 4072; + public static final int GetPlayerFriendListRsp = 4098; + public static final int GetPlayerHomeCompInfoReq = 4597; + public static final int GetPlayerMpModeAvailabilityReq = 1844; + public static final int GetPlayerMpModeAvailabilityRsp = 1849; + public static final int GetPlayerSocialDetailReq = 4073; + public static final int GetPlayerSocialDetailRsp = 4099; + public static final int GetPlayerTokenReq = 172; + public static final int GetPlayerTokenRsp = 198; + public static final int GetPushTipsRewardReq = 2227; + public static final int GetPushTipsRewardRsp = 2294; + public static final int GetQuestTalkHistoryReq = 490; + public static final int GetQuestTalkHistoryRsp = 473; + public static final int GetRecentMpPlayerListReq = 4034; + public static final int GetRecentMpPlayerListRsp = 4050; + public static final int GetRegionSearchReq = 5602; + public static final int GetReunionMissionInfoReq = 5094; + public static final int GetReunionMissionInfoRsp = 5099; + public static final int GetReunionPrivilegeInfoReq = 5097; + public static final int GetReunionPrivilegeInfoRsp = 5087; + public static final int GetReunionSignInInfoReq = 5052; + public static final int GetReunionSignInInfoRsp = 5081; + public static final int GetSceneAreaReq = 265; + public static final int GetSceneAreaRsp = 204; + public static final int GetSceneNpcPositionReq = 535; + public static final int GetSceneNpcPositionRsp = 507; + public static final int GetScenePerformanceReq = 3419; + public static final int GetScenePerformanceRsp = 3137; + public static final int GetScenePointReq = 297; + public static final int GetScenePointRsp = 281; + public static final int GetShopReq = 772; + public static final int GetShopRsp = 798; + public static final int GetShopmallDataReq = 707; + public static final int GetShopmallDataRsp = 721; + public static final int GetSignInRewardReq = 2507; + public static final int GetSignInRewardRsp = 2521; + public static final int GetWidgetSlotReq = 4253; + public static final int GetWidgetSlotRsp = 4254; + public static final int GetWorldMpInfoReq = 3391; + public static final int GetWorldMpInfoRsp = 3320; + public static final int GiveUpRoguelikeDungeonCardReq = 8353; + public static final int GiveUpRoguelikeDungeonCardRsp = 8497; + public static final int GivingRecordChangeNotify = 187; + public static final int GivingRecordNotify = 116; + public static final int GmTalkNotify = 94; + public static final int GmTalkReq = 98; + public static final int GmTalkRsp = 12; + public static final int GrantRewardNotify = 663; + public static final int GroupLinkAllNotify = 5776; + public static final int GroupLinkChangeNotify = 5768; + public static final int GroupLinkDeleteNotify = 5775; + public static final int GroupSuiteNotify = 3257; + public static final int GroupUnloadNotify = 3344; + public static final int GuestBeginEnterSceneNotify = 3031; + public static final int GuestPostEnterSceneNotify = 3144; + public static final int H5ActivityIdsNotify = 5675; public static final int HideAndSeekPlayerReadyNotify = 5302; - public static final int HideAndSeekPlayerSetAvatarNotify = 5316; - public static final int HideAndSeekSelectAvatarReq = 5329; - public static final int HideAndSeekSelectAvatarRsp = 5325; - public static final int HideAndSeekSelectSkillReq = 8307; - public static final int HideAndSeekSelectSkillRsp = 8227; - public static final int HideAndSeekSetReadyReq = 5383; - public static final int HideAndSeekSetReadyRsp = 5303; - public static final int HideAndSeekSettleNotify = 5334; - public static final int HitClientTrivialNotify = 218; - public static final int HitTreeNotify = 3222; - public static final int HomeAvatarAllFinishRewardNotify = 4648; - public static final int HomeAvatarCostumeChangeNotify = 4685; - public static final int HomeAvatarRewardEventGetReq = 4775; - public static final int HomeAvatarRewardEventGetRsp = 4873; - public static final int HomeAvatarRewardEventNotify = 4789; - public static final int HomeAvatarSummonAllEventNotify = 4617; - public static final int HomeAvatarSummonEventReq = 4615; - public static final int HomeAvatarSummonEventRsp = 4498; - public static final int HomeAvatarSummonFinishReq = 4748; - public static final int HomeAvatarSummonFinishRsp = 4782; - public static final int HomeAvatarTalkFinishInfoNotify = 4502; - public static final int HomeAvatarTalkReq = 4712; - public static final int HomeAvatarTalkRsp = 4700; - public static final int HomeAvtarAllFinishRewardNotify = 4849; - public static final int HomeBasicInfoNotify = 4872; - public static final int HomeBlockNotify = 4542; - public static final int HomeChangeEditModeReq = 4625; - public static final int HomeChangeEditModeRsp = 4885; - public static final int HomeChangeModuleReq = 4688; - public static final int HomeChangeModuleRsp = 4821; - public static final int HomeChooseModuleReq = 4479; - public static final int HomeChooseModuleRsp = 4745; - public static final int HomeComfortInfoNotify = 4649; - public static final int HomeCustomFurnitureInfoNotify = 4482; - public static final int HomeEditCustomFurnitureReq = 4516; - public static final int HomeEditCustomFurnitureRsp = 4871; - public static final int HomeFishFarmingInfoNotify = 4682; + public static final int HideAndSeekPlayerSetAvatarNotify = 5319; + public static final int HideAndSeekSelectAvatarReq = 5330; + public static final int HideAndSeekSelectAvatarRsp = 5367; + public static final int HideAndSeekSelectSkillReq = 8183; + public static final int HideAndSeekSelectSkillRsp = 8088; + public static final int HideAndSeekSetReadyReq = 5358; + public static final int HideAndSeekSetReadyRsp = 5370; + public static final int HideAndSeekSettleNotify = 5317; + public static final int HitClientTrivialNotify = 244; + public static final int HitTreeNotify = 3019; + public static final int HomeAvatarAllFinishRewardNotify = 4741; + public static final int HomeAvatarCostumeChangeNotify = 4748; + public static final int HomeAvatarRewardEventGetReq = 4551; + public static final int HomeAvatarRewardEventGetRsp = 4833; + public static final int HomeAvatarRewardEventNotify = 4852; + public static final int HomeAvatarSummonAllEventNotify = 4808; + public static final int HomeAvatarSummonEventReq = 4806; + public static final int HomeAvatarSummonEventRsp = 4817; + public static final int HomeAvatarSummonFinishReq = 4629; + public static final int HomeAvatarSummonFinishRsp = 4696; + public static final int HomeAvatarTalkFinishInfoNotify = 4896; + public static final int HomeAvatarTalkReq = 4688; + public static final int HomeAvatarTalkRsp = 4464; + public static final int HomeAvtarAllFinishRewardNotify = 4453; + public static final int HomeBasicInfoNotify = 4885; + public static final int HomeBlockNotify = 4543; + public static final int HomeChangeEditModeReq = 4564; + public static final int HomeChangeEditModeRsp = 4559; + public static final int HomeChangeModuleReq = 4809; + public static final int HomeChangeModuleRsp = 4596; + public static final int HomeChooseModuleReq = 4524; + public static final int HomeChooseModuleRsp = 4648; + public static final int HomeComfortInfoNotify = 4699; + public static final int HomeCustomFurnitureInfoNotify = 4712; + public static final int HomeEditCustomFurnitureReq = 4724; + public static final int HomeEditCustomFurnitureRsp = 4496; + public static final int HomeFishFarmingInfoNotify = 4677; public static final int HomeGetArrangementInfoReq = 4848; - public static final int HomeGetArrangementInfoRsp = 4456; - public static final int HomeGetBasicInfoReq = 4535; - public static final int HomeGetFishFarmingInfoReq = 4455; - public static final int HomeGetFishFarmingInfoRsp = 4889; - public static final int HomeGetOnlineStatusReq = 4796; - public static final int HomeGetOnlineStatusRsp = 4554; - public static final int HomeKickPlayerReq = 4809; - public static final int HomeKickPlayerRsp = 4752; - public static final int HomeLimitedShopBuyGoodsReq = 4638; - public static final int HomeLimitedShopBuyGoodsRsp = 4790; - public static final int HomeLimitedShopGoodsListReq = 4579; - public static final int HomeLimitedShopGoodsListRsp = 4846; - public static final int HomeLimitedShopInfoChangeNotify = 4814; - public static final int HomeLimitedShopInfoNotify = 4621; - public static final int HomeLimitedShopInfoReq = 4616; - public static final int HomeLimitedShopInfoRsp = 4585; - public static final int HomeMarkPointNotify = 4746; - public static final int HomeModuleSeenReq = 4546; - public static final int HomeModuleSeenRsp = 4526; - public static final int HomeModuleUnlockNotify = 4781; - public static final int HomePlantFieldNotify = 4466; - public static final int HomePlantInfoNotify = 4835; - public static final int HomePlantInfoReq = 4833; - public static final int HomePlantInfoRsp = 4859; - public static final int HomePlantSeedReq = 4614; - public static final int HomePlantSeedRsp = 4804; - public static final int HomePlantWeedReq = 4877; - public static final int HomePlantWeedRsp = 4575; - public static final int HomePriorCheckNotify = 4690; - public static final int HomeResourceNotify = 4806; - public static final int HomeResourceTakeFetterExpReq = 4840; - public static final int HomeResourceTakeFetterExpRsp = 4500; - public static final int HomeResourceTakeHomeCoinReq = 4763; - public static final int HomeResourceTakeHomeCoinRsp = 4658; - public static final int HomeSceneInitFinishReq = 4552; - public static final int HomeSceneInitFinishRsp = 4592; - public static final int HomeSceneJumpReq = 4659; - public static final int HomeSceneJumpRsp = 4570; - public static final int HomeTransferReq = 4880; - public static final int HomeTransferRsp = 4767; - public static final int HomeUnknown1Notify = 4528; - public static final int HomeUnknown2Req = 4857; - public static final int HomeUnknown2Rsp = 4670; - public static final int HomeUpdateArrangementInfoReq = 4472; - public static final int HomeUpdateArrangementInfoRsp = 4822; - public static final int HomeUpdateFishFarmingInfoReq = 4604; - public static final int HomeUpdateFishFarmingInfoRsp = 4856; - public static final int HostPlayerNotify = 341; - public static final int HuntingFailNotify = 4302; - public static final int HuntingGiveUpReq = 4337; - public static final int HuntingGiveUpRsp = 4332; - public static final int HuntingOngoingNotify = 4313; - public static final int HuntingRevealClueNotify = 4347; - public static final int HuntingRevealFinalNotify = 4316; - public static final int HuntingStartNotify = 4326; - public static final int HuntingSuccessNotify = 4301; - public static final int InBattleMechanicusBuildingPointsNotify = 5385; - public static final int InBattleMechanicusCardResultNotify = 5330; - public static final int InBattleMechanicusConfirmCardNotify = 5307; - public static final int InBattleMechanicusConfirmCardReq = 5355; - public static final int InBattleMechanicusConfirmCardRsp = 5327; - public static final int InBattleMechanicusExcapeMonsterNotify = 5332; - public static final int InBattleMechanicusLeftMonsterNotify = 5317; - public static final int InBattleMechanicusPickCardNotify = 5382; - public static final int InBattleMechanicusPickCardReq = 5335; - public static final int InBattleMechanicusPickCardRsp = 5349; - public static final int InBattleMechanicusSettleNotify = 5398; - public static final int InteractDailyDungeonInfoNotify = 916; - public static final int InterruptGalleryReq = 5507; - public static final int InterruptGalleryRsp = 5530; - public static final int InvestigationMonsterUpdateNotify = 1922; - public static final int ItemAddHintNotify = 632; - public static final int ItemCdGroupTimeNotify = 611; - public static final int ItemGivingReq = 178; - public static final int ItemGivingRsp = 108; - public static final int JoinHomeWorldFailNotify = 4863; - public static final int JoinPlayerFailNotify = 268; - public static final int JoinPlayerSceneReq = 253; - public static final int JoinPlayerSceneRsp = 239; - public static final int KeepAliveNotify = 9; - public static final int LeaveSceneReq = 231; - public static final int LeaveSceneRsp = 241; - public static final int LeaveWorldNotify = 3420; - public static final int LevelupCityReq = 287; - public static final int LevelupCityRsp = 289; - public static final int LifeStateChangeNotify = 1231; - public static final int LiveEndNotify = 801; - public static final int LiveStartNotify = 820; - public static final int LoadActivityTerrainNotify = 2175; - public static final int LuaEnvironmentEffectNotify = 3289; - public static final int LuaSetOptionNotify = 387; - public static final int LunaRiteAreaFinishNotify = 8107; - public static final int LunaRiteGroupBundleRegisterNotify = 8327; - public static final int LunaRiteHintPointRemoveNotify = 8420; - public static final int LunaRiteHintPointReq = 8342; - public static final int LunaRiteHintPointRsp = 8481; - public static final int LunaRiteSacrificeReq = 8062; - public static final int LunaRiteSacrificeRsp = 8401; - public static final int LunaRiteTakeSacrificeRewardReq = 8669; - public static final int LunaRiteTakeSacrificeRewardRsp = 8252; - public static final int MailChangeNotify = 1431; - public static final int MainCoopUpdateNotify = 1959; - public static final int MapAreaChangeNotify = 3103; + public static final int HomeGetArrangementInfoRsp = 4844; + public static final int HomeGetBasicInfoReq = 4655; + public static final int HomeGetFishFarmingInfoReq = 4476; + public static final int HomeGetFishFarmingInfoRsp = 4678; + public static final int HomeGetOnlineStatusReq = 4820; + public static final int HomeGetOnlineStatusRsp = 4705; + public static final int HomeKickPlayerReq = 4870; + public static final int HomeKickPlayerRsp = 4691; + public static final int HomeLimitedShopBuyGoodsReq = 4760; + public static final int HomeLimitedShopBuyGoodsRsp = 4750; + public static final int HomeLimitedShopGoodsListReq = 4552; + public static final int HomeLimitedShopGoodsListRsp = 4546; + public static final int HomeLimitedShopInfoChangeNotify = 4790; + public static final int HomeLimitedShopInfoNotify = 4887; + public static final int HomeLimitedShopInfoReq = 4825; + public static final int HomeLimitedShopInfoRsp = 4796; + public static final int HomeMarkPointNotify = 4474; + public static final int HomeModuleSeenReq = 4499; + public static final int HomeModuleSeenRsp = 4821; + public static final int HomeModuleUnlockNotify = 4560; + public static final int HomePlantFieldNotify = 4549; + public static final int HomePlantInfoNotify = 4587; + public static final int HomePlantInfoReq = 4647; + public static final int HomePlantInfoRsp = 4701; + public static final int HomePlantSeedReq = 4804; + public static final int HomePlantSeedRsp = 4556; + public static final int HomePlantWeedReq = 4640; + public static final int HomePlantWeedRsp = 4527; + public static final int HomePriorCheckNotify = 4599; + public static final int HomeResourceNotify = 4892; + public static final int HomeResourceTakeFetterExpReq = 4768; + public static final int HomeResourceTakeFetterExpRsp = 4645; + public static final int HomeResourceTakeHomeCoinReq = 4479; + public static final int HomeResourceTakeHomeCoinRsp = 4541; + public static final int HomeSceneInitFinishReq = 4674; + public static final int HomeSceneInitFinishRsp = 4505; + public static final int HomeSceneJumpReq = 4528; + public static final int HomeSceneJumpRsp = 4698; + public static final int HomeTransferReq = 4726; + public static final int HomeTransferRsp = 4616; + public static final int HomeUpdateArrangementInfoReq = 4510; + public static final int HomeUpdateArrangementInfoRsp = 4757; + public static final int HomeUpdateFishFarmingInfoReq = 4544; + public static final int HomeUpdateFishFarmingInfoRsp = 4857; + public static final int HostPlayerNotify = 312; + public static final int HuntingFailNotify = 4320; + public static final int HuntingGiveUpReq = 4341; + public static final int HuntingGiveUpRsp = 4342; + public static final int HuntingOngoingNotify = 4345; + public static final int HuntingRevealClueNotify = 4322; + public static final int HuntingRevealFinalNotify = 4344; + public static final int HuntingStartNotify = 4329; + public static final int HuntingSuccessNotify = 4349; + public static final int InBattleMechanicusBuildingPointsNotify = 5303; + public static final int InBattleMechanicusCardResultNotify = 5397; + public static final int InBattleMechanicusConfirmCardNotify = 5348; + public static final int InBattleMechanicusConfirmCardReq = 5331; + public static final int InBattleMechanicusConfirmCardRsp = 5375; + public static final int InBattleMechanicusEscapeMonsterNotify = 5307; + public static final int InBattleMechanicusLeftMonsterNotify = 5321; + public static final int InBattleMechanicusPickCardNotify = 5399; + public static final int InBattleMechanicusPickCardReq = 5390; + public static final int InBattleMechanicusPickCardRsp = 5373; + public static final int InBattleMechanicusSettleNotify = 5305; + public static final int InteractDailyDungeonInfoNotify = 919; + public static final int InterruptGalleryReq = 5548; + public static final int InterruptGalleryRsp = 5597; + public static final int InvestigationMonsterUpdateNotify = 1906; + public static final int ItemAddHintNotify = 607; + public static final int ItemCdGroupTimeNotify = 634; + public static final int ItemGivingReq = 140; + public static final int ItemGivingRsp = 118; + public static final int JoinHomeWorldFailNotify = 4530; + public static final int JoinPlayerFailNotify = 236; + public static final int JoinPlayerSceneReq = 292; + public static final int JoinPlayerSceneRsp = 220; + public static final int KeepAliveNotify = 72; + public static final int LeaveSceneReq = 298; + public static final int LeaveSceneRsp = 212; + public static final int LeaveWorldNotify = 3017; + public static final int LevelupCityReq = 216; + public static final int LevelupCityRsp = 287; + public static final int LifeStateChangeNotify = 1298; + public static final int LiveEndNotify = 806; + public static final int LiveStartNotify = 826; + public static final int LoadActivityTerrainNotify = 2029; + public static final int LuaEnvironmentEffectNotify = 3408; + public static final int LuaSetOptionNotify = 316; + public static final int LunaRiteAreaFinishNotify = 8213; + public static final int LunaRiteGroupBundleRegisterNotify = 8465; + public static final int LunaRiteHintPointRemoveNotify = 8787; + public static final int LunaRiteHintPointReq = 8195; + public static final int LunaRiteHintPointRsp = 8765; + public static final int LunaRiteSacrificeReq = 8805; + public static final int LunaRiteSacrificeRsp = 8080; + public static final int LunaRiteTakeSacrificeRewardReq = 8045; + public static final int LunaRiteTakeSacrificeRewardRsp = 8397; + public static final int MailChangeNotify = 1498; + public static final int MainCoopUpdateNotify = 1968; + public static final int MapAreaChangeNotify = 3378; public static final int MarkEntityInMinMapNotify = 202; - public static final int MarkMapReq = 3208; - public static final int MarkMapRsp = 3421; - public static final int MarkNewNotify = 1227; - public static final int MarkTargetInvestigationMonsterNotify = 1928; - public static final int MassiveEntityElementOpBatchNotify = 377; - public static final int MassiveEntityStateChangedNotify = 303; - public static final int MaterialDeleteReturnNotify = 693; - public static final int MaterialDeleteUpdateNotify = 643; - public static final int McoinExchangeHcoinReq = 687; - public static final int McoinExchangeHcoinRsp = 689; - public static final int MechanicusCandidateTeamCreateReq = 3997; - public static final int MechanicusCandidateTeamCreateRsp = 3998; - public static final int MechanicusCloseNotify = 3917; - public static final int MechanicusCoinNotify = 3937; - public static final int MechanicusLevelupGearReq = 3949; - public static final int MechanicusLevelupGearRsp = 3982; - public static final int MechanicusOpenNotify = 3932; - public static final int MechanicusSequenceOpenNotify = 3941; - public static final int MechanicusUnlockGearReq = 3985; - public static final int MechanicusUnlockGearRsp = 3935; - public static final int MeetNpcReq = 585; - public static final int MeetNpcRsp = 535; - public static final int MetNpcIdListNotify = 517; - public static final int MiracleRingDataNotify = 5243; - public static final int MiracleRingDeliverItemReq = 5226; - public static final int MiracleRingDeliverItemRsp = 5247; - public static final int MiracleRingDestroyNotify = 5216; - public static final int MiracleRingDropResultNotify = 5203; - public static final int MiracleRingTakeRewardReq = 5204; - public static final int MiracleRingTakeRewardRsp = 5228; - public static final int MistTrialDunegonFailNotify = 8580; - public static final int MistTrialGetChallengeMissionReq = 8668; - public static final int MistTrialGetChallengeMissionRsp = 8385; - public static final int MistTrialSelectAvatarAndEnterDungeonReq = 8318; - public static final int MistTrialSelectAvatarAndEnterDungeonRsp = 8403; - public static final int MonsterAIConfigHashNotify = 3121; - public static final int MonsterAlertChangeNotify = 313; - public static final int MonsterForceAlertNotify = 342; - public static final int MonsterPointArrayRouteUpdateNotify = 3138; - public static final int MonsterSummonTagNotify = 1309; - public static final int MpBlockNotify = 1808; - public static final int MpPlayGuestReplyInviteReq = 1811; - public static final int MpPlayGuestReplyInviteRsp = 1841; - public static final int MpPlayGuestReplyNotify = 1805; - public static final int MpPlayInviteResultNotify = 1806; + public static final int MarkMapReq = 3466; + public static final int MarkMapRsp = 3079; + public static final int MarkNewNotify = 1275; + public static final int MarkTargetInvestigationMonsterNotify = 1915; + public static final int MassiveEntityElementOpBatchNotify = 357; + public static final int MassiveEntityStateChangedNotify = 370; + public static final int MaterialDeleteReturnNotify = 661; + public static final int MaterialDeleteUpdateNotify = 700; + public static final int McoinExchangeHcoinReq = 616; + public static final int McoinExchangeHcoinRsp = 687; + public static final int MechanicusCandidateTeamCreateReq = 3981; + public static final int MechanicusCandidateTeamCreateRsp = 3905; + public static final int MechanicusCloseNotify = 3921; + public static final int MechanicusCoinNotify = 3935; + public static final int MechanicusLevelupGearReq = 3973; + public static final int MechanicusLevelupGearRsp = 3999; + public static final int MechanicusOpenNotify = 3907; + public static final int MechanicusSequenceOpenNotify = 3912; + public static final int MechanicusUnlockGearReq = 3903; + public static final int MechanicusUnlockGearRsp = 3990; + public static final int MeetNpcReq = 503; + public static final int MeetNpcRsp = 590; + public static final int MetNpcIdListNotify = 521; + public static final int MiracleRingDataNotify = 5225; + public static final int MiracleRingDeliverItemReq = 5229; + public static final int MiracleRingDeliverItemRsp = 5222; + public static final int MiracleRingDestroyNotify = 5244; + public static final int MiracleRingDropResultNotify = 5231; + public static final int MiracleRingTakeRewardReq = 5207; + public static final int MiracleRingTakeRewardRsp = 5202; + public static final int MistTrialDunegonFailNotify = 8135; + public static final int MistTrialGetChallengeMissionReq = 8893; + public static final int MistTrialGetChallengeMissionRsp = 8508; + public static final int MistTrialSelectAvatarAndEnterDungeonReq = 8666; + public static final int MistTrialSelectAvatarAndEnterDungeonRsp = 8239; + public static final int MonsterAIConfigHashNotify = 3039; + public static final int MonsterAlertChangeNotify = 363; + public static final int MonsterForceAlertNotify = 395; + public static final int MonsterPointArrayRouteUpdateNotify = 3410; + public static final int MonsterSummonTagNotify = 1372; + public static final int MpBlockNotify = 1801; + public static final int MpPlayGuestReplyInviteReq = 1848; + public static final int MpPlayGuestReplyInviteRsp = 1850; + public static final int MpPlayGuestReplyNotify = 1812; + public static final int MpPlayInviteResultNotify = 1815; public static final int MpPlayOwnerCheckReq = 1814; - public static final int MpPlayOwnerCheckRsp = 1812; - public static final int MpPlayOwnerInviteNotify = 1815; - public static final int MpPlayOwnerStartInviteReq = 1846; - public static final int MpPlayOwnerStartInviteRsp = 1827; - public static final int MpPlayPrepareInterruptNotify = 1848; - public static final int MpPlayPrepareNotify = 1839; - public static final int MultistagePlayEndNotify = 5375; - public static final int MultistagePlayFinishStageReq = 5331; - public static final int MultistagePlayFinishStageRsp = 5397; - public static final int MultistagePlayInfoNotify = 5309; - public static final int MultistagePlaySettleNotify = 5314; - public static final int MultistagePlayStageEndNotify = 5340; - public static final int MusicGameCreateBeatmapReq = 6326; - public static final int MusicGameCreateBeatmapRsp = 6347; + public static final int MpPlayOwnerCheckRsp = 1847; + public static final int MpPlayOwnerInviteNotify = 1835; + public static final int MpPlayOwnerStartInviteReq = 1837; + public static final int MpPlayOwnerStartInviteRsp = 1823; + public static final int MpPlayPrepareInterruptNotify = 1813; + public static final int MpPlayPrepareNotify = 1833; + public static final int MultistagePlayEndNotify = 5355; + public static final int MultistagePlayFinishStageReq = 5398; + public static final int MultistagePlayFinishStageRsp = 5381; + public static final int MultistagePlayInfoNotify = 5372; + public static final int MultistagePlaySettleNotify = 5313; + public static final int MultistagePlayStageEndNotify = 5379; public static final int MusicGameGetBeatmapReq = 6318; public static final int MusicGameGetBeatmapRsp = 6309; - public static final int MusicGameSearchBeatmapReq = 6343; + public static final int MusicGameSettleReq = 8892; + public static final int MusicGameSettleRsp = 8673; + public static final int MusicGameStartReq = 8406; + public static final int MusicGameStartRsp = 8326; + public static final int MusicGameCreateBeatmapRsp = 6347; + public static final int MusicGameCreateBeatmapReq = 6326; public static final int MusicGameSearchBeatmapRsp = 6304; - public static final int MusicGameSettleReq = 8745; - public static final int MusicGameSettleRsp = 8288; - public static final int MusicGameStartReq = 8927; - public static final int MusicGameStartRsp = 8101; - public static final int MusicCustomReq = 6318; - public static final int MusicCustomRsp = 6309; - public static final int MusicGameStoreSubmitReq = 6326; - public static final int MusicGameStoreSubmitRsp = 6347; - public static final int MusicGameStoreSubmitNotify = 6337; + public static final int MusicGameSearchBeatmapReq = 6343; public static final int MusicGameStartToPlayOthersBeatmapReq = 6302; public static final int MusicGameStartToPlayOthersBeatmapRsp = 6313; - public static final int NavMeshStatsNotify = 2387; - public static final int NormalUidOpNotify = 5718; - public static final int NpcTalkReq = 509; - public static final int NpcTalkRsp = 531; - public static final int ObstacleModifyNotify = 2341; - public static final int OfferingInteractReq = 2908; - public static final int OfferingInteractRsp = 2923; - public static final int OneoffGatherPointDetectorDataNotify = 4262; - public static final int OpActivityDataNotify = 5141; - public static final int OpActivityStateNotify = 2509; - public static final int OpActivityUpdateNotify = 5137; - public static final int OpenBlossomCircleCampGuideNotify = 2785; - public static final int OpenStateChangeNotify = 112; - public static final int OpenStateUpdateNotify = 119; - public static final int OrderDisplayNotify = 4103; - public static final int OrderFinishNotify = 4143; - public static final int OtherPlayerEnterHomeNotify = 4609; - public static final int PathfindingEnterSceneReq = 2332; - public static final int PathfindingEnterSceneRsp = 2317; - public static final int PathfindingPingNotify = 2337; - public static final int PersonalLineAllDataReq = 446; - public static final int PersonalLineAllDataRsp = 433; - public static final int PersonalLineNewUnlockNotify = 470; - public static final int PersonalSceneJumpReq = 266; - public static final int PersonalSceneJumpRsp = 248; - public static final int PingReq = 32; - public static final int PingRsp = 17; - public static final int PlantFlowerAcceptAllGiveFlowerReq = 8017; - public static final int PlantFlowerAcceptAllGiveFlowerRsp = 8831; - public static final int PlantFlowerAcceptGiveFlowerReq = 8137; - public static final int PlantFlowerAcceptGiveFlowerRsp = 8431; - public static final int PlantFlowerEditFlowerCombinationReq = 8506; - public static final int PlantFlowerEditFlowerCombinationRsp = 8335; - public static final int PlantFlowerGetCanGiveFriendFlowerReq = 8648; - public static final int PlantFlowerGetCanGiveFriendFlowerRsp = 8507; - public static final int PlantFlowerGetFriendFlowerWishListReq = 8840; - public static final int PlantFlowerGetFriendFlowerWishListRsp = 8553; - public static final int PlantFlowerGetRecvFlowerListReq = 8914; - public static final int PlantFlowerGetRecvFlowerListRsp = 8929; - public static final int PlantFlowerGetSeedInfoReq = 8913; - public static final int PlantFlowerGetSeedInfoRsp = 8932; - public static final int PlantFlowerGiveFriendFlowerReq = 8836; - public static final int PlantFlowerGiveFriendFlowerRsp = 8893; - public static final int PlantFlowerHaveRecvFlowerNotify = 8174; - public static final int PlantFlowerSetFlowerWishReq = 8650; - public static final int PlantFlowerSetFlowerWishRsp = 8588; - public static final int PlantFlowerTakeSeedRewardReq = 8182; - public static final int PlantFlowerTakeSeedRewardRsp = 8386; - public static final int PlatformChangeRouteNotify = 205; - public static final int PlatformStartRouteNotify = 208; - public static final int PlatformStopRouteNotify = 204; - public static final int PlayerAllowEnterMpAfterAgreeMatchNotify = 4151; - public static final int PlayerApplyEnterHomeNotify = 4504; - public static final int PlayerApplyEnterHomeResultNotify = 4766; - public static final int PlayerApplyEnterHomeResultReq = 4568; - public static final int PlayerApplyEnterHomeResultRsp = 4697; - public static final int PlayerApplyEnterMpAfterMatchAgreedNotify = 4163; - public static final int PlayerApplyEnterMpNotify = 1818; - public static final int PlayerApplyEnterMpReq = 1809; - public static final int PlayerApplyEnterMpResultNotify = 1804; - public static final int PlayerApplyEnterMpResultReq = 1828; - public static final int PlayerApplyEnterMpResultRsp = 1803; - public static final int PlayerApplyEnterMpRsp = 1843; - public static final int PlayerCancelMatchReq = 4154; - public static final int PlayerCancelMatchRsp = 4178; - public static final int PlayerChatCDNotify = 3464; - public static final int PlayerChatNotify = 3295; - public static final int PlayerChatReq = 3378; - public static final int PlayerChatRsp = 3321; - public static final int PlayerCompoundMaterialReq = 122; - public static final int PlayerCompoundMaterialRsp = 154; - public static final int PlayerConfirmMatchReq = 4197; - public static final int PlayerConfirmMatchRsp = 4166; - public static final int PlayerCookArgsReq = 104; - public static final int PlayerCookArgsRsp = 105; - public static final int PlayerCookReq = 158; - public static final int PlayerCookRsp = 150; - public static final int PlayerDataNotify = 135; - public static final int PlayerEnterDungeonReq = 941; - public static final int PlayerEnterDungeonRsp = 937; - public static final int PlayerEnterSceneInfoNotify = 274; - public static final int PlayerEnterSceneNotify = 209; - public static final int PlayerEyePointStateNotify = 3376; - public static final int PlayerFishingDataNotify = 5815; - public static final int PlayerForceExitReq = 173; - public static final int PlayerForceExitRsp = 161; - public static final int PlayerGameTimeNotify = 155; - public static final int PlayerGeneralMatchConfirmNotify = 4182; - public static final int PlayerGeneralMatchDismissNotify = 4187; + public static final int NavMeshStatsNotify = 2316; + public static final int NormalUidOpNotify = 5726; + public static final int NpcTalkReq = 572; + public static final int NpcTalkRsp = 598; + public static final int ObstacleModifyNotify = 2312; + public static final int OfferingInteractReq = 2918; + public static final int OfferingInteractRsp = 2908; + public static final int OneofGatherPointDetectorDataNotify = 4297; + public static final int OpActivityDataNotify = 5112; + public static final int OpActivityStateNotify = 2572; + public static final int OpActivityUpdateNotify = 5135; + public static final int OpenBlossomCircleCampGuideNotify = 2703; + public static final int OpenStateChangeNotify = 127; + public static final int OpenStateUpdateNotify = 193; + public static final int OrderDisplayNotify = 4131; + public static final int OrderFinishNotify = 4125; + public static final int OtherPlayerEnterHomeNotify = 4628; + public static final int PSNBlackListNotify = 4040; + public static final int PSNFriendListNotify = 4087; + public static final int PSPlayerApplyEnterMpReq = 1841; + public static final int PSPlayerApplyEnterMpRsp = 1842; + public static final int PathfindingEnterSceneReq = 2307; + public static final int PathfindingEnterSceneRsp = 2321; + public static final int PathfindingPingNotify = 2335; + public static final int PersonalLineAllDataReq = 474; + public static final int PersonalLineAllDataRsp = 476; + public static final int PersonalLineNewUnlockNotify = 442; + public static final int PersonalSceneJumpReq = 284; + public static final int PersonalSceneJumpRsp = 280; + public static final int PingReq = 7; + public static final int PingRsp = 21; + public static final int PlantFlowerAcceptAllGiveFlowerReq = 8808; + public static final int PlantFlowerAcceptAllGiveFlowerRsp = 8888; + public static final int PlantFlowerAcceptGiveFlowerReq = 8383; + public static final int PlantFlowerAcceptGiveFlowerRsp = 8567; + public static final int PlantFlowerEditFlowerCombinationReq = 8843; + public static final int PlantFlowerEditFlowerCombinationRsp = 8788; + public static final int PlantFlowerGetCanGiveFriendFlowerReq = 8716; + public static final int PlantFlowerGetCanGiveFriendFlowerRsp = 8766; + public static final int PlantFlowerGetFriendFlowerWishListReq = 8126; + public static final int PlantFlowerGetFriendFlowerWishListRsp = 8511; + public static final int PlantFlowerGetRecvFlowerListReq = 8270; + public static final int PlantFlowerGetRecvFlowerListRsp = 8374; + public static final int PlantFlowerGetSeedInfoReq = 8560; + public static final int PlantFlowerGetSeedInfoRsp = 8764; + public static final int PlantFlowerGiveFriendFlowerReq = 8846; + public static final int PlantFlowerGiveFriendFlowerRsp = 8386; + public static final int PlantFlowerHaveRecvFlowerNotify = 8078; + public static final int PlantFlowerSetFlowerWishReq = 8547; + public static final int PlantFlowerSetFlowerWishRsp = 8910; + public static final int PlantFlowerTakeSeedRewardReq = 8968; + public static final int PlantFlowerTakeSeedRewardRsp = 8860; + public static final int PlatformChangeRouteNotify = 268; + public static final int PlatformStartRouteNotify = 218; + public static final int PlatformStopRouteNotify = 266; + public static final int PlayerAllowEnterMpAfterAgreeMatchNotify = 4199; + public static final int PlayerApplyEnterHomeNotify = 4533; + public static final int PlayerApplyEnterHomeResultNotify = 4468; + public static final int PlayerApplyEnterHomeResultReq = 4693; + public static final int PlayerApplyEnterHomeResultRsp = 4706; + public static final int PlayerApplyEnterMpAfterMatchAgreedNotify = 4195; + public static final int PlayerApplyEnterMpNotify = 1826; + public static final int PlayerApplyEnterMpReq = 1818; + public static final int PlayerApplyEnterMpResultNotify = 1807; + public static final int PlayerApplyEnterMpResultReq = 1802; + public static final int PlayerApplyEnterMpResultRsp = 1831; + public static final int PlayerApplyEnterMpRsp = 1825; + public static final int PlayerCancelMatchReq = 4157; + public static final int PlayerCancelMatchRsp = 4152; + public static final int PlayerChatCDNotify = 3367; + public static final int PlayerChatNotify = 3010; + public static final int PlayerChatReq = 3185; + public static final int PlayerChatRsp = 3228; + public static final int PlayerCompoundMaterialReq = 150; + public static final int PlayerCompoundMaterialRsp = 143; + public static final int PlayerConfirmMatchReq = 4172; + public static final int PlayerConfirmMatchRsp = 4194; + public static final int PlayerCookArgsReq = 166; + public static final int PlayerCookArgsRsp = 168; + public static final int PlayerCookReq = 194; + public static final int PlayerCookRsp = 188; + public static final int PlayerDataNotify = 190; + public static final int PlayerEnterDungeonReq = 912; + public static final int PlayerEnterDungeonRsp = 935; + public static final int PlayerEnterSceneInfoNotify = 214; + public static final int PlayerEnterSceneNotify = 272; + public static final int PlayerEyePointStateNotify = 3051; + public static final int PlayerFishingDataNotify = 5835; + public static final int PlayerForceExitReq = 189; + public static final int PlayerForceExitRsp = 159; + public static final int PlayerGameTimeNotify = 131; + public static final int PlayerGeneralMatchConfirmNotify = 4192; + public static final int PlayerGeneralMatchDismissNotify = 4191; public static final int PlayerGetForceQuitBanInfoReq = 4164; - public static final int PlayerGetForceQuitBanInfoRsp = 4162; - public static final int PlayerHomeCompInfoNotify = 4563; - public static final int PlayerInjectFixNotify = 188; - public static final int PlayerInvestigationAllInfoNotify = 1905; - public static final int PlayerInvestigationNotify = 1927; - public static final int PlayerInvestigationTargetNotify = 1906; - public static final int PlayerLevelRewardUpdateNotify = 143; - public static final int PlayerLoginReq = 141; - public static final int PlayerLoginRsp = 137; - public static final int PlayerLogoutNotify = 185; - public static final int PlayerLogoutReq = 132; - public static final int PlayerLogoutRsp = 117; - public static final int PlayerLuaShellNotify = 110; - public static final int PlayerMatchAgreedResultNotify = 4152; - public static final int PlayerMatchInfoNotify = 4193; - public static final int PlayerMatchStopNotify = 4153; - public static final int PlayerMatchSuccNotify = 4176; - public static final int PlayerOfferingDataNotify = 2901; - public static final int PlayerOfferingReq = 2906; - public static final int PlayerOfferingRsp = 2911; - public static final int PlayerPreEnterMpNotify = 1847; - public static final int PlayerPropChangeNotify = 186; - public static final int PlayerPropChangeReasonNotify = 1282; - public static final int PlayerPropNotify = 127; - public static final int PlayerQuitDungeonReq = 932; - public static final int PlayerQuitDungeonRsp = 917; - public static final int PlayerQuitFromHomeNotify = 4776; - public static final int PlayerQuitFromMpNotify = 1826; - public static final int PlayerRandomCookReq = 120; - public static final int PlayerRandomCookRsp = 113; - public static final int PlayerRechargeDataNotify = 4128; - public static final int PlayerReportReq = 4059; - public static final int PlayerReportRsp = 4084; - public static final int PlayerRoutineDataNotify = 3518; - public static final int PlayerSetLanguageReq = 170; - public static final int PlayerSetLanguageRsp = 129; - public static final int PlayerSetOnlyMPWithPSPlayerReq = 1802; - public static final int PlayerSetOnlyMPWithPSPlayerRsp = 1813; - public static final int PlayerSetPauseReq = 159; - public static final int PlayerSetPauseRsp = 184; - public static final int PlayerStartMatchReq = 4168; - public static final int PlayerStartMatchRsp = 4159; - public static final int PlayerStoreNotify = 609; - public static final int PlayerTimeNotify = 172; - public static final int PlayerWorldSceneInfoListNotify = 3172; - public static final int PostEnterSceneReq = 3097; - public static final int PostEnterSceneRsp = 3344; - public static final int PrivateChatNotify = 4991; - public static final int PrivateChatReq = 4959; - public static final int PrivateChatRsp = 4981; - public static final int PrivateChatSetSequenceReq = 4987; - public static final int PrivateChatSetSequenceRsp = 4982; - public static final int ProfilePictureChangeNotify = 4087; - public static final int ProjectorOptionReq = 813; - public static final int ProjectorOptionRsp = 842; - public static final int ProudSkillChangeNotify = 1055; - public static final int ProudSkillExtraLevelNotify = 1097; - public static final int ProudSkillUpgradeReq = 1049; - public static final int ProudSkillUpgradeRsp = 1082; - public static final int PSNBlackListNotify = 4078; - public static final int PSNFriendListNotify = 4089; - public static final int PSPlayerApplyEnterMpReq = 1837; - public static final int PSPlayerApplyEnterMpRsp = 1832; - public static final int PullPrivateChatReq = 4967; - public static final int PullPrivateChatRsp = 5035; - public static final int PullRecentChatReq = 4985; - public static final int PullRecentChatRsp = 4999; - public static final int PushTipsAllDataNotify = 2224; - public static final int PushTipsChangeNotify = 2238; - public static final int PushTipsReadFinishReq = 2206; - public static final int PushTipsReadFinishRsp = 2219; - public static final int QueryCodexMonsterBeKilledNumReq = 4207; - public static final int QueryCodexMonsterBeKilledNumRsp = 4205; - public static final int QueryPathReq = 2309; - public static final int QueryPathRsp = 2331; - public static final int QuestCreateEntityReq = 482; - public static final int QuestCreateEntityRsp = 455; - public static final int QuestDelNotify = 441; - public static final int QuestDestroyEntityReq = 427; - public static final int QuestDestroyEntityRsp = 407; - public static final int QuestDestroyNpcReq = 424; - public static final int QuestDestroyNpcRsp = 438; - public static final int QuestGlobalVarNotify = 411; - public static final int QuestListNotify = 409; - public static final int QuestListUpdateNotify = 431; - public static final int QuestProgressUpdateNotify = 445; - public static final int QuestTransmitReq = 422; - public static final int QuestTransmitRsp = 454; - public static final int QuestUpdateQuestTimeVarNotify = 484; - public static final int QuestUpdateQuestVarNotify = 463; - public static final int QuestUpdateQuestVarReq = 490; - public static final int QuestUpdateQuestVarRsp = 486; - public static final int QuickUseWidgetReq = 4251; - public static final int QuickUseWidgetRsp = 4252; - public static final int ReadMailNotify = 1441; - public static final int ReadPrivateChatReq = 5032; - public static final int ReadPrivateChatRsp = 5005; - public static final int ReceivedTrialAvatarActivityRewardReq = 2054; - public static final int ReceivedTrialAvatarActivityRewardRsp = 2199; - public static final int RechargeReq = 4118; - public static final int RechargeRsp = 4109; - public static final int RedeemLegendaryKeyReq = 436; - public static final int RedeemLegendaryKeyRsp = 428; - public static final int RefreshBackgroundAvatarReq = 1660; - public static final int RefreshBackgroundAvatarRsp = 1751; - public static final int RefreshRoguelikeDungeonCardReq = 8072; - public static final int RefreshRoguelikeDungeonCardRsp = 8644; - public static final int RegionSearchChangeRegionNotify = 5609; - public static final int RegionSearchNotify = 5618; - public static final int ReliquaryDecomposeReq = 615; - public static final int ReliquaryDecomposeRsp = 692; - public static final int ReliquaryPromoteReq = 612; - public static final int ReliquaryPromoteRsp = 658; - public static final int ReliquaryUpgradeReq = 606; - public static final int ReliquaryUpgradeRsp = 619; - public static final int RemoveBlacklistReq = 4013; - public static final int RemoveBlacklistRsp = 4042; - public static final int RemoveRandTaskInfoNotify = 193; - public static final int ReportFightAntiCheatNotify = 305; - public static final int ReportTrackingIOInfoNotify = 4126; - public static final int RequestLiveInfoReq = 858; - public static final int RequestLiveInfoRsp = 850; - public static final int ResinCardDataUpdateNotify = 4101; - public static final int ResinChangeNotify = 670; - public static final int RestartEffigyChallengeReq = 2023; - public static final int RestartEffigyChallengeRsp = 2133; - public static final int ReunionActivateNotify = 5065; - public static final int ReunionBriefInfoReq = 5068; - public static final int ReunionBriefInfoRsp = 5059; - public static final int ReunionDailyRefreshNotify = 5091; - public static final int ReunionPrivilegeChangeNotify = 5061; - public static final int ReunionSettleNotify = 5077; - public static final int RobotPushPlayerDataNotify = 30; - public static final int RogueCellUpdateNotify = 8022; - public static final int RogueDungeonPlayerCellChangeNotify = 8832; - public static final int RogueHealAvatarsReq = 8331; - public static final int RogueHealAvatarsRsp = 8937; - public static final int RoguelikeCardGachaNotify = 8618; - public static final int RoguelikeEffectDataNotify = 8606; - public static final int RoguelikeEffectViewReq = 8377; - public static final int RoguelikeEffectViewRsp = 8770; - public static final int RoguelikeGiveUpReq = 8988; - public static final int RoguelikeGiveUpRsp = 8009; - public static final int RoguelikeMistClearNotify = 8198; - public static final int RoguelikeRefreshCardCostUpdateNotify = 8912; - public static final int RoguelikeResourceBonusPropUpdateNotify = 8823; - public static final int RoguelikeRuneRecordUpdateNotify = 8497; - public static final int RoguelikeSelectAvatarAndEnterDungeonReq = 8975; - public static final int RoguelikeSelectAvatarAndEnterDungeonRsp = 8471; - public static final int RoguelikeTakeStageFirstPassRewardReq = 8205; - public static final int RoguelikeTakeStageFirstPassRewardRsp = 8409; - public static final int RogueResumeDungeonReq = 8417; - public static final int RogueResumeDungeonRsp = 8565; - public static final int RogueSwitchAvatarReq = 8930; - public static final int RogueSwitchAvatarRsp = 8556; - public static final int SalesmanDeliverItemReq = 2118; - public static final int SalesmanDeliverItemRsp = 2038; - public static final int SalesmanTakeRewardReq = 2007; - public static final int SalesmanTakeRewardRsp = 2100; - public static final int SalesmanTakeSpecialRewardReq = 2065; - public static final int SalesmanTakeSpecialRewardRsp = 2107; - public static final int SaveCoopDialogReq = 1991; - public static final int SaveCoopDialogRsp = 1955; - public static final int SaveMainCoopReq = 1993; - public static final int SaveMainCoopRsp = 1954; - public static final int SceneAreaUnlockNotify = 219; - public static final int SceneAreaWeatherNotify = 229; - public static final int SceneAudioNotify = 3430; - public static final int SceneAvatarStaminaStepReq = 282; - public static final int SceneAvatarStaminaStepRsp = 255; - public static final int SceneCreateEntityReq = 250; - public static final int SceneCreateEntityRsp = 220; - public static final int SceneDataNotify = 3117; - public static final int SceneDestroyEntityReq = 213; - public static final int SceneDestroyEntityRsp = 242; - public static final int SceneEntitiesMoveCombineNotify = 3298; - public static final int SceneEntitiesMovesReq = 240; - public static final int SceneEntitiesMovesRsp = 275; - public static final int SceneEntityAppearNotify = 217; - public static final int SceneEntityDisappearNotify = 285; - public static final int SceneEntityDrownReq = 212; - public static final int SceneEntityDrownRsp = 258; - public static final int SceneEntityMoveNotify = 227; - public static final int SceneEntityMoveReq = 235; - public static final int SceneEntityMoveRsp = 249; - public static final int SceneEntityUpdateNotify = 3089; - public static final int SceneForceLockNotify = 211; - public static final int SceneForceUnlockNotify = 201; - public static final int SceneGalleryInfoNotify = 5597; - public static final int SceneInitFinishReq = 237; - public static final int SceneInitFinishRsp = 232; - public static final int SceneKickPlayerNotify = 292; - public static final int SceneKickPlayerReq = 295; - public static final int SceneKickPlayerRsp = 215; - public static final int ScenePlayBattleInfoListNotify = 4447; - public static final int ScenePlayBattleInfoNotify = 4359; - public static final int ScenePlayBattleInterruptNotify = 4377; - public static final int ScenePlayBattleResultNotify = 4357; - public static final int ScenePlayBattleUidOpNotify = 4380; - public static final int ScenePlayerInfoNotify = 225; - public static final int ScenePlayerLocationNotify = 207; - public static final int ScenePlayerSoundNotify = 210; - public static final int ScenePlayGuestReplyInviteReq = 4435; - public static final int ScenePlayGuestReplyInviteRsp = 4385; - public static final int ScenePlayGuestReplyNotify = 4399; - public static final int ScenePlayInfoListNotify = 4405; - public static final int ScenePlayInviteResultNotify = 4432; - public static final int ScenePlayOutofRegionNotify = 4448; - public static final int ScenePlayOwnerCheckReq = 4381; - public static final int ScenePlayOwnerCheckRsp = 4391; - public static final int ScenePlayOwnerInviteNotify = 4367; - public static final int ScenePlayOwnerStartInviteReq = 4387; - public static final int ScenePlayOwnerStartInviteRsp = 4382; - public static final int ScenePointUnlockNotify = 290; - public static final int SceneRouteChangeNotify = 278; - public static final int SceneTeamUpdateNotify = 1699; - public static final int SceneTimeNotify = 262; - public static final int SceneTransToPointReq = 286; - public static final int SceneTransToPointRsp = 263; - public static final int SceneWeatherForcastReq = 3190; - public static final int SceneWeatherForcastRsp = 3063; - public static final int SeaLampCoinNotify = 2096; - public static final int SeaLampContributeItemReq = 2168; - public static final int SeaLampContributeItemRsp = 2159; - public static final int SeaLampFlyLampNotify = 2051; - public static final int SeaLampFlyLampReq = 2071; - public static final int SeaLampFlyLampRsp = 2019; - public static final int SeaLampPopularityNotify = 2112; - public static final int SeaLampTakeContributionRewardReq = 2069; - public static final int SeaLampTakeContributionRewardRsp = 2103; - public static final int SeaLampTakePhaseRewardReq = 2092; - public static final int SeaLampTakePhaseRewardRsp = 2160; - public static final int SealBattleBeginNotify = 273; - public static final int SealBattleEndNotify = 261; - public static final int SealBattleProgressNotify = 288; - public static final int SeeMonsterReq = 281; - public static final int SeeMonsterRsp = 264; - public static final int SelectAsterMidDifficultyReq = 2190; - public static final int SelectAsterMidDifficultyRsp = 2010; - public static final int SelectEffigyChallengeConditionReq = 2111; - public static final int SelectEffigyChallengeConditionRsp = 2068; - public static final int SelectRoguelikeDungeonCardReq = 8070; - public static final int SelectRoguelikeDungeonCardRsp = 8040; - public static final int SelectWorktopOptionReq = 832; - public static final int SelectWorktopOptionRsp = 817; - public static final int ServerAnnounceNotify = 2029; - public static final int ServerAnnounceRevokeNotify = 2141; - public static final int ServerBuffChangeNotify = 393; - public static final int ServerCondMeetQuestListUpdateNotify = 401; - public static final int ServerDisconnectClientNotify = 166; - public static final int ServerGlobalValueChangeNotify = 1130; - public static final int ServerLogNotify = 55; - public static final int ServerMessageNotify = 5709; - public static final int ServerTimeNotify = 82; - public static final int ServerUpdateGlobalValueNotify = 1107; - public static final int SetBattlePassViewedReq = 2637; - public static final int SetBattlePassViewedRsp = 2632; - public static final int SetChatEmojiCollectionReq = 4066; - public static final int SetChatEmojiCollectionRsp = 4048; - public static final int SetCoopChapterViewedReq = 1956; - public static final int SetCoopChapterViewedRsp = 1998; - public static final int SetCurExpeditionChallengeIdReq = 2130; - public static final int SetCurExpeditionChallengeIdRsp = 2093; - public static final int SetEntityClientDataNotify = 3375; - public static final int SetEquipLockStateReq = 604; - public static final int SetEquipLockStateRsp = 605; - public static final int SetFriendEnterHomeOptionReq = 4761; - public static final int SetFriendEnterHomeOptionRsp = 4590; - public static final int SetFriendRemarkNameReq = 4070; - public static final int SetFriendRemarkNameRsp = 4029; - public static final int SetH5ActivityRedDotTimestampReq = 5654; - public static final int SetH5ActivityRedDotTimestampRsp = 5678; - public static final int SetIsAutoUnlockSpecificEquipReq = 639; - public static final int SetIsAutoUnlockSpecificEquipRsp = 695; - public static final int SetLimitOptimizationNotify = 8194; - public static final int SetNameCardReq = 4006; - public static final int SetNameCardRsp = 4019; - public static final int SetOpenStateReq = 138; - public static final int SetOpenStateRsp = 106; - public static final int SetPlayerBirthdayReq = 4007; - public static final int SetPlayerBirthdayRsp = 4030; - public static final int SetPlayerBornDataReq = 198; - public static final int SetPlayerBornDataRsp = 145; - public static final int SetPlayerHeadImageReq = 4045; - public static final int SetPlayerHeadImageRsp = 4090; - public static final int SetPlayerNameReq = 163; - public static final int SetPlayerNameRsp = 124; - public static final int SetPlayerPropReq = 130; - public static final int SetPlayerPropRsp = 197; - public static final int SetPlayerSignatureReq = 4097; - public static final int SetPlayerSignatureRsp = 4098; - public static final int SetSceneWeatherAreaReq = 256; - public static final int SetSceneWeatherAreaRsp = 265; - public static final int SetUpAvatarTeamReq = 1753; - public static final int SetUpAvatarTeamRsp = 1664; - public static final int SetUpLunchBoxWidgetReq = 4297; - public static final int SetUpLunchBoxWidgetRsp = 4266; - public static final int SetWidgetSlotReq = 4269; - public static final int SetWidgetSlotRsp = 4260; - public static final int ShowClientGuideNotify = 3241; - public static final int ShowClientTutorialNotify = 3079; - public static final int ShowCommonTipsNotify = 3357; - public static final int ShowMessageNotify = 37; - public static final int ShowTemplateReminderNotify = 3011; - public static final int SignInInfoReq = 2541; - public static final int SignInInfoRsp = 2537; - public static final int SocialDataNotify = 4054; - public static final int SpringUseReq = 1623; - public static final int SpringUseRsp = 1733; - public static final int StartArenaChallengeLevelReq = 2154; - public static final int StartArenaChallengeLevelRsp = 2191; - public static final int StartBuoyantCombatGalleryReq = 9000; - public static final int StartBuoyantCombatGalleryRsp = 8364; - public static final int StartCoopPointReq = 1982; + public static final int PlayerGetForceQuitBanInfoRsp = 4197; + public static final int PlayerHomeCompInfoNotify = 4880; + public static final int PlayerInjectFixNotify = 132; + public static final int PlayerInvestigationAllInfoNotify = 1928; + public static final int PlayerInvestigationNotify = 1911; + public static final int PlayerInvestigationTargetNotify = 1929; + public static final int PlayerLevelRewardUpdateNotify = 200; + public static final int PlayerLoginReq = 112; + public static final int PlayerLoginRsp = 135; + public static final int PlayerLogoutNotify = 103; + public static final int PlayerLogoutReq = 107; + public static final int PlayerLogoutRsp = 121; + public static final int PlayerLuaShellNotify = 133; + public static final int PlayerMatchAgreedResultNotify = 4170; + public static final int PlayerMatchInfoNotify = 4175; + public static final int PlayerMatchStopNotify = 4181; + public static final int PlayerMatchSuccNotify = 4179; + public static final int PlayerOfferingDataNotify = 2923; + public static final int PlayerOfferingReq = 2907; + public static final int PlayerOfferingRsp = 2917; + public static final int PlayerPreEnterMpNotify = 1822; + public static final int PlayerPropChangeNotify = 139; + public static final int PlayerPropChangeReasonNotify = 1299; + public static final int PlayerPropNotify = 175; + public static final int PlayerQuitDungeonReq = 907; + public static final int PlayerQuitDungeonRsp = 921; + public static final int PlayerQuitFromHomeNotify = 4656; + public static final int PlayerQuitFromMpNotify = 1829; + public static final int PlayerRandomCookReq = 126; + public static final int PlayerRandomCookRsp = 163; + public static final int PlayerRechargeDataNotify = 4102; + public static final int PlayerReportReq = 4024; + public static final int PlayerReportRsp = 4056; + public static final int PlayerRoutineDataNotify = 3526; + public static final int PlayerSetLanguageReq = 142; + public static final int PlayerSetLanguageRsp = 130; + public static final int PlayerSetOnlyMPWithPSPlayerReq = 1820; + public static final int PlayerSetOnlyMPWithPSPlayerRsp = 1845; + public static final int PlayerSetPauseReq = 124; + public static final int PlayerSetPauseRsp = 156; + public static final int PlayerStartMatchReq = 4176; + public static final int PlayerStartMatchRsp = 4168; + public static final int PlayerStoreNotify = 672; + public static final int PlayerTimeNotify = 191; + public static final int PlayerWorldSceneInfoListNotify = 3129; + public static final int PostEnterSceneReq = 3312; + public static final int PostEnterSceneRsp = 3184; + public static final int PrivateChatNotify = 4962; + public static final int PrivateChatReq = 5022; + public static final int PrivateChatRsp = 5048; + public static final int PrivateChatSetSequenceReq = 4985; + public static final int PrivateChatSetSequenceRsp = 4957; + public static final int ProfilePictureChangeNotify = 4016; + public static final int ProjectorOptionReq = 863; + public static final int ProjectorOptionRsp = 895; + public static final int ProudSkillChangeNotify = 1031; + public static final int ProudSkillExtraLevelNotify = 1081; + public static final int ProudSkillUpgradeReq = 1073; + public static final int ProudSkillUpgradeRsp = 1099; + public static final int PullPrivateChatReq = 4971; + public static final int PullPrivateChatRsp = 4953; + public static final int PullRecentChatReq = 5040; + public static final int PullRecentChatRsp = 5023; + public static final int PushTipsAllDataNotify = 2222; + public static final int PushTipsChangeNotify = 2265; + public static final int PushTipsReadFinishReq = 2204; + public static final int PushTipsReadFinishRsp = 2293; + public static final int QueryCodexMonsterBeKilledNumReq = 4203; + public static final int QueryCodexMonsterBeKilledNumRsp = 4209; + public static final int QueryPathReq = 2372; + public static final int QueryPathRsp = 2398; + public static final int QuestCreateEntityReq = 499; + public static final int QuestCreateEntityRsp = 431; + public static final int QuestDelNotify = 412; + public static final int QuestDestroyEntityReq = 475; + public static final int QuestDestroyEntityRsp = 448; + public static final int QuestDestroyNpcReq = 422; + public static final int QuestDestroyNpcRsp = 465; + public static final int QuestGlobalVarNotify = 434; + public static final int QuestListNotify = 472; + public static final int QuestListUpdateNotify = 498; + public static final int QuestProgressUpdateNotify = 482; + public static final int QuestTransmitReq = 450; + public static final int QuestTransmitRsp = 443; + public static final int QuestUpdateQuestTimeVarNotify = 456; + public static final int QuestUpdateQuestVarNotify = 453; + public static final int QuestUpdateQuestVarReq = 447; + public static final int QuestUpdateQuestVarRsp = 439; + public static final int QuickUseWidgetReq = 4299; + public static final int QuickUseWidgetRsp = 4270; + public static final int ReadMailNotify = 1412; + public static final int ReadPrivateChatReq = 5049; + public static final int ReadPrivateChatRsp = 4981; + public static final int ReceivedTrialAvatarActivityRewardReq = 2130; + public static final int ReceivedTrialAvatarActivityRewardRsp = 2076; + public static final int RechargeReq = 4126; + public static final int RechargeRsp = 4118; + public static final int RedeemLegendaryKeyReq = 446; + public static final int RedeemLegendaryKeyRsp = 441; + public static final int RefreshBackgroundAvatarReq = 1743; + public static final int RefreshBackgroundAvatarRsp = 1800; + public static final int RefreshRoguelikeDungeonCardReq = 8279; + public static final int RefreshRoguelikeDungeonCardRsp = 8349; + public static final int RegionSearchChangeRegionNotify = 5618; + public static final int RegionSearchNotify = 5626; + public static final int ReliquaryDecomposeReq = 638; + public static final int ReliquaryDecomposeRsp = 611; + public static final int ReliquaryPromoteReq = 627; + public static final int ReliquaryPromoteRsp = 694; + public static final int ReliquaryUpgradeReq = 604; + public static final int ReliquaryUpgradeRsp = 693; + public static final int RemoveBlacklistReq = 4063; + public static final int RemoveBlacklistRsp = 4095; + public static final int RemoveRandTaskInfoNotify = 161; + public static final int ReportFightAntiCheatNotify = 368; + public static final int ReportTrackingIOInfoNotify = 4129; + public static final int RequestLiveInfoReq = 894; + public static final int RequestLiveInfoRsp = 888; + public static final int ResinCardDataUpdateNotify = 4149; + public static final int ResinChangeNotify = 642; + public static final int RestartEffigyChallengeReq = 2148; + public static final int RestartEffigyChallengeRsp = 2042; + public static final int ReunionActivateNotify = 5085; + public static final int ReunionBriefInfoReq = 5076; + public static final int ReunionBriefInfoRsp = 5068; + public static final int ReunionDailyRefreshNotify = 5100; + public static final int ReunionPrivilegeChangeNotify = 5098; + public static final int ReunionSettleNotify = 5073; + public static final int RobotPushPlayerDataNotify = 97; + public static final int RogueCellUpdateNotify = 8642; + public static final int RogueDungeonPlayerCellChangeNotify = 8347; + public static final int RogueHealAvatarsReq = 8947; + public static final int RogueHealAvatarsRsp = 8949; + public static final int RogueResumeDungeonReq = 8795; + public static final int RogueResumeDungeonRsp = 8647; + public static final int RogueSwitchAvatarReq = 8201; + public static final int RogueSwitchAvatarRsp = 8915; + public static final int RoguelikeCardGachaNotify = 8925; + public static final int RoguelikeEffectDataNotify = 8222; + public static final int RoguelikeEffectViewReq = 8528; + public static final int RoguelikeEffectViewRsp = 8639; + public static final int RoguelikeGiveUpReq = 8660; + public static final int RoguelikeGiveUpRsp = 8139; + public static final int RoguelikeMistClearNotify = 8324; + public static final int RoguelikeRefreshCardCostUpdateNotify = 8927; + public static final int RoguelikeResourceBonusPropUpdateNotify = 8555; + public static final int RoguelikeRuneRecordUpdateNotify = 8973; + public static final int RoguelikeSelectAvatarAndEnterDungeonReq = 8457; + public static final int RoguelikeSelectAvatarAndEnterDungeonRsp = 8538; + public static final int RoguelikeTakeStageFirstPassRewardReq = 8421; + public static final int RoguelikeTakeStageFirstPassRewardRsp = 8552; + public static final int SalesmanDeliverItemReq = 2138; + public static final int SalesmanDeliverItemRsp = 2104; + public static final int SalesmanTakeRewardReq = 2191; + public static final int SalesmanTakeRewardRsp = 2110; + public static final int SalesmanTakeSpecialRewardReq = 2145; + public static final int SalesmanTakeSpecialRewardRsp = 2124; + public static final int SaveCoopDialogReq = 2000; + public static final int SaveCoopDialogRsp = 1962; + public static final int SaveMainCoopReq = 1975; + public static final int SaveMainCoopRsp = 1957; + public static final int SceneAreaUnlockNotify = 293; + public static final int SceneAreaWeatherNotify = 230; + public static final int SceneAudioNotify = 3166; + public static final int SceneAvatarStaminaStepReq = 299; + public static final int SceneAvatarStaminaStepRsp = 231; + public static final int SceneCreateEntityReq = 288; + public static final int SceneCreateEntityRsp = 226; + public static final int SceneDataNotify = 3203; + public static final int SceneDestroyEntityReq = 263; + public static final int SceneDestroyEntityRsp = 295; + public static final int SceneEntitiesMoveCombineNotify = 3387; + public static final int SceneEntitiesMovesReq = 279; + public static final int SceneEntitiesMovesRsp = 255; + public static final int SceneEntityAppearNotify = 221; + public static final int SceneEntityDisappearNotify = 203; + public static final int SceneEntityDrownReq = 227; + public static final int SceneEntityDrownRsp = 294; + public static final int SceneEntityMoveNotify = 275; + public static final int SceneEntityMoveReq = 290; + public static final int SceneEntityMoveRsp = 273; + public static final int SceneEntityUpdateNotify = 3412; + public static final int SceneForceLockNotify = 234; + public static final int SceneForceUnlockNotify = 206; + public static final int SceneGalleryInfoNotify = 5581; + public static final int SceneInitFinishReq = 235; + public static final int SceneInitFinishRsp = 207; + public static final int SceneKickPlayerNotify = 211; + public static final int SceneKickPlayerReq = 264; + public static final int SceneKickPlayerRsp = 238; + public static final int ScenePlayBattleInfoListNotify = 4431; + public static final int ScenePlayBattleInfoNotify = 4422; + public static final int ScenePlayBattleInterruptNotify = 4425; + public static final int ScenePlayBattleResultNotify = 4398; + public static final int ScenePlayBattleUidOpNotify = 4447; + public static final int ScenePlayGuestReplyInviteReq = 4353; + public static final int ScenePlayGuestReplyInviteRsp = 4440; + public static final int ScenePlayGuestReplyNotify = 4423; + public static final int ScenePlayInfoListNotify = 4381; + public static final int ScenePlayInviteResultNotify = 4449; + public static final int ScenePlayOutofRegionNotify = 4355; + public static final int ScenePlayOwnerCheckReq = 4448; + public static final int ScenePlayOwnerCheckRsp = 4362; + public static final int ScenePlayOwnerInviteNotify = 4371; + public static final int ScenePlayOwnerStartInviteReq = 4385; + public static final int ScenePlayOwnerStartInviteRsp = 4357; + public static final int ScenePlayerInfoNotify = 267; + public static final int ScenePlayerLocationNotify = 248; + public static final int ScenePlayerSoundNotify = 233; + public static final int ScenePointUnlockNotify = 247; + public static final int SceneRouteChangeNotify = 240; + public static final int SceneTeamUpdateNotify = 1775; + public static final int SceneTimeNotify = 245; + public static final int SceneTransToPointReq = 239; + public static final int SceneTransToPointRsp = 253; + public static final int SceneWeatherForcastReq = 3110; + public static final int SceneWeatherForcastRsp = 3012; + public static final int SeaLampCoinNotify = 2114; + public static final int SeaLampContributeItemReq = 2123; + public static final int SeaLampContributeItemRsp = 2139; + public static final int SeaLampFlyLampNotify = 2105; + public static final int SeaLampFlyLampReq = 2199; + public static final int SeaLampFlyLampRsp = 2192; + public static final int SeaLampPopularityNotify = 2032; + public static final int SeaLampTakeContributionRewardReq = 2019; + public static final int SeaLampTakeContributionRewardRsp = 2177; + public static final int SeaLampTakePhaseRewardReq = 2176; + public static final int SeaLampTakePhaseRewardRsp = 2190; + public static final int SealBattleBeginNotify = 289; + public static final int SealBattleEndNotify = 259; + public static final int SealBattleProgressNotify = 232; + public static final int SeeMonsterReq = 228; + public static final int SeeMonsterRsp = 251; + public static final int SelectAsterMidDifficultyReq = 2134; + public static final int SelectAsterMidDifficultyRsp = 2180; + public static final int SelectEffigyChallengeConditionReq = 2064; + public static final int SelectEffigyChallengeConditionRsp = 2039; + public static final int SelectRoguelikeDungeonCardReq = 8085; + public static final int SelectRoguelikeDungeonCardRsp = 8138; + public static final int SelectWorktopOptionReq = 807; + public static final int SelectWorktopOptionRsp = 821; + public static final int ServerAnnounceNotify = 2197; + public static final int ServerAnnounceRevokeNotify = 2092; + public static final int ServerBuffChangeNotify = 361; + public static final int ServerCondMeetQuestListUpdateNotify = 406; + public static final int ServerDisconnectClientNotify = 184; + public static final int ServerGlobalValueChangeNotify = 1197; + public static final int ServerLogNotify = 31; + public static final int ServerMessageNotify = 5718; + public static final int ServerTimeNotify = 99; + public static final int ServerUpdateGlobalValueNotify = 1148; + public static final int SetBattlePassViewedReq = 2641; + public static final int SetBattlePassViewedRsp = 2642; + public static final int SetChatEmojiCollectionReq = 4084; + public static final int SetChatEmojiCollectionRsp = 4080; + public static final int SetCoopChapterViewedReq = 1965; + public static final int SetCoopChapterViewedRsp = 1963; + public static final int SetCurExpeditionChallengeIdReq = 2021; + public static final int SetCurExpeditionChallengeIdRsp = 2049; + public static final int SetEntityClientDataNotify = 3146; + public static final int SetEquipLockStateReq = 666; + public static final int SetEquipLockStateRsp = 668; + public static final int SetFriendEnterHomeOptionReq = 4494; + public static final int SetFriendEnterHomeOptionRsp = 4743; + public static final int SetFriendRemarkNameReq = 4042; + public static final int SetFriendRemarkNameRsp = 4030; + public static final int SetH5ActivityRedDotTimestampReq = 5657; + public static final int SetH5ActivityRedDotTimestampRsp = 5652; + public static final int SetIsAutoUnlockSpecificEquipReq = 620; + public static final int SetIsAutoUnlockSpecificEquipRsp = 664; + public static final int SetLimitOptimizationNotify = 8851; + public static final int SetNameCardReq = 4004; + public static final int SetNameCardRsp = 4093; + public static final int SetOpenStateReq = 165; + public static final int SetOpenStateRsp = 104; + public static final int SetPlayerBirthdayReq = 4048; + public static final int SetPlayerBirthdayRsp = 4097; + public static final int SetPlayerBornDataReq = 105; + public static final int SetPlayerBornDataRsp = 182; + public static final int SetPlayerHeadImageReq = 4082; + public static final int SetPlayerHeadImageRsp = 4047; + public static final int SetPlayerNameReq = 153; + public static final int SetPlayerNameRsp = 122; + public static final int SetPlayerPropReq = 197; + public static final int SetPlayerPropRsp = 181; + public static final int SetPlayerSignatureReq = 4081; + public static final int SetPlayerSignatureRsp = 4005; + public static final int SetSceneWeatherAreaReq = 254; + public static final int SetSceneWeatherAreaRsp = 283; + public static final int SetUpAvatarTeamReq = 1690; + public static final int SetUpAvatarTeamRsp = 1646; + public static final int SetUpLunchBoxWidgetReq = 4272; + public static final int SetUpLunchBoxWidgetRsp = 4294; + public static final int SetWidgetSlotReq = 4259; + public static final int SetWidgetSlotRsp = 4277; + public static final int ShowClientGuideNotify = 3005; + public static final int ShowClientTutorialNotify = 3305; + public static final int ShowCommonTipsNotify = 3352; + public static final int ShowMessageNotify = 35; + public static final int ShowTemplateReminderNotify = 3491; + public static final int SignInInfoReq = 2512; + public static final int SignInInfoRsp = 2535; + public static final int SocialDataNotify = 4043; + public static final int SpringUseReq = 1748; + public static final int SpringUseRsp = 1642; + public static final int StartArenaChallengeLevelReq = 2127; + public static final int StartArenaChallengeLevelRsp = 2125; + public static final int StartBuoyantCombatGalleryReq = 8732; + public static final int StartBuoyantCombatGalleryRsp = 8680; + public static final int StartCoopPointReq = 1992; public static final int StartCoopPointRsp = 1964; - public static final int StartEffigyChallengeReq = 2157; - public static final int StartEffigyChallengeRsp = 2008; - public static final int StartFishingReq = 5843; - public static final int StartFishingRsp = 5804; - public static final int StartRogueEliteCellChallengeReq = 8722; - public static final int StartRogueEliteCellChallengeRsp = 8876; - public static final int StartRogueNormalCellChallengeReq = 8456; - public static final int StartRogueNormalCellChallengeRsp = 8156; - public static final int StoreItemChangeNotify = 641; - public static final int StoreItemDelNotify = 637; - public static final int StoreWeightLimitNotify = 631; - public static final int SummerTimeFloatSignalPositionNotify = 8622; - public static final int SummerTimeFloatSignalUpdateNotify = 8333; - public static final int SummerTimeSprintBoatRestartReq = 8175; - public static final int SummerTimeSprintBoatRestartRsp = 8563; - public static final int SummerTimeSprintBoatSettleNotify = 8117; - public static final int SumoDungeonSettleNotify = 8426; - public static final int SumoEnterDungeonNotify = 8727; - public static final int SumoLeaveDungeonNotify = 8440; - public static final int SumoRestartDungeonReq = 8585; - public static final int SumoRestartDungeonRsp = 8628; - public static final int SumoSaveTeamReq = 8970; - public static final int SumoSaveTeamRsp = 8890; - public static final int SumoSelectTeamAndEnterDungeonReq = 8030; - public static final int SumoSelectTeamAndEnterDungeonRsp = 8915; - public static final int SumoSetNoSwitchPunishTimeNotify = 8269; - public static final int SumoSwitchTeamReq = 8400; - public static final int SumoSwitchTeamRsp = 8442; - public static final int SyncScenePlayTeamEntityNotify = 3096; - public static final int SyncTeamEntityNotify = 334; - public static final int TakeAchievementGoalRewardReq = 2678; - public static final int TakeAchievementGoalRewardRsp = 2653; - public static final int TakeAchievementRewardReq = 2693; - public static final int TakeAchievementRewardRsp = 2654; - public static final int TakeAsterSpecialRewardReq = 2174; - public static final int TakeAsterSpecialRewardRsp = 2035; - public static final int TakeBattlePassMissionPointReq = 2626; - public static final int TakeBattlePassMissionPointRsp = 2647; - public static final int TakeBattlePassRewardReq = 2628; - public static final int TakeBattlePassRewardRsp = 2603; - public static final int TakeCityReputationExploreRewardReq = 2830; - public static final int TakeCityReputationExploreRewardRsp = 2897; - public static final int TakeCityReputationLevelRewardReq = 2841; - public static final int TakeCityReputationLevelRewardRsp = 2837; - public static final int TakeCityReputationParentQuestReq = 2817; - public static final int TakeCityReputationParentQuestRsp = 2885; - public static final int TakeCompoundOutputReq = 146; - public static final int TakeCompoundOutputRsp = 133; - public static final int TakeCoopRewardReq = 1977; - public static final int TakeCoopRewardRsp = 1965; - public static final int TakeDeliveryDailyRewardReq = 2037; - public static final int TakeDeliveryDailyRewardRsp = 2083; - public static final int TakeEffigyFirstPassRewardReq = 2200; - public static final int TakeEffigyFirstPassRewardRsp = 2073; - public static final int TakeEffigyRewardReq = 2062; - public static final int TakeEffigyRewardRsp = 2110; - public static final int TakeFirstShareRewardReq = 4046; - public static final int TakeFirstShareRewardRsp = 4033; - public static final int TakeFurnitureMakeReq = 4768; - public static final int TakeFurnitureMakeRsp = 4599; - public static final int TakeHuntingOfferReq = 4318; - public static final int TakeHuntingOfferRsp = 4309; - public static final int TakeInvestigationRewardReq = 1925; - public static final int TakeInvestigationRewardRsp = 1903; - public static final int TakeInvestigationTargetRewardReq = 1901; - public static final int TakeInvestigationTargetRewardRsp = 1908; - public static final int TakeMaterialDeleteReturnReq = 660; - public static final int TakeMaterialDeleteReturnRsp = 677; - public static final int TakeoffEquipReq = 698; - public static final int TakeoffEquipRsp = 645; - public static final int TakeOfferingLevelRewardReq = 2903; - public static final int TakeOfferingLevelRewardRsp = 2902; - public static final int TakePlayerLevelRewardReq = 160; - public static final int TakePlayerLevelRewardRsp = 177; - public static final int TakeRegionSearchRewardReq = 5643; - public static final int TakeRegionSearchRewardRsp = 5604; - public static final int TakeResinCardDailyRewardReq = 4147; - public static final int TakeResinCardDailyRewardRsp = 4116; - public static final int TakeReunionFirstGiftRewardReq = 5093; - public static final int TakeReunionFirstGiftRewardRsp = 5054; - public static final int TakeReunionMissionRewardReq = 5082; + public static final int StartEffigyChallengeReq = 2169; + public static final int StartEffigyChallengeRsp = 2173; + public static final int StartFishingReq = 5825; + public static final int StartFishingRsp = 5807; + public static final int StartRogueEliteCellChallengeReq = 8242; + public static final int StartRogueEliteCellChallengeRsp = 8958; + public static final int StartRogueNormalCellChallengeReq = 8205; + public static final int StartRogueNormalCellChallengeRsp = 8036; + public static final int StoreItemChangeNotify = 612; + public static final int StoreItemDelNotify = 635; + public static final int StoreWeightLimitNotify = 698; + public static final int SummerTimeFloatSignalPositionNotify = 8077; + public static final int SummerTimeFloatSignalUpdateNotify = 8781; + public static final int SummerTimeSprintBoatRestartReq = 8410; + public static final int SummerTimeSprintBoatRestartRsp = 8356; + public static final int SummerTimeSprintBoatSettleNotify = 8651; + public static final int SumoDungeonSettleNotify = 8291; + public static final int SumoEnterDungeonNotify = 8013; + public static final int SumoLeaveDungeonNotify = 8640; + public static final int SumoRestartDungeonReq = 8612; + public static final int SumoRestartDungeonRsp = 8214; + public static final int SumoSaveTeamReq = 8313; + public static final int SumoSaveTeamRsp = 8319; + public static final int SumoSelectTeamAndEnterDungeonReq = 8215; + public static final int SumoSelectTeamAndEnterDungeonRsp = 8193; + public static final int SumoSetNoSwitchPunishTimeNotify = 8935; + public static final int SumoSwitchTeamReq = 8351; + public static final int SumoSwitchTeamRsp = 8525; + public static final int SyncScenePlayTeamEntityNotify = 3333; + public static final int SyncTeamEntityNotify = 317; + public static final int TakeAchievementGoalRewardReq = 2652; + public static final int TakeAchievementGoalRewardRsp = 2681; + public static final int TakeAchievementRewardReq = 2675; + public static final int TakeAchievementRewardRsp = 2657; + public static final int TakeAsterSpecialRewardReq = 2097; + public static final int TakeAsterSpecialRewardRsp = 2193; + public static final int TakeBattlePassMissionPointReq = 2629; + public static final int TakeBattlePassMissionPointRsp = 2622; + public static final int TakeBattlePassRewardReq = 2602; + public static final int TakeBattlePassRewardRsp = 2631; + public static final int TakeCityReputationExploreRewardReq = 2897; + public static final int TakeCityReputationExploreRewardRsp = 2881; + public static final int TakeCityReputationLevelRewardReq = 2812; + public static final int TakeCityReputationLevelRewardRsp = 2835; + public static final int TakeCityReputationParentQuestReq = 2821; + public static final int TakeCityReputationParentQuestRsp = 2803; + public static final int TakeCompoundOutputReq = 174; + public static final int TakeCompoundOutputRsp = 176; + public static final int TakeCoopRewardReq = 1973; + public static final int TakeCoopRewardRsp = 1985; + public static final int TakeDeliveryDailyRewardReq = 2121; + public static final int TakeDeliveryDailyRewardRsp = 2162; + public static final int TakeEffigyFirstPassRewardReq = 2196; + public static final int TakeEffigyFirstPassRewardRsp = 2061; + public static final int TakeEffigyRewardReq = 2040; + public static final int TakeEffigyRewardRsp = 2007; + public static final int TakeFirstShareRewardReq = 4074; + public static final int TakeFirstShareRewardRsp = 4076; + public static final int TakeFurnitureMakeReq = 4772; + public static final int TakeFurnitureMakeRsp = 4769; + public static final int TakeHuntingOfferReq = 4326; + public static final int TakeHuntingOfferRsp = 4318; + public static final int TakeInvestigationRewardReq = 1912; + public static final int TakeInvestigationRewardRsp = 1922; + public static final int TakeInvestigationTargetRewardReq = 1918; + public static final int TakeInvestigationTargetRewardRsp = 1916; + public static final int TakeMaterialDeleteReturnReq = 629; + public static final int TakeMaterialDeleteReturnRsp = 657; + public static final int TakeOfferingLevelRewardReq = 2919; + public static final int TakeOfferingLevelRewardRsp = 2911; + public static final int TakePlayerLevelRewardReq = 129; + public static final int TakePlayerLevelRewardRsp = 157; + public static final int TakeRegionSearchRewardReq = 5625; + public static final int TakeRegionSearchRewardRsp = 5607; + public static final int TakeResinCardDailyRewardReq = 4122; + public static final int TakeResinCardDailyRewardRsp = 4144; + public static final int TakeReunionFirstGiftRewardReq = 5075; + public static final int TakeReunionFirstGiftRewardRsp = 5057; + public static final int TakeReunionMissionRewardReq = 5092; public static final int TakeReunionMissionRewardRsp = 5064; - public static final int TakeReunionSignInRewardReq = 5076; - public static final int TakeReunionSignInRewardRsp = 5097; - public static final int TakeReunionWatcherRewardReq = 5052; - public static final int TakeReunionWatcherRewardRsp = 5063; - public static final int TaskVarNotify = 191; - public static final int TeamResonanceChangeNotify = 1045; - public static final int TowerAllDataReq = 2435; - public static final int TowerAllDataRsp = 2449; - public static final int TowerBriefDataNotify = 2409; - public static final int TowerBuffSelectReq = 2407; - public static final int TowerBuffSelectRsp = 2430; - public static final int TowerCurLevelRecordChangeNotify = 2441; - public static final int TowerDailyRewardProgressChangeNotify = 2437; - public static final int TowerEnterLevelReq = 2455; - public static final int TowerEnterLevelRsp = 2427; - public static final int TowerFloorRecordChangeNotify = 2431; - public static final int TowerGetFloorStarRewardReq = 2406; - public static final int TowerGetFloorStarRewardRsp = 2419; - public static final int TowerLevelEndNotify = 2442; - public static final int TowerLevelStarCondNotify = 2401; - public static final int TowerMiddleLevelChangeTeamNotify = 2411; - public static final int TowerRecordHandbookReq = 2422; - public static final int TowerRecordHandbookRsp = 2454; - public static final int TowerSurrenderReq = 2424; - public static final int TowerSurrenderRsp = 2438; - public static final int TowerTeamSelectReq = 2417; - public static final int TowerTeamSelectRsp = 2485; - public static final int TreasureMapBonusChallengeNotify = 2075; - public static final int TreasureMapCurrencyNotify = 2098; - public static final int TreasureMapDetectorDataNotify = 4291; - public static final int TreasureMapGuideTaskDoneNotify = 2088; - public static final int TreasureMapHostInfoNotify = 8206; - public static final int TreasureMapMpChallengeNotify = 2036; - public static final int TreasureMapPreTaskDoneNotify = 2055; - public static final int TreasureMapRegionActiveNotify = 2059; - public static final int TreasureMapRegionInfoNotify = 2106; - public static final int TrialAvatarFirstPassDungeonNotify = 2137; - public static final int TrialAvatarInDungeonIndexNotify = 2024; - public static final int TriggerCreateGadgetToEquipPartNotify = 322; - public static final int TriggerRoguelikeCurseNotify = 8235; - public static final int TriggerRoguelikeRuneReq = 8138; - public static final int TriggerRoguelikeRuneRsp = 8781; - public static final int TryEnterHomeReq = 4553; - public static final int TryEnterHomeRsp = 4610; - public static final int UnfreezeGroupLimitNotify = 3253; - public static final int UnionCmdNotify = 98; - public static final int UnlockAvatarTalentReq = 1009; - public static final int UnlockAvatarTalentRsp = 1031; - public static final int UnlockCoopChapterReq = 1952; - public static final int UnlockCoopChapterRsp = 1963; - public static final int UnlockedFurnitureFormulaDataNotify = 4680; - public static final int UnlockedFurnitureSuiteDataNotify = 4717; - public static final int UnlockNameCardNotify = 4001; - public static final int UnlockPersonalLineReq = 476; - public static final int UnlockPersonalLineRsp = 472; - public static final int UnlockTransPointReq = 3228; - public static final int UnlockTransPointRsp = 3101; - public static final int UnmarkEntityInMinMapNotify = 216; - public static final int UpdateAbilityCreatedMovingPlatformNotify = 897; - public static final int UpdatePlayerShowAvatarListReq = 4025; - public static final int UpdatePlayerShowAvatarListRsp = 4083; + public static final int TakeReunionSignInRewardReq = 5079; + public static final int TakeReunionSignInRewardRsp = 5072; + public static final int TakeReunionWatcherRewardReq = 5070; + public static final int TakeReunionWatcherRewardRsp = 5095; + public static final int TakeoffEquipReq = 605; + public static final int TakeoffEquipRsp = 682; + public static final int TaskVarNotify = 160; + public static final int TeamResonanceChangeNotify = 1082; + public static final int TowerAllDataReq = 2490; + public static final int TowerAllDataRsp = 2473; + public static final int TowerBriefDataNotify = 2472; + public static final int TowerBuffSelectReq = 2448; + public static final int TowerBuffSelectRsp = 2497; + public static final int TowerCurLevelRecordChangeNotify = 2412; + public static final int TowerDailyRewardProgressChangeNotify = 2435; + public static final int TowerEnterLevelReq = 2431; + public static final int TowerEnterLevelRsp = 2475; + public static final int TowerFloorRecordChangeNotify = 2498; + public static final int TowerGetFloorStarRewardReq = 2404; + public static final int TowerGetFloorStarRewardRsp = 2493; + public static final int TowerLevelEndNotify = 2495; + public static final int TowerLevelStarCondNotify = 2406; + public static final int TowerMiddleLevelChangeTeamNotify = 2434; + public static final int TowerRecordHandbookReq = 2450; + public static final int TowerRecordHandbookRsp = 2443; + public static final int TowerSurrenderReq = 2422; + public static final int TowerSurrenderRsp = 2465; + public static final int TowerTeamSelectReq = 2421; + public static final int TowerTeamSelectRsp = 2403; + public static final int TreasureMapBonusChallengeNotify = 2115; + public static final int TreasureMapCurrencyNotify = 2171; + public static final int TreasureMapDetectorDataNotify = 4300; + public static final int TreasureMapGuideTaskDoneNotify = 2119; + public static final int TreasureMapHostInfoNotify = 8681; + public static final int TreasureMapMpChallengeNotify = 2048; + public static final int TreasureMapPreTaskDoneNotify = 2152; + public static final int TreasureMapRegionActiveNotify = 2122; + public static final int TreasureMapRegionInfoNotify = 2185; + public static final int TrialAvatarFirstPassDungeonNotify = 2013; + public static final int TrialAvatarInDungeonIndexNotify = 2186; + public static final int TriggerCreateGadgetToEquipPartNotify = 350; + public static final int TriggerRoguelikeCurseNotify = 8412; + public static final int TriggerRoguelikeRuneReq = 8463; + public static final int TriggerRoguelikeRuneRsp = 8065; + public static final int TryEnterHomeReq = 4482; + public static final int TryEnterHomeRsp = 4653; + public static final int UnfreezeGroupLimitNotify = 3220; + public static final int UnionCmdNotify = 5; + public static final int Unk2200_DEHCEKCILAB_ClientNotify = 88; + public static final int Unk2700_AAHKMNNAFIH = 8231; + public static final int Unk2700_ACILPONNGGK_ClientReq = 4537; + public static final int Unk2700_ADBFKMECFNJ_ClientNotify = 6240; + public static final int Unk2700_AEEMJIMOPKD = 8481; + public static final int Unk2700_AHHFDDOGCNA = 8768; + public static final int Unk2700_AHOMMGBBIAH = 8066; + public static final int Unk2700_AIBHKIENDPF = 8147; + public static final int Unk2700_AIGKGLHBMCP_ServerRsp = 6244; + public static final int Unk2700_AIKOFHAKNPC = 8740; + public static final int Unk2700_AKIBKKOMBMC = 8120; + public static final int Unk2700_ALBPFHFJHHF_ClientReq = 6036; + public static final int Unk2700_ALFEKGABMAA = 8022; + public static final int Unk2700_AMOEOCPOMGJ_ClientReq = 6090; + public static final int Unk2700_ANEBALDAFJI = 8357; + public static final int Unk2700_ANGBJGAOMHF_ClientReq = 6344; + public static final int Unk2700_AOIJNFMIAIP = 8614; + public static final int Unk2700_APNHPEJCDMO = 8610; + public static final int Unk2700_APOBKAEHMEL = 8216; + public static final int Unk2700_BBLJNCKPKPN = 8192; + public static final int Unk2700_BBMKJGPMIOE = 8580; + public static final int Unk2700_BCFKCLHCBDI = 8419; + public static final int Unk2700_BCPHPHGOKGN = 8227; + public static final int Unk2700_BEDCCMDPNCH = 8499; + public static final int Unk2700_BEDLIGJANCJ_ClientReq = 4558; + public static final int Unk2700_BEINCMBJDAA_ClientReq = 333; + public static final int Unk2700_BKEELPKCHGO_ClientReq = 6209; + public static final int Unk2700_BKGPMAHMHIG = 8561; + public static final int Unk2700_BLCHNMCGJCJ = 8948; + public static final int Unk2700_BLFFJBMLAPI = 8772; + public static final int Unk2700_BLHIGLFDHFA_ServerNotify = 4654; + public static final int Unk2700_BLNOMGJJLOI = 8854; + public static final int Unk2700_BMDBBHFJMPF = 8178; + public static final int Unk2700_BNABFJBODGE = 8226; + public static final int Unk2700_BNCBHLOKDCD = 8602; + public static final int Unk2700_BNMDCEKPDMC = 8641; + public static final int Unk2700_BOEHCEAAKKA = 8921; + public static final int Unk2700_BOPIJJPNHCK = 8590; + public static final int Unk2700_BPFNCHEFKJM = 8449; + public static final int Unk2700_BPPDLOJLAAO = 8280; + public static final int Unk2700_CALNMMBNKFD = 8502; + public static final int Unk2700_CAODHBDOGNE = 8597; + public static final int Unk2700_CBGOFDNILKA = 8159; + public static final int Unk2700_CCCKFHICDHD_ClientNotify = 3314; + public static final int Unk2700_CEEONDKDIHH_ClientReq = 6213; + public static final int Unk2700_CFLKEDHFPAB = 8143; + public static final int Unk2700_CGNFBKKBPJE = 8240; + public static final int Unk2700_CHICHNGLKPI = 8149; + public static final int Unk2700_CILGDLMHCNG_ServerNotify = 1951; + public static final int Unk2700_CIOMEDJDPBP_ClientReq = 6342; + public static final int Unk2700_CJKCCLEGPCM = 8153; + public static final int Unk2700_CLKGPNDKIDD = 8725; + public static final int Unk2700_CLMGFEOPNFH = 8938; + public static final int Unk2700_CNEIMEHAAAF = 8903; + public static final int Unk2700_CNNJKJFHGGD = 8264; + public static final int Unk2700_COGBIJAPDLE = 8535; + public static final int Unk2700_CPDDDMPAIDL = 8817; + public static final int Unk2700_CPEMGFIMICD = 8588; + public static final int Unk2700_DAGJNGODABM_ClientReq = 6329; + public static final int Unk2700_DBPDHLEGOLB = 8127; + public static final int Unk2700_DCBEFDDECOJ = 8858; + public static final int Unk2700_DCKKCAJCNKP_ServerRsp = 6207; + public static final int Unk2700_DDAHPHCEIIM = 8144; + public static final int Unk2700_DDLBKAMGGEE_ServerRsp = 6215; + public static final int Unk2700_DFOHGHKAIBO = 8442; + public static final int Unk2700_DGLIANMBMPA = 8342; + public static final int Unk2700_DJMKFGKGAEA = 8411; + public static final int Unk2700_DLAEFMAMIIJ = 8844; + public static final int Unk2700_EAAGDFHHNMJ_ServerReq = 1105; + public static final int Unk2700_EAAMIOAFNOD_ServerRsp = 4064; + public static final int Unk2700_EAGIANJBNGK_ClientReq = 151; + public static final int Unk2700_EAOAMGDLJMP = 8617; + public static final int Unk2700_EBJCAMGPFDB = 8838; + public static final int Unk2700_EBOECOIFJMP = 8717; + public static final int Unk2700_ECBEAMKBGMD_ClientReq = 6235; + public static final int Unk2700_EDCIENBEEDI = 8919; + public static final int Unk2700_EDDNHJPJBBF = 8733; + public static final int Unk2700_EDMCLPMBEMH = 8387; + public static final int Unk2700_EELPPGCAKHL = 8373; + public static final int Unk2700_EHAMOPKCIGI_ServerNotify = 4805; + public static final int Unk2700_EHFBIEDHILL = 8882; + public static final int Unk2700_EJHALNBHHHD_ServerRsp = 6322; + public static final int Unk2700_EJIOFGEEIOM = 8837; + public static final int Unk2700_EKBMEKPHJGK = 8726; + public static final int Unk2700_EMHAHHAKOGA = 8163; + public static final int Unk2700_FADPOMMGLCH = 8918; + public static final int Unk2700_FCLBOLKPMGK = 8753; + public static final int Unk2700_FDJBLKOBFIH = 8334; + public static final int Unk2700_FEODEAEOOKE = 8507; + public static final int Unk2700_FFMAKIPBPHE = 8989; + public static final int Unk2700_FFOBMLOCPMH_ClientNotify = 6211; + public static final int Unk2700_FGEEFFLBAKO = 8546; + public static final int Unk2700_FGJBPNIKNDE = 8398; + public static final int Unk2700_FIODAJPNBIK = 8937; + public static final int Unk2700_FJEHHCPCBLG_ServerNotify = 4872; + public static final int Unk2700_FJJFKOEACCE = 8450; + public static final int Unk2700_FKCDCGCBIEA_ServerNotify = 6276; + public static final int Unk2700_FKMOKPBJIKO = 8482; + public static final int Unk2700_FLGMLEFJHBB_ClientReq = 6210; + public static final int Unk2700_FMNAGFKECPL_ClientReq = 6222; + public static final int Unk2700_FNHKFHGNLPP_ServerRsp = 6248; + public static final int Unk2700_FNJHJKELICK = 8119; + public static final int Unk2700_FOOOKMANFPE_ClientReq = 6249; + public static final int Unk2700_FPCJGEOBADP_ServerRsp = 6204; + public static final int Unk2700_FPJLFMEHHLB_ServerNotify = 4060; + public static final int Unk2700_FPOBGEBDAOD_ServerNotify = 5547; + public static final int Unk2700_GBJOLBGLELJ = 8014; + public static final int Unk2700_GDODKDJJPMP_ServerRsp = 4605; + public static final int Unk2700_GECHLGFKPOD_ServerNotify = 5364; + public static final int Unk2700_GEIGCHNDOAA = 8657; + public static final int Unk2700_GFMPOHAGMLO_ClientReq = 6250; + public static final int Unk2700_GIAILDLPEOO_ServerRsp = 6241; + public static final int Unk2700_GIFGEDBCPFC_ServerRsp = 417; + public static final int Unk2700_GIFKPMNGNGB = 8608; + public static final int Unk2700_GKHEKGMFBJN = 8688; + public static final int Unk2700_GKKNFMNJFDP = 8261; + public static final int Unk2700_GLAPMLGHDDC_ClientReq = 5960; + public static final int Unk2700_GLIILNDIPLK_ServerNotify = 6341; + public static final int Unk2700_GLLIEOABOML = 8057; + public static final int Unk2700_GMNGEEBMABP = 8352; + public static final int Unk2700_GNDOKLHDHBJ_ClientReq = 6245; + public static final int Unk2700_GNOAKIGLPCG = 8991; + public static final int Unk2700_GNPPPIHBDLJ = 8709; + public static final int Unk2700_GPHLCIAMDFG = 8095; + public static final int Unk2700_GPIHGEEKBOO_ClientReq = 6233; + public static final int Unk2700_GPOIPAHPHJE = 8967; + public static final int Unk2700_HBLAGOMHKPL_ClientRsp = 137; + public static final int Unk2700_HBOFACHAGIF_ServerNotify = 9072; + public static final int Unk2700_HDBFJJOBIAP_ClientReq = 6325; + public static final int Unk2700_HFCDIGNAAPJ = 8129; + public static final int Unk2700_HGMCBHFFDLJ = 8826; + public static final int Unk2700_HGMOIKODALP_ServerRsp = 6220; + public static final int Unk2700_HHGMCHANCBJ_ServerNotify = 6217; + public static final int Unk2700_HIIFAMCBJCD_ServerRsp = 4206; + public static final int Unk2700_HJKOHHGBMJP = 8933; + public static final int Unk2700_HKADKMFMBPG = 8017; + public static final int Unk2700_HMFCCGCKHCA = 8946; + public static final int Unk2700_HMHHLEHFBLB = 8713; + public static final int Unk2700_HMMFPDMLGEM = 8554; + public static final int Unk2700_HNFGBBECGMJ = 8607; + public static final int Unk2700_HOPDLJLBKIC_ServerRsp = 6056; + public static final int Unk2700_IAADLJBLOIN_ServerNotify = 4092; + public static final int Unk2700_IAAPADOAMIA = 8414; + public static final int Unk2700_IACKJNNMCAC_ClientReq = 4523; + public static final int Unk2700_IBOKDNKBMII = 8825; + public static final int Unk2700_ICABIPHHPKE = 8028; + public static final int Unk2700_IDADEMGCJBF_ClientNotify = 6243; + public static final int Unk2700_IDAGMLJOJMP = 8799; + public static final int Unk2700_IDGCNKONBBJ = 8793; + public static final int Unk2700_IEFAGBHIODK = 8402; + public static final int Unk2700_IEGOOOECBFH = 8880; + public static final int Unk2700_IGPIIHEDJLJ_ServerRsp = 6218; + public static final int Unk2700_IHLONDFBCOE_ClientReq = 6320; + public static final int Unk2700_IHOOCHJACEL = 8325; + public static final int Unk2700_IHPFBKANGMJ = 8771; + public static final int Unk2700_IJFEPCBOLDF = 8756; + public static final int Unk2700_IJLANPFECKC = 8277; + public static final int Unk2700_ILBBAKACCHA_ClientReq = 470; + public static final int Unk2700_ILLDDDFLKHP = 8959; + public static final int Unk2700_IMHNKDHHGMA = 8186; + public static final int Unk2700_INBDPOIMAHK_ClientReq = 6242; + public static final int Unk2700_INOMEGGAGOP = 8132; + public static final int Unk2700_IPGJEAEFJMM_ServerRsp = 6318; + public static final int Unk2700_JCKGJAELBMB = 8704; + public static final int Unk2700_JCOECJGPNOL_ServerRsp = 5929; + public static final int Unk2700_JDMPECKFGIG_ServerNotify = 4639; + public static final int Unk2700_JEFIMHGLOJF = 8096; + public static final int Unk2700_JEHIAJHHIMP_ServerNotify = 109; + public static final int Unk2700_JFGFIDBPGBK = 8381; + public static final int Unk2700_JHMIHJFFJBO = 8862; + public static final int Unk2700_JJAFAJIKDDK_ServerRsp = 6307; + public static final int Unk2700_JJCDNAHAPKD_ClientReq = 6226; + public static final int Unk2700_JKFGMBAMNDA_ServerNotify = 5320; + public static final int Unk2700_JKOKBPFCILA_ClientReq = 467; + public static final int Unk2700_JLOFMANHGHI_ClientReq = 6247; + public static final int Unk2700_JNCINBLCNNL = 8696; + public static final int Unk2700_JOHOODKBINN_ClientReq = 4256; + public static final int Unk2700_JPLFIOOMCGG = 8142; + public static final int Unk2700_KAJNLGIDKAB_ServerRsp = 4289; + public static final int Unk2700_KDDPDHGPGEF_ServerRsp = 123; + public static final int Unk2700_KDFNIGOBLEK = 8308; + public static final int Unk2700_KDNNKELPJFL = 8777; + public static final int Unk2700_KEMOFNEAOOO_ClientRsp = 1182; + public static final int Unk2700_KFPEIHHCCLA = 8978; + public static final int Unk2700_KGHOJPDNMKK_ServerRsp = 4641; + public static final int Unk2700_KGNJIBIMAHI = 8842; + public static final int Unk2700_KHLJJPGOELG_ClientReq = 6225; + public static final int Unk2700_KIHEEAGDGIL_ServerNotify = 108; + public static final int Unk2700_KIIOGMKFNNP_ServerRsp = 4615; + public static final int Unk2700_KKEDIMOKCGD = 8218; + public static final int Unk2700_KMIDCPLAGMN = 8848; + public static final int Unk2700_KMNPMLCHELD_ServerRsp = 6201; + public static final int Unk2700_KNGFOEKOODA_ServerRsp = 2163; + public static final int Unk2700_KNMDFCBLIIG_ServerRsp = 384; + public static final int Unk2700_KOGOPPONCHB_ClientReq = 4208; + public static final int Unk2700_KPGMEMHEEMD = 8185; + public static final int Unk2700_KPMMEBNMMCL = 8363; + public static final int Unk2700_LAFHGMOPCCM_ServerNotify = 5553; + public static final int Unk2700_LBJKLAGNDEJ_ClientReq = 4759; + public static final int Unk2700_LBOPCDPFJEC = 8062; + public static final int Unk2700_LCFGKHHIAEH_ServerNotify = 4014; + public static final int Unk2700_LDJLMCAHHEN = 8748; + public static final int Unk2700_LEMPLKGOOJC = 8362; + public static final int Unk2700_LGAGHFKFFDO_ServerRsp = 6349; + public static final int Unk2700_LGGAIDMLDIA_ServerReq = 177; + public static final int Unk2700_LGHJBAEBJKE_ServerRsp = 6227; + public static final int Unk2700_LHMOFCJCIKM = 9000; + public static final int Unk2700_LIJCBOBECHJ = 8964; + public static final int Unk2700_LJINJNECBIA = 8113; + public static final int Unk2700_LKFKCNJFGIF_ServerRsp = 458; + public static final int Unk2700_LKPBBMPFPPE_ClientReq = 6326; + public static final int Unk2700_LLBCBPADBNO = 8154; + public static final int Unk2700_LMAKABBJNLN = 8253; + public static final int Unk2700_LNBBLNNPNBE_ServerNotify = 4583; + public static final int Unk2700_LNMFIHNFKOO = 8572; + public static final int Unk2700_LOHBMOKOPLH_ServerNotify = 4608; + public static final int Unk2700_LPMIMLCNEDA = 8518; + public static final int Unk2700_MBIAJKLACBG = 5757; + public static final int Unk2700_MCJIOOELGHG_ServerNotify = 6033; + public static final int Unk2700_MCOFAKMDMEF_ServerRsp = 6345; + public static final int Unk2700_MDGKMNEBIBA = 8038; + public static final int Unk2700_MDPHLPEGFCG_ClientReq = 4020; + public static final int Unk2700_MEBFPBDNPGO_ServerNotify = 4847; + public static final int Unk2700_MEFJECGAFNH_ServerNotify = 5338; + public static final int Unk2700_MENCEGPEFAK = 8791; + public static final int Unk2700_MFAIPHGDPBL = 8345; + public static final int Unk2700_MFINCDMFGLD_ServerNotify = 152; + public static final int Unk2700_MHMBDFKOOLJ_ClientNotify = 6234; + public static final int Unk2700_MIBHNLEMICB = 8462; + public static final int Unk2700_MIEJMGNBPJE = 8377; + public static final int Unk2700_MJAIKMBPKCD = 8569; + public static final int Unk2700_MJCCKKHJNMP_ServerRsp = 6212; + public static final int Unk2700_MKAFBOPFDEF_ServerNotify = 430; + public static final int Unk2700_MKLLNAHEJJC_ServerRsp = 4287; + public static final int Unk2700_MKMDOIKBBEP = 8026; + public static final int Unk2700_MLMJFIGJJEH_ServerNotify = 4878; + public static final int Unk2700_MMDCAFMGACC_ServerNotify = 6221; + public static final int Unk2700_MMFIJILOCOP_ClientReq = 4486; + public static final int Unk2700_MNIBEMEMGMO = 8514; + public static final int Unk2700_MPPAHFFHIPI_ServerNotify = 4187; + public static final int Unk2700_NAEHEDLGLKA = 8257; + public static final int Unk2700_NBFJOJPCCEK_ServerRsp = 6057; + public static final int Unk2700_NBFOJLAHFCA_ServerNotify = 5928; + public static final int Unk2700_NCJLMACGOCD_ClientNotify = 933; + public static final int Unk2700_NCMPMILICGJ = 8407; + public static final int Unk2700_NCPLKHGCOAH = 8767; + public static final int Unk2700_NDDBFNNHLFE = 8340; + public static final int Unk2700_NEHPMNPAAKC = 8806; + public static final int Unk2700_NELNFCMDMHE_ServerRsp = 6314; + public static final int Unk2700_NFGNGFLNOOJ_ServerNotify = 4811; + public static final int Unk2700_NGEKONFLEBB = 8703; + public static final int Unk2700_NGPMINKIOPK = 8956; + public static final int Unk2700_NIMPHALPEPO_ClientNotify = 6236; + public static final int Unk2700_NINHGODEMHH_ServerNotify = 2155; + public static final int Unk2700_NJNMEFINDCF = 8093; + public static final int Unk2700_NKIEIGPLMIO = 8459; + public static final int Unk2700_NLBJHDNKPCC = 8626; + public static final int Unk2700_NLJBCGILMIE = 8281; + public static final int Unk2700_NMEENGOJOKD = 8930; + public static final int Unk2700_NMJCGMOOIFP = 8061; + public static final int Unk2700_NMJIMIKKIME = 8943; + public static final int Unk2700_NNDKOICOGGH_ServerNotify = 5539; + public static final int Unk2700_NNMDBDNIMHN_ServerRsp = 4538; + public static final int Unk2700_OBCKNDBAPGE = 8072; + public static final int Unk2700_OBDHJJHLIKJ = 8523; + public static final int Unk2700_OCAJADDLPBB = 8718; + public static final int Unk2700_ODBNBICOCFK = 8054; + public static final int Unk2700_ODJKHILOILK = 8067; + public static final int Unk2700_OEDLCGKNGLH = 8686; + public static final int Unk2700_OFDBHGHAJBD_ServerNotify = 6223; + public static final int Unk2700_OGHMHELMBNN_ServerRsp = 4488; + public static final int Unk2700_OHDDPIFAPPD = 8125; + public static final int Unk2700_OHIKIOLLMHM = 8233; + public static final int Unk2700_OJHJBKHIPLA_ClientReq = 2009; + public static final int Unk2700_OJLJMJLKNGJ_ClientReq = 6203; + public static final int Unk2700_OKEKCGDGPDA = 8396; + public static final int Unk2700_OKNDIGOKMMC = 8426; + public static final int Unk2700_OLKJCGDHENH = 8343; + public static final int Unk2700_ONKMCKLJNAL = 8401; + public static final int Unk2700_PBGBOLJMIIB = 8924; + public static final int Unk2700_PCBGAIAJPHH = 8758; + public static final int Unk2700_PDGJFHAGMKD = 8447; + public static final int Unk2700_PFFKAEPBEHE_ServerRsp = 6214; + public static final int Unk2700_PFOLNOBIKFB = 8833; + public static final int Unk2700_PHFADCJDBOF = 8559; + public static final int Unk2700_PHLEDBIFIFL = 8165; + public static final int Unk2700_PIEJLIIGLGM_ServerRsp = 6237; + public static final int Unk2700_PIEJMALFKIF = 8531; + public static final int Unk2700_PJCMAELKFEP = 8367; + public static final int Unk2700_PJPMOLPHNEH = 8895; + public static final int Unk2700_PKCLMDHHPFI = 8423; + public static final int Unk2700_PKKJEOFNLCF = 8983; + public static final int Unk2700_PMKNJBJPLBH = 8385; + public static final int Unk2700_PPBALCAKIBD = 8273; + public static final int Unk2700_PPOGMFAKBMK_ServerRsp = 6219; + public static final int Unk2800_ACHELBEEBIP = 21800; + public static final int Unk2800_ANGFAFEJBAE = 846; + public static final int Unk2800_BDAPFODFMNE = 24550; + public static final int Unk2800_BOFEHJBJELJ = 8574; + public static final int Unk2800_CHEDEMEDPPM = 5565; + public static final int Unk2800_COCHLKHLCPO = 23467; + public static final int Unk2800_DKDJCLLNGNL = 8346; + public static final int Unk2800_DNKCFLKHKJG = 876; + public static final int Unk2800_DPINLADLBFA = 1902; + public static final int Unk2800_ECCLDPCADCJ = 1921; + public static final int Unk2800_EKGCCBDIKFI = 21851; + public static final int Unk2800_FHCJIICLONO = 21025; + public static final int Unk2800_GDDLBKEENNA = 24601; + public static final int Unk2800_HHPCNJGKIPP = 23388; + public static final int Unk2800_HKBAEOMCFOD = 145; + public static final int Unk2800_IBDOMAIDPGK = 5594; + public static final int Unk2800_IECLGDFOMFJ = 8513; + public static final int Unk2800_IGKGDAGGCEC = 1684; + public static final int Unk2800_IILBEPIEBJO = 8476; + public static final int Unk2800_ILKIAECAAKG = 3004; + public static final int Unk2800_JCPNICABMAF = 5504; + public static final int Unk2800_KFNCDHFHJPD = 8996; + public static final int Unk2800_KHLHFFHGEHA = 21834; + public static final int Unk2800_KILFIICJLEE = 5593; + public static final int Unk2800_KJEOLFNEOPF = 1768; + public static final int Unk2800_KOMBBIEEGCP = 5522; + public static final int Unk2800_KPJKAJLNAED = 874; + public static final int Unk2800_LGIKLPBOJOI = 8145; + public static final int Unk2800_LIBCDGDJMDF = 5527; + public static final int Unk2800_MNBDNGKGDGF = 8004; + public static final int Unk2800_NHEOHBNFHJD = 8870; + public static final int Unk2800_OFIHDGFMDGB = 171; + public static final int Unk2800_OMGNOBICOCD = 843; + public static final int Unk2800_OOKIPFHPJMG = 21054; + public static final int UnlockAvatarTalentReq = 1072; + public static final int UnlockAvatarTalentRsp = 1098; + public static final int UnlockCoopChapterReq = 1970; + public static final int UnlockCoopChapterRsp = 1995; + public static final int UnlockNameCardNotify = 4006; + public static final int UnlockPersonalLineReq = 449; + public static final int UnlockPersonalLineRsp = 491; + public static final int UnlockTransPointReq = 3035; + public static final int UnlockTransPointRsp = 3426; + public static final int UnlockedFurnitureFormulaDataNotify = 4846; + public static final int UnlockedFurnitureSuiteDataNotify = 4454; + public static final int UnmarkEntityInMinMapNotify = 219; + public static final int UpdateAbilityCreatedMovingPlatformNotify = 881; + public static final int UpdatePS4BlockListReq = 4046; + public static final int UpdatePS4BlockListRsp = 4041; + public static final int UpdatePS4FriendListNotify = 4039; + public static final int UpdatePS4FriendListReq = 4089; + public static final int UpdatePS4FriendListRsp = 4059; + public static final int UpdatePlayerShowAvatarListReq = 4067; + public static final int UpdatePlayerShowAvatarListRsp = 4058; public static final int UpdatePlayerShowNameCardListReq = 4002; - public static final int UpdatePlayerShowNameCardListRsp = 4016; - public static final int UpdatePS4BlockListReq = 4036; - public static final int UpdatePS4BlockListRsp = 4028; - public static final int UpdatePS4FriendListNotify = 4086; - public static final int UpdatePS4FriendListReq = 4073; - public static final int UpdatePS4FriendListRsp = 4061; - public static final int UpdateRedPointNotify = 19; - public static final int UpdateReunionWatcherNotify = 5087; - public static final int UpgradeRoguelikeShikigamiReq = 8422; - public static final int UpgradeRoguelikeShikigamiRsp = 8671; - public static final int UseItemReq = 635; - public static final int UseItemRsp = 649; - public static final int UseMiracleRingReq = 5218; - public static final int UseMiracleRingRsp = 5209; - public static final int UseWidgetCreateGadgetReq = 4283; - public static final int UseWidgetCreateGadgetRsp = 4279; - public static final int UseWidgetRetractGadgetReq = 4290; - public static final int UseWidgetRetractGadgetRsp = 4271; - public static final int VehicleInteractReq = 838; - public static final int VehicleInteractRsp = 806; - public static final int VehicleStaminaNotify = 811; - public static final int ViewCodexReq = 4203; - public static final int ViewCodexRsp = 4202; - public static final int WatcherAllDataNotify = 2209; - public static final int WatcherChangeNotify = 2231; - public static final int WatcherEventNotify = 2241; - public static final int WatcherEventTypeNotify = 2237; - public static final int WaterSpritePhaseFinishNotify = 2028; - public static final int WeaponAwakenReq = 642; - public static final int WeaponAwakenRsp = 601; - public static final int WeaponPromoteReq = 624; - public static final int WeaponPromoteRsp = 638; - public static final int WeaponUpgradeReq = 686; - public static final int WeaponUpgradeRsp = 663; - public static final int WearEquipReq = 630; - public static final int WearEquipRsp = 697; - public static final int WidgetActiveChangeNotify = 4295; - public static final int WidgetCoolDownNotify = 4263; - public static final int WidgetDoBagReq = 4284; - public static final int WidgetDoBagRsp = 4286; - public static final int WidgetGadgetAllDataNotify = 4285; - public static final int WidgetGadgetDataNotify = 4292; - public static final int WidgetGadgetDestroyNotify = 4275; - public static final int WidgetReportReq = 4287; - public static final int WidgetReportRsp = 4282; - public static final int WidgetSlotChangeNotify = 4274; - public static final int WidgetUseAttachAbilityGroupChangeNotify = 4299; - public static final int WindSeedClientNotify = 1182; - public static final int WorktopOptionNotify = 837; - public static final int WorldAllRoutineTypeNotify = 3509; - public static final int WorldDataNotify = 3131; - public static final int WorldOwnerBlossomBriefInfoNotify = 2737; - public static final int WorldOwnerBlossomScheduleInfoNotify = 2732; + public static final int UpdatePlayerShowNameCardListRsp = 4019; + public static final int UpdateRedPointNotify = 93; + public static final int UpdateReunionWatcherNotify = 5091; + public static final int UpgradeRoguelikeShikigamiReq = 8151; + public static final int UpgradeRoguelikeShikigamiRsp = 8966; + public static final int UseItemReq = 690; + public static final int UseItemRsp = 673; + public static final int UseMiracleRingReq = 5226; + public static final int UseMiracleRingRsp = 5218; + public static final int UseWidgetCreateGadgetReq = 4293; + public static final int UseWidgetCreateGadgetRsp = 4290; + public static final int UseWidgetRetractGadgetReq = 4286; + public static final int UseWidgetRetractGadgetRsp = 4261; + public static final int VehicleInteractReq = 865; + public static final int VehicleInteractRsp = 804; + public static final int VehicleStaminaNotify = 834; + public static final int ViewCodexReq = 4202; + public static final int ViewCodexRsp = 4201; + public static final int WatcherAllDataNotify = 2272; + public static final int WatcherChangeNotify = 2298; + public static final int WatcherEventNotify = 2212; + public static final int WatcherEventTypeNotify = 2235; + public static final int WaterSpritePhaseFinishNotify = 2025; + public static final int WeaponAwakenReq = 695; + public static final int WeaponAwakenRsp = 606; + public static final int WeaponPromoteReq = 622; + public static final int WeaponPromoteRsp = 665; + public static final int WeaponUpgradeReq = 639; + public static final int WeaponUpgradeRsp = 653; + public static final int WearEquipReq = 697; + public static final int WearEquipRsp = 681; + public static final int WidgetActiveChangeNotify = 4280; + public static final int WidgetCoolDownNotify = 4295; + public static final int WidgetDoBagReq = 4255; + public static final int WidgetDoBagRsp = 4296; + public static final int WidgetGadgetAllDataNotify = 4284; + public static final int WidgetGadgetDataNotify = 4266; + public static final int WidgetGadgetDestroyNotify = 4274; + public static final int WidgetReportReq = 4291; + public static final int WidgetReportRsp = 4292; + public static final int WidgetSlotChangeNotify = 4267; + public static final int WidgetUseAttachAbilityGroupChangeNotify = 4258; + public static final int WindSeedClientNotify = 1199; + public static final int WorktopOptionNotify = 835; + public static final int WorldAllRoutineTypeNotify = 3518; + public static final int WorldDataNotify = 3308; + public static final int WorldOwnerBlossomBriefInfoNotify = 2735; + public static final int WorldOwnerBlossomScheduleInfoNotify = 2707; public static final int WorldOwnerDailyTaskNotify = 102; - public static final int WorldPlayerDieNotify = 296; - public static final int WorldPlayerInfoNotify = 3304; - public static final int WorldPlayerLocationNotify = 283; - public static final int WorldPlayerReviveReq = 247; - public static final int WorldPlayerReviveRsp = 280; - public static final int WorldPlayerRTTNotify = 24; - public static final int WorldRoutineChangeNotify = 3504; - public static final int WorldRoutineTypeCloseNotify = 3528; - public static final int WorldRoutineTypeRefreshNotify = 3543; + public static final int WorldPlayerDieNotify = 285; + public static final int WorldPlayerInfoNotify = 3116; + public static final int WorldPlayerLocationNotify = 258; + public static final int WorldPlayerRTTNotify = 22; + public static final int WorldPlayerReviveReq = 225; + public static final int WorldPlayerReviveRsp = 278; + public static final int WorldRoutineChangeNotify = 3507; + public static final int WorldRoutineTypeCloseNotify = 3502; + public static final int WorldRoutineTypeRefreshNotify = 3525; - // Unknown + // Unknown - public static final HashSet BANNED_PACKETS = new HashSet() {{ - add(PacketOpcodes.WindSeedClientNotify); - add(PacketOpcodes.PlayerLuaShellNotify); - }}; -} + public static final HashSet BANNED_PACKETS = new HashSet<>() { + { + this.add(PacketOpcodes.WindSeedClientNotify); + this.add(PacketOpcodes.PlayerLuaShellNotify); + } + }; +} \ No newline at end of file From 42e3af4e3930bce0a679cc1d509bd6283da02bf6 Mon Sep 17 00:00:00 2001 From: AnimeGitB Date: Wed, 13 Jul 2022 11:39:49 +0930 Subject: [PATCH 08/61] QueryPathReq update From bc2c5deb482fb6ace5a1a23715b4597f92cdf258 Mon Sep 17 00:00:00 2001 From: AnimeGitB Date: Wed, 13 Jul 2022 12:03:57 +0930 Subject: [PATCH 09/61] Add Dispatch Password authentication --- .../auth/DefaultAuthentication.java | 21 +- .../auth/DefaultAuthenticators.java | 180 +++++++++++++++--- .../command/commands/AccountCommand.java | 73 ++++++- .../grasscutter/server/http/HttpServer.java | 7 +- .../server/http/dispatch/RegionHandler.java | 117 ++++++++---- .../http/objects/QueryCurRegionRspJson.java | 6 + .../packet/recv/HandlerGetPlayerTokenReq.java | 52 ++++- .../packet/send/PacketGetPlayerTokenRsp.java | 105 ++++++---- .../emu/grasscutter/utils/ByteHelper.java | 24 +++ .../grasscutter/utils/ConfigContainer.java | 2 + .../java/emu/grasscutter/utils/Crypto.java | 35 +++- src/main/resources/languages/en-US.json | 5 + 12 files changed, 503 insertions(+), 124 deletions(-) create mode 100644 src/main/java/emu/grasscutter/server/http/objects/QueryCurRegionRspJson.java create mode 100644 src/main/java/emu/grasscutter/utils/ByteHelper.java diff --git a/src/main/java/emu/grasscutter/auth/DefaultAuthentication.java b/src/main/java/emu/grasscutter/auth/DefaultAuthentication.java index efe637530..51f0684ba 100644 --- a/src/main/java/emu/grasscutter/auth/DefaultAuthentication.java +++ b/src/main/java/emu/grasscutter/auth/DefaultAuthentication.java @@ -6,6 +6,7 @@ import emu.grasscutter.game.Account; import emu.grasscutter.server.http.objects.ComboTokenResJson; import emu.grasscutter.server.http.objects.LoginResultJson; +import static emu.grasscutter.Configuration.ACCOUNT; import static emu.grasscutter.utils.Language.translate; /** @@ -13,12 +14,20 @@ import static emu.grasscutter.utils.Language.translate; * Allows all users to access any account. */ public final class DefaultAuthentication implements AuthenticationSystem { - private final Authenticator passwordAuthenticator = new PasswordAuthenticator(); - private final Authenticator tokenAuthenticator = new TokenAuthenticator(); - private final Authenticator sessionKeyAuthenticator = new SessionKeyAuthenticator(); - private final ExternalAuthenticator externalAuthenticator = new ExternalAuthentication(); - private final OAuthAuthenticator oAuthAuthenticator = new OAuthAuthentication(); - + private Authenticator passwordAuthenticator; + private Authenticator tokenAuthenticator = new TokenAuthenticator(); + private Authenticator sessionKeyAuthenticator = new SessionKeyAuthenticator(); + private ExternalAuthenticator externalAuthenticator = new ExternalAuthentication(); + private OAuthAuthenticator oAuthAuthenticator = new OAuthAuthentication(); + + public DefaultAuthentication() { + if(ACCOUNT.EXPERIMENTAL_RealPassword) { + passwordAuthenticator = new ExperimentalPasswordAuthenticator(); + } else { + passwordAuthenticator = new PasswordAuthenticator(); + } + } + @Override public void createAccount(String username, String password) { // Unhandled. The default authenticator doesn't store passwords. diff --git a/src/main/java/emu/grasscutter/auth/DefaultAuthenticators.java b/src/main/java/emu/grasscutter/auth/DefaultAuthenticators.java index 905535380..6c5585ec8 100644 --- a/src/main/java/emu/grasscutter/auth/DefaultAuthenticators.java +++ b/src/main/java/emu/grasscutter/auth/DefaultAuthenticators.java @@ -1,10 +1,19 @@ package emu.grasscutter.auth; +import at.favre.lib.crypto.bcrypt.BCrypt; import emu.grasscutter.Grasscutter; import emu.grasscutter.auth.AuthenticationSystem.AuthenticationRequest; import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.game.Account; import emu.grasscutter.server.http.objects.*; +import emu.grasscutter.utils.FileUtils; +import emu.grasscutter.utils.Utils; + +import javax.crypto.Cipher; +import java.nio.charset.StandardCharsets; +import java.security.KeyFactory; +import java.security.interfaces.RSAPrivateKey; +import java.security.spec.PKCS8EncodedKeySpec; import static emu.grasscutter.Configuration.*; import static emu.grasscutter.utils.Language.translate; @@ -13,19 +22,20 @@ import static emu.grasscutter.utils.Language.translate; * A class containing default authenticators. */ public final class DefaultAuthenticators { - + /** * Handles the authentication request from the username and password form. */ public static class PasswordAuthenticator implements Authenticator { - @Override public LoginResultJson authenticate(AuthenticationRequest request) { + @Override + public LoginResultJson authenticate(AuthenticationRequest request) { var response = new LoginResultJson(); - + var requestData = request.getPasswordRequest(); assert requestData != null; // This should never be null. int playerCount = Grasscutter.getGameServer().getPlayers().size(); - boolean successfulLogin = false; + boolean successfulLogin = false; String address = request.getRequest().ip(); String responseMessage = translate("messages.dispatch.account.username_error"); String loggerMessage = ""; @@ -34,12 +44,12 @@ public final class DefaultAuthenticators { Account account = DatabaseHelper.getAccountByName(requestData.account); if (ACCOUNT.maxPlayer <= -1 || playerCount < ACCOUNT.maxPlayer) { // Check if account exists. - if(account == null && ACCOUNT.autoCreate) { + if (account == null && ACCOUNT.autoCreate) { // This account has been created AUTOMATICALLY. There will be no permissions added. account = DatabaseHelper.createAccountWithUid(requestData.account, 0); // Check if the account was created successfully. - if(account == null) { + if (account == null) { responseMessage = translate("messages.dispatch.account.username_create_error"); Grasscutter.getLogger().info(translate("messages.dispatch.account.account_login_create_error", address)); } else { @@ -49,9 +59,9 @@ public final class DefaultAuthenticators { // Log the creation. Grasscutter.getLogger().info(translate("messages.dispatch.account.account_login_create_success", address, response.data.account.uid)); } - } else if(account != null) + } else if (account != null) successfulLogin = true; - else + else loggerMessage = translate("messages.dispatch.account.account_login_exist_error", address); } else { @@ -59,9 +69,120 @@ public final class DefaultAuthenticators { loggerMessage = translate("messages.dispatch.account.login_max_player_limit", address); } - + // Set response data. - if(successfulLogin) { + if (successfulLogin) { + response.message = "OK"; + response.data.account.uid = account.getId(); + response.data.account.token = account.generateSessionKey(); + response.data.account.email = account.getEmail(); + + loggerMessage = translate("messages.dispatch.account.login_success", address, account.getId()); + } else { + response.retcode = -201; + response.message = responseMessage; + + } + Grasscutter.getLogger().info(loggerMessage); + + return response; + } + } + + public static class ExperimentalPasswordAuthenticator implements Authenticator { + @Override + public LoginResultJson authenticate(AuthenticationRequest request) { + var response = new LoginResultJson(); + + var requestData = request.getPasswordRequest(); + assert requestData != null; // This should never be null. + int playerCount = Grasscutter.getGameServer().getPlayers().size(); + + boolean successfulLogin = false; + String address = request.getRequest().ip(); + String responseMessage = translate("messages.dispatch.account.username_error"); + String loggerMessage = ""; + String decryptedPassword = ""; + + // Get Password + if (GAME_OPTIONS.uaPatchCompatible) { + // Make sure your patch can send passwords in plain text + decryptedPassword = request.getPasswordRequest().password; + } else { + try { + byte[] key = FileUtils.readResource("/keys/auth_private-key.der"); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(key); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + RSAPrivateKey private_key = (RSAPrivateKey) keyFactory.generatePrivate(keySpec); + + Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + + cipher.init(Cipher.DECRYPT_MODE, private_key); + + decryptedPassword = new String(cipher.doFinal(Utils.base64Decode(request.getPasswordRequest().password)), StandardCharsets.UTF_8); + } catch (Exception ignored) { + ignored.printStackTrace(); + } + } + + if (decryptedPassword == null) { + successfulLogin = false; + loggerMessage = translate("messages.dispatch.account.login_password_error", address); + responseMessage = translate("messages.dispatch.account.password_error"); + } + + // Get account from database. + Account account = DatabaseHelper.getAccountByName(requestData.account); + if (ACCOUNT.maxPlayer <= -1 || playerCount < ACCOUNT.maxPlayer) { + // Check if account exists. + if (account == null && ACCOUNT.autoCreate) { + // This account has been created AUTOMATICALLY. There will be no permissions added. + if (decryptedPassword.length() >= 8) { + account = DatabaseHelper.createAccountWithUid(requestData.account, 0); + account.setPassword(BCrypt.withDefaults().hashToString(12, decryptedPassword.toCharArray())); + account.save(); + + // Check if the account was created successfully. + if (account == null) { + responseMessage = translate("messages.dispatch.account.username_create_error"); + loggerMessage = translate("messages.dispatch.account.account_login_create_error", address); + } else { + // Continue with login. + successfulLogin = true; + + // Log the creation. + Grasscutter.getLogger().info(translate("messages.dispatch.account.account_login_create_success", address, response.data.account.uid)); + } + } else { + successfulLogin = false; + loggerMessage = translate("messages.dispatch.account.login_password_error", address); + responseMessage = translate("messages.dispatch.account.password_length_error"); + } + } else if (account != null) { + if (account.getPassword() != null && !account.getPassword().isEmpty()) { + if (BCrypt.verifyer().verify(decryptedPassword.toCharArray(), account.getPassword()).verified) { + successfulLogin = true; + } else { + successfulLogin = false; + loggerMessage = translate("messages.dispatch.account.login_password_error", address); + responseMessage = translate("messages.dispatch.account.password_error"); + } + } else { + successfulLogin = false; + loggerMessage = translate("messages.dispatch.account.login_password_storage_error", address); + responseMessage = translate("password_storage_error"); + } + } else { + loggerMessage = translate("messages.dispatch.account.account_login_exist_error", address); + } + } else { + responseMessage = translate("messages.dispatch.account.server_max_player_limit"); + loggerMessage = translate("messages.dispatch.account.login_max_player_limit", address); + } + + + // Set response data. + if (successfulLogin) { response.message = "OK"; response.data.account.uid = account.getId(); response.data.account.token = account.generateSessionKey(); @@ -83,9 +204,10 @@ public final class DefaultAuthenticators { * Handles the authentication request from the game when using a registry token. */ public static class TokenAuthenticator implements Authenticator { - @Override public LoginResultJson authenticate(AuthenticationRequest request) { + @Override + public LoginResultJson authenticate(AuthenticationRequest request) { var response = new LoginResultJson(); - + var requestData = request.getTokenRequest(); assert requestData != null; @@ -106,7 +228,7 @@ public final class DefaultAuthenticators { successfulLogin = account != null && account.getSessionKey().equals(requestData.token); // Set response data. - if(successfulLogin) { + if (successfulLogin) { response.message = "OK"; response.data.account.uid = account.getId(); response.data.account.token = account.getSessionKey(); @@ -138,13 +260,15 @@ public final class DefaultAuthenticators { * Handles the authentication request from the game when using a combo token/session key. */ public static class SessionKeyAuthenticator implements Authenticator { - @Override public ComboTokenResJson authenticate(AuthenticationRequest request) { - var response = new ComboTokenResJson(); - + @Override + public ComboTokenResJson authenticate(AuthenticationRequest request) { + var response = new ComboTokenResJson(); + var requestData = request.getSessionKeyRequest(); var loginData = request.getSessionKeyData(); - assert requestData != null; assert loginData != null; - + assert requestData != null; + assert loginData != null; + boolean successfulLogin; String address = request.getRequest().ip(); String loggerMessage; @@ -158,7 +282,7 @@ public final class DefaultAuthenticators { successfulLogin = account != null && account.getSessionKey().equals(loginData.token); // Set response data. - if(successfulLogin) { + if (successfulLogin) { response.message = "OK"; response.data.open_id = account.getId(); response.data.combo_id = "157795300"; @@ -190,17 +314,20 @@ public final class DefaultAuthenticators { * Handles authentication requests from external sources. */ public static class ExternalAuthentication implements ExternalAuthenticator { - @Override public void handleLogin(AuthenticationRequest request) { + @Override + public void handleLogin(AuthenticationRequest request) { assert request.getResponse() != null; request.getResponse().send("Authentication is not available with the default authentication method."); } - @Override public void handleAccountCreation(AuthenticationRequest request) { + @Override + public void handleAccountCreation(AuthenticationRequest request) { assert request.getResponse() != null; request.getResponse().send("Authentication is not available with the default authentication method."); } - @Override public void handlePasswordReset(AuthenticationRequest request) { + @Override + public void handlePasswordReset(AuthenticationRequest request) { assert request.getResponse() != null; request.getResponse().send("Authentication is not available with the default authentication method."); } @@ -210,17 +337,20 @@ public final class DefaultAuthenticators { * Handles authentication requests from OAuth sources. */ public static class OAuthAuthentication implements OAuthAuthenticator { - @Override public void handleLogin(AuthenticationRequest request) { + @Override + public void handleLogin(AuthenticationRequest request) { assert request.getResponse() != null; request.getResponse().send("Authentication is not available with the default authentication method."); } - @Override public void handleRedirection(AuthenticationRequest request, ClientType type) { + @Override + public void handleRedirection(AuthenticationRequest request, ClientType type) { assert request.getResponse() != null; request.getResponse().send("Authentication is not available with the default authentication method."); } - @Override public void handleTokenProcess(AuthenticationRequest request) { + @Override + public void handleTokenProcess(AuthenticationRequest request) { assert request.getResponse() != null; request.getResponse().send("Authentication is not available with the default authentication method."); } diff --git a/src/main/java/emu/grasscutter/command/commands/AccountCommand.java b/src/main/java/emu/grasscutter/command/commands/AccountCommand.java index 0d50b3787..4f96b986f 100644 --- a/src/main/java/emu/grasscutter/command/commands/AccountCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/AccountCommand.java @@ -1,5 +1,7 @@ package emu.grasscutter.command.commands; +import at.favre.lib.crypto.bcrypt.BCrypt; +import emu.grasscutter.Configuration; import emu.grasscutter.Grasscutter; import emu.grasscutter.command.Command; import emu.grasscutter.command.CommandHandler; @@ -11,7 +13,7 @@ import java.util.List; import static emu.grasscutter.utils.Language.translate; -@Command(label = "account", usage = "account [uid]", description = "commands.account.description", targetRequirement = Command.TargetRequirement.NONE) +@Command(label = "account", usage = "account [uid|password] [uid] ", description = "commands.account.description", targetRequirement = Command.TargetRequirement.NONE) public final class AccountCommand implements CommandHandler { @Override @@ -35,13 +37,38 @@ public final class AccountCommand implements CommandHandler { return; case "create": int uid = 0; - if (args.size() > 2) { - try { - uid = Integer.parseInt(args.get(2)); - } catch (NumberFormatException ignored) { - CommandHandler.sendMessage(null, translate(sender, "commands.account.invalid")); + String password = ""; + + if(Configuration.ACCOUNT.EXPERIMENTAL_RealPassword == true) { + if(args.size() < 3) { + CommandHandler.sendMessage(null, "EXPERIMENTAL_RealPassword requires a password argument"); + CommandHandler.sendMessage(null, "Usage: account create [uid]"); + return; } + password = args.get(2); + + if (args.size() == 4) { + try { + uid = Integer.parseInt(args.get(3)); + } catch (NumberFormatException ignored) { + CommandHandler.sendMessage(null, translate(sender, "commands.account.invalid")); + if(Configuration.ACCOUNT.EXPERIMENTAL_RealPassword == true) { + CommandHandler.sendMessage(null, "EXPERIMENTAL_RealPassword requires argument 2 to be a password, not a uid"); + CommandHandler.sendMessage(null, "Usage: account create [uid]"); + } + return; + } + } + } else { + if (args.size() > 2) { + try { + uid = Integer.parseInt(args.get(2)); + } catch (NumberFormatException ignored) { + CommandHandler.sendMessage(null, translate(sender, "commands.account.invalid")); + return; + } + } } emu.grasscutter.game.Account account = DatabaseHelper.createAccountWithUid(username, uid); @@ -49,6 +76,9 @@ public final class AccountCommand implements CommandHandler { CommandHandler.sendMessage(null, translate(sender, "commands.account.exists")); return; } else { + if(Configuration.ACCOUNT.EXPERIMENTAL_RealPassword == true) { + account.setPassword(BCrypt.withDefaults().hashToString(12, password.toCharArray())); + } account.addPermission("*"); account.save(); // Save account to database. @@ -74,6 +104,37 @@ public final class AccountCommand implements CommandHandler { // Finally, we do the actual deletion. DatabaseHelper.deleteAccount(toDelete); CommandHandler.sendMessage(null, translate(sender, "commands.account.delete")); + return; + case "resetpass": + if(Configuration.ACCOUNT.EXPERIMENTAL_RealPassword != true) { + CommandHandler.sendMessage(null, "resetpass requires EXPERIMENTAL_RealPassword to be true."); + return; + } + + if(args.size() != 3) { + CommandHandler.sendMessage(null, "Invalid Args"); + CommandHandler.sendMessage(null, "Usage: account resetpass "); + return; + } + + Account toUpdate = DatabaseHelper.getAccountByName(username); + + if (toUpdate == null) { + CommandHandler.sendMessage(null, translate(sender, "commands.account.no_account")); + return; + } + + // Get the player for the account. + // If that player is currently online, we kick them before proceeding with the deletion. + Player uPlayer = Grasscutter.getGameServer().getPlayerByAccountId(toUpdate.getId()); + if (uPlayer != null) { + uPlayer.getSession().close(); + } + + toUpdate.setPassword(BCrypt.withDefaults().hashToString(12, args.get(2).toCharArray())); + toUpdate.save(); + CommandHandler.sendMessage(null, "Password Updated."); + return; } } } diff --git a/src/main/java/emu/grasscutter/server/http/HttpServer.java b/src/main/java/emu/grasscutter/server/http/HttpServer.java index bcc020ed7..34d2059a1 100644 --- a/src/main/java/emu/grasscutter/server/http/HttpServer.java +++ b/src/main/java/emu/grasscutter/server/http/HttpServer.java @@ -11,7 +11,7 @@ import org.eclipse.jetty.server.ServerConnector; import org.eclipse.jetty.util.ssl.SslContextFactory; import java.io.File; -import java.io.IOException; +import java.io.UnsupportedEncodingException; import static emu.grasscutter.Configuration.*; import static emu.grasscutter.utils.Language.translate; @@ -126,15 +126,16 @@ public final class HttpServer { /** * Starts listening on the HTTP server. + * @throws UnsupportedEncodingException */ - public void start() { + public void start() throws UnsupportedEncodingException { // Attempt to start the HTTP server. if(HTTP_INFO.bindAddress.equals("")){ this.express.listen(HTTP_INFO.bindPort); }else{ this.express.listen(HTTP_INFO.bindAddress, HTTP_INFO.bindPort); } - + // Log bind information. Grasscutter.getLogger().info(translate("messages.dispatch.port_bind", Integer.toString(this.express.raw().port()))); } diff --git a/src/main/java/emu/grasscutter/server/http/dispatch/RegionHandler.java b/src/main/java/emu/grasscutter/server/http/dispatch/RegionHandler.java index f2d1cc4ca..c1fdfc7a0 100644 --- a/src/main/java/emu/grasscutter/server/http/dispatch/RegionHandler.java +++ b/src/main/java/emu/grasscutter/server/http/dispatch/RegionHandler.java @@ -1,33 +1,31 @@ package emu.grasscutter.server.http.dispatch; import com.google.protobuf.ByteString; -import com.google.protobuf.InvalidProtocolBufferException; import emu.grasscutter.Grasscutter; import emu.grasscutter.Grasscutter.ServerRunMode; -import emu.grasscutter.net.proto.QueryCurrRegionHttpRspOuterClass.*; -import emu.grasscutter.net.proto.RegionInfoOuterClass; +import emu.grasscutter.net.proto.QueryCurrRegionHttpRspOuterClass.QueryCurrRegionHttpRsp; import emu.grasscutter.net.proto.RegionInfoOuterClass.RegionInfo; import emu.grasscutter.net.proto.RegionSimpleInfoOuterClass.RegionSimpleInfo; import emu.grasscutter.server.event.dispatch.QueryAllRegionsEvent; import emu.grasscutter.server.event.dispatch.QueryCurrentRegionEvent; import emu.grasscutter.server.http.Router; +import emu.grasscutter.server.http.objects.QueryCurRegionRspJson; import emu.grasscutter.utils.Crypto; -import emu.grasscutter.utils.FileUtils; import emu.grasscutter.utils.Utils; import express.Express; import express.http.Request; import express.http.Response; import io.javalin.Javalin; -import java.io.File; -import java.util.ArrayList; -import java.util.Base64; -import java.util.List; -import java.util.Map; +import javax.crypto.Cipher; +import java.io.ByteArrayOutputStream; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; +import java.security.Signature; + import static emu.grasscutter.Configuration.*; -import static emu.grasscutter.net.proto.QueryRegionListHttpRspOuterClass.*; +import static emu.grasscutter.net.proto.QueryRegionListHttpRspOuterClass.QueryRegionListHttpRsp; /** * Handles requests related to region queries. @@ -35,7 +33,7 @@ import static emu.grasscutter.net.proto.QueryRegionListHttpRspOuterClass.*; public final class RegionHandler implements Router { private static final Map regions = new ConcurrentHashMap<>(); private static String regionListResponse; - + public RegionHandler() { try { // Read & initialize region data. this.initialize(); @@ -51,33 +49,33 @@ public final class RegionHandler implements Router { String dispatchDomain = "http" + (HTTP_ENCRYPTION.useInRouting ? "s" : "") + "://" + lr(HTTP_INFO.accessAddress, HTTP_INFO.bindAddress) + ":" + lr(HTTP_INFO.accessPort, HTTP_INFO.bindPort); - + // Create regions. List servers = new ArrayList<>(); List usedNames = new ArrayList<>(); // List to check for potential naming conflicts. - + var configuredRegions = new ArrayList<>(List.of(DISPATCH_INFO.regions)); if(SERVER.runMode != ServerRunMode.HYBRID && configuredRegions.size() == 0) { Grasscutter.getLogger().error("[Dispatch] There are no game servers available. Exiting due to unplayable state."); System.exit(1); - } else if (configuredRegions.size() == 0) + } else if (configuredRegions.size() == 0) configuredRegions.add(new Region("os_usa", DISPATCH_INFO.defaultName, - lr(GAME_INFO.accessAddress, GAME_INFO.bindAddress), - lr(GAME_INFO.accessPort, GAME_INFO.bindPort))); - + lr(GAME_INFO.accessAddress, GAME_INFO.bindAddress), + lr(GAME_INFO.accessPort, GAME_INFO.bindPort))); + configuredRegions.forEach(region -> { if (usedNames.contains(region.Name)) { Grasscutter.getLogger().error("Region name already in use."); return; } - + // Create a region identifier. var identifier = RegionSimpleInfo.newBuilder() .setName(region.Name).setTitle(region.Title).setType("DEV_PUBLIC") .setDispatchUrl(dispatchDomain + "/query_cur_region/" + region.Name) .build(); usedNames.add(region.Name); servers.add(identifier); - + // Create a region info object. var regionInfo = RegionInfo.newBuilder() .setGateserverIp(region.Ip).setGateserverPort(region.Port) @@ -87,22 +85,22 @@ public final class RegionHandler implements Router { var updatedQuery = QueryCurrRegionHttpRsp.newBuilder().setRegionInfo(regionInfo).build(); regions.put(region.Name, new RegionData(updatedQuery, Utils.base64Encode(updatedQuery.toByteString().toByteArray()))); }); - + // Create a config object. byte[] customConfig = "{\"sdkenv\":\"2\",\"checkdevice\":\"false\",\"loadPatch\":\"false\",\"showexception\":\"false\",\"regionConfig\":\"pm|fk|add\",\"downloadMode\":\"0\"}".getBytes(); Crypto.xor(customConfig, Crypto.DISPATCH_KEY); // XOR the config with the key. - + // Create an updated region list. QueryRegionListHttpRsp updatedRegionList = QueryRegionListHttpRsp.newBuilder() .addAllRegionList(servers) .setClientSecretKey(ByteString.copyFrom(Crypto.DISPATCH_SEED)) .setClientCustomConfigEncrypted(ByteString.copyFrom(customConfig)) .setEnableLoginPc(true).build(); - + // Set the region list response. regionListResponse = Utils.base64Encode(updatedRegionList.toByteString().toByteArray()); } - + @Override public void applyRoutes(Express express, Javalin handle) { express.get("/query_region_list", RegionHandler::queryRegionList); express.get("/query_cur_region/:region", RegionHandler::queryCurrentRegion ); @@ -116,7 +114,7 @@ public final class RegionHandler implements Router { QueryAllRegionsEvent event = new QueryAllRegionsEvent(regionListResponse); event.call(); // Respond with event result. response.send(event.getRegionList()); - + // Log to console. Grasscutter.getLogger().info(String.format("[Dispatch] Client %s request: query_region_list", request.ip())); } @@ -127,19 +125,72 @@ public final class RegionHandler implements Router { private static void queryCurrentRegion(Request request, Response response) { // Get region to query. String regionName = request.params("region"); - + String versionName = request.query("version"); + var region = regions.get(regionName); + // Get region data. String regionData = "CAESGE5vdCBGb3VuZCB2ZXJzaW9uIGNvbmZpZw=="; if (request.query().values().size() > 0) { - var region = regions.get(regionName); - if(region != null) regionData = region.getBase64(); + if(region != null) + regionData = region.getBase64(); } - - // Invoke event. - QueryCurrentRegionEvent event = new QueryCurrentRegionEvent(regionData); event.call(); - // Respond with event result. - response.send(event.getRegionInfo()); + if( versionName.contains("2.7.5") || versionName.contains("2.8.")) { + try { + QueryCurrentRegionEvent event = new QueryCurrentRegionEvent(regionData); event.call(); + + if (GAME_OPTIONS.uaPatchCompatible) { + // More love for UA Patch players + + var rsp = new QueryCurRegionRspJson(); + + rsp.content = event.getRegionInfo(); + rsp.sign = "TW9yZSBsb3ZlIGZvciBVQSBQYXRjaCBwbGF5ZXJz"; + + response.send(rsp); + return; + } + + String key_id = request.query("key_id"); + Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + cipher.init(Cipher.ENCRYPT_MODE, key_id.equals("3") ? Crypto.CUR_OS_ENCRYPT_KEY : Crypto.CUR_CN_ENCRYPT_KEY); + var regionInfo = Utils.base64Decode(event.getRegionInfo()); + + //Encrypt regionInfo in chunks + ByteArrayOutputStream encryptedRegionInfoStream = new ByteArrayOutputStream(); + + //Thank you so much GH Copilot + int chunkSize = 256 - 11; + int regionInfoLength = regionInfo.length; + int numChunks = (int) Math.ceil(regionInfoLength / (double) chunkSize); + + for (int i = 0; i < numChunks; i++) { + byte[] chunk = Arrays.copyOfRange(regionInfo, i * chunkSize, Math.min((i + 1) * chunkSize, regionInfoLength)); + byte[] encryptedChunk = cipher.doFinal(chunk); + encryptedRegionInfoStream.write(encryptedChunk); + } + + Signature privateSignature = Signature.getInstance("SHA256withRSA"); + privateSignature.initSign(Crypto.CUR_SIGNING_KEY); + privateSignature.update(regionInfo); + + var rsp = new QueryCurRegionRspJson(); + + rsp.content = Utils.base64Encode(encryptedRegionInfoStream.toByteArray()); + rsp.sign = Utils.base64Encode(privateSignature.sign()); + + response.send(rsp); + } + catch (Exception e) { + Grasscutter.getLogger().error("An error occurred while handling query_cur_region.", e); + } + } + else { + // Invoke event. + QueryCurrentRegionEvent event = new QueryCurrentRegionEvent(regionData); event.call(); + // Respond with event result. + response.send(event.getRegionInfo()); + } // Log to console. Grasscutter.getLogger().info(String.format("Client %s request: query_cur_region/%s", request.ip(), regionName)); } @@ -172,4 +223,4 @@ public final class RegionHandler implements Router { public static QueryCurrRegionHttpRsp getCurrentRegion() { return SERVER.runMode == ServerRunMode.HYBRID ? regions.get("os_usa").getRegionQuery() : null; } -} +} \ No newline at end of file diff --git a/src/main/java/emu/grasscutter/server/http/objects/QueryCurRegionRspJson.java b/src/main/java/emu/grasscutter/server/http/objects/QueryCurRegionRspJson.java new file mode 100644 index 000000000..39fd24da7 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/http/objects/QueryCurRegionRspJson.java @@ -0,0 +1,6 @@ +package emu.grasscutter.server.http.objects; + +public class QueryCurRegionRspJson { + public String content; + public String sign; +} diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetPlayerTokenReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetPlayerTokenReq.java index 68ac9af9c..b598f6d1e 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetPlayerTokenReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetPlayerTokenReq.java @@ -1,6 +1,7 @@ package emu.grasscutter.server.packet.recv; import static emu.grasscutter.Configuration.ACCOUNT; +import static emu.grasscutter.Configuration.GAME_OPTIONS; import emu.grasscutter.Grasscutter; import emu.grasscutter.database.DatabaseHelper; @@ -14,6 +15,14 @@ import emu.grasscutter.server.event.game.PlayerCreationEvent; import emu.grasscutter.server.game.GameSession; import emu.grasscutter.server.game.GameSession.SessionState; import emu.grasscutter.server.packet.send.PacketGetPlayerTokenRsp; +import emu.grasscutter.utils.ByteHelper; +import emu.grasscutter.utils.Crypto; +import emu.grasscutter.utils.Utils; + +import javax.crypto.Cipher; + +import java.nio.ByteBuffer; +import java.security.Signature; @Opcodes(PacketOpcodes.GetPlayerTokenReq) public class HandlerGetPlayerTokenReq extends PacketHandler { @@ -90,8 +99,45 @@ public class HandlerGetPlayerTokenReq extends PacketHandler { session.setUseSecretKey(true); session.setState(SessionState.WAITING_FOR_LOGIN); - // Send packet - session.send(new PacketGetPlayerTokenRsp(session)); - } + // Only >= 2.7.50 has this + if (req.getKeyId() > 0) { + if (GAME_OPTIONS.uaPatchCompatible) { + // More love for ua patch plz 😭 + byte[] clientBytes = Utils.base64Decode(req.getClientSeed()); + byte[] seed = ByteHelper.longToBytes(Crypto.ENCRYPT_SEED); + Crypto.xor(clientBytes, seed); + + String base64str = Utils.base64Encode(clientBytes); + + session.send(new PacketGetPlayerTokenRsp(session, base64str, "bm90aGluZyBoZXJl")); + return; + } + + Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + cipher.init(Cipher.DECRYPT_MODE, Crypto.CUR_SIGNING_KEY); + + var client_seed_encrypted = Utils.base64Decode(req.getClientSeed()); + var client_seed = ByteBuffer.wrap(cipher.doFinal(client_seed_encrypted)) + .getLong(); + + byte[] seed_bytes = ByteBuffer.wrap(new byte[8]) + .putLong(Crypto.ENCRYPT_SEED ^ client_seed) + .array(); + + //Kind of a hack, but whatever + cipher.init(Cipher.ENCRYPT_MODE, req.getKeyId() == 3 ? Crypto.CUR_OS_ENCRYPT_KEY : Crypto.CUR_CN_ENCRYPT_KEY); + var seed_encrypted = cipher.doFinal(seed_bytes); + + Signature privateSignature = Signature.getInstance("SHA256withRSA"); + privateSignature.initSign(Crypto.CUR_SIGNING_KEY); + privateSignature.update(seed_bytes); + + session.send(new PacketGetPlayerTokenRsp(session, Utils.base64Encode(seed_encrypted), Utils.base64Encode(privateSignature.sign()))); + } + else { + // Send packet + session.send(new PacketGetPlayerTokenRsp(session)); + } + } } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketGetPlayerTokenRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketGetPlayerTokenRsp.java index 1377920e5..8fb558acb 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketGetPlayerTokenRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketGetPlayerTokenRsp.java @@ -10,45 +10,70 @@ import emu.grasscutter.utils.Crypto; public class PacketGetPlayerTokenRsp extends BasePacket { - public PacketGetPlayerTokenRsp(GameSession session) { - super(PacketOpcodes.GetPlayerTokenRsp, true); - - this.setUseDispatchKey(true); + public PacketGetPlayerTokenRsp(GameSession session) { + super(PacketOpcodes.GetPlayerTokenRsp, true); - GetPlayerTokenRsp p = GetPlayerTokenRsp.newBuilder() - .setUid(session.getPlayer().getUid()) - .setToken(session.getAccount().getToken()) - .setAccountType(1) - .setIsProficientPlayer(session.getPlayer().getAvatars().getAvatarCount() > 0) // Not sure where this goes - .setSecretKeySeed(Crypto.ENCRYPT_SEED) - .setSecurityCmdBuffer(ByteString.copyFrom(Crypto.ENCRYPT_SEED_BUFFER)) - .setPlatformType(3) - .setChannelId(1) - .setCountryCode("US") - .setClientVersionRandomKey("c25-314dd05b0b5f") - .setRegPlatform(3) - .setClientIpStr(session.getAddress().getAddress().getHostAddress()) - .build(); - - this.setData(p.toByteArray()); - } - - public PacketGetPlayerTokenRsp(GameSession session, int retcode, String msg, int blackEndTime) { - super(PacketOpcodes.GetPlayerTokenRsp, true); - - this.setUseDispatchKey(true); - - GetPlayerTokenRsp p = GetPlayerTokenRsp.newBuilder() - .setUid(session.getPlayer().getUid()) - .setIsProficientPlayer(session.getPlayer().getAvatars().getAvatarCount() > 0) - .setRetcode(retcode) - .setMsg(msg) - .setBlackUidEndTime(blackEndTime) - .setRegPlatform(3) - .setCountryCode("US") - .setClientIpStr(session.getAddress().getAddress().getHostAddress()) - .build(); - - this.setData(p.toByteArray()); - } + this.setUseDispatchKey(true); + + GetPlayerTokenRsp p = GetPlayerTokenRsp.newBuilder() + .setUid(session.getPlayer().getUid()) + .setToken(session.getAccount().getToken()) + .setAccountType(1) + .setIsProficientPlayer(session.getPlayer().getAvatars().getAvatarCount() > 0) // Not sure where this goes + .setSecretKeySeed(Crypto.ENCRYPT_SEED) + .setSecurityCmdBuffer(ByteString.copyFrom(Crypto.ENCRYPT_SEED_BUFFER)) + .setPlatformType(3) + .setChannelId(1) + .setCountryCode("US") + .setClientVersionRandomKey("c25-314dd05b0b5f") + .setRegPlatform(3) + .setClientIpStr(session.getAddress().getAddress().getHostAddress()) + .build(); + + this.setData(p.toByteArray()); + } + + public PacketGetPlayerTokenRsp(GameSession session, int retcode, String msg, int blackEndTime) { + super(PacketOpcodes.GetPlayerTokenRsp, true); + + this.setUseDispatchKey(true); + + GetPlayerTokenRsp p = GetPlayerTokenRsp.newBuilder() + .setUid(session.getPlayer().getUid()) + .setIsProficientPlayer(session.getPlayer().getAvatars().getAvatarCount() > 0) + .setRetcode(retcode) + .setMsg(msg) + .setBlackUidEndTime(blackEndTime) + .setRegPlatform(3) + .setCountryCode("US") + .setClientIpStr(session.getAddress().getAddress().getHostAddress()) + .build(); + + this.setData(p.toByteArray()); + } + + public PacketGetPlayerTokenRsp(GameSession session, String encryptedSeed, String encryptedSeedSign) { + super(PacketOpcodes.GetPlayerTokenRsp, true); + + this.setUseDispatchKey(true); + + GetPlayerTokenRsp p = GetPlayerTokenRsp.newBuilder() + .setUid(session.getPlayer().getUid()) + .setToken(session.getAccount().getToken()) + .setAccountType(1) + .setIsProficientPlayer(session.getPlayer().getAvatars().getAvatarCount() > 0) // Not sure where this goes + .setSecretKeySeed(Crypto.ENCRYPT_SEED) + .setSecurityCmdBuffer(ByteString.copyFrom(Crypto.ENCRYPT_SEED_BUFFER)) + .setPlatformType(3) + .setChannelId(1) + .setCountryCode("US") + .setClientVersionRandomKey("c25-314dd05b0b5f") + .setRegPlatform(3) + .setClientIpStr(session.getAddress().getAddress().getHostAddress()) + .setEncryptedSeed(encryptedSeed) + .setSeedSignature(encryptedSeedSign) + .build(); + + this.setData(p.toByteArray()); + } } diff --git a/src/main/java/emu/grasscutter/utils/ByteHelper.java b/src/main/java/emu/grasscutter/utils/ByteHelper.java new file mode 100644 index 000000000..1f9e408b1 --- /dev/null +++ b/src/main/java/emu/grasscutter/utils/ByteHelper.java @@ -0,0 +1,24 @@ +package emu.grasscutter.utils; + +public class ByteHelper { + public static byte[] changeBytes(byte[] a) { + byte[] b = new byte[a.length]; + for (int i = 0; i < a.length; i++) { + b[i] = a[a.length - i - 1]; + } + return b; + } + + public static byte[] longToBytes(long x) { + byte[] bytes = new byte[8]; + bytes[0] = (byte) (x >> 56); + bytes[1] = (byte) (x >> 48); + bytes[2] = (byte) (x >> 40); + bytes[3] = (byte) (x >> 32); + bytes[4] = (byte) (x >> 24); + bytes[5] = (byte) (x >> 16); + bytes[6] = (byte) (x >> 8); + bytes[7] = (byte) (x); + return bytes; + } +} \ No newline at end of file diff --git a/src/main/java/emu/grasscutter/utils/ConfigContainer.java b/src/main/java/emu/grasscutter/utils/ConfigContainer.java index 8c031c7a6..17ef6b8ca 100644 --- a/src/main/java/emu/grasscutter/utils/ConfigContainer.java +++ b/src/main/java/emu/grasscutter/utils/ConfigContainer.java @@ -112,6 +112,7 @@ public class ConfigContainer { public static class Account { public boolean autoCreate = false; + public boolean EXPERIMENTAL_RealPassword = false; public String[] defaultPermissions = {}; public int maxPlayer = -1; } @@ -210,6 +211,7 @@ public class ConfigContainer { public int cap = 160; public int rechargeTime = 480; } + public boolean uaPatchCompatible = false; } public static class JoinOptions { diff --git a/src/main/java/emu/grasscutter/utils/Crypto.java b/src/main/java/emu/grasscutter/utils/Crypto.java index 3bde63aa7..c8a264f48 100644 --- a/src/main/java/emu/grasscutter/utils/Crypto.java +++ b/src/main/java/emu/grasscutter/utils/Crypto.java @@ -1,13 +1,13 @@ package emu.grasscutter.utils; +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.PublicKey; import java.security.SecureRandom; -import java.util.Base64; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; import emu.grasscutter.Grasscutter; -import emu.grasscutter.net.proto.GetPlayerTokenRspOuterClass.GetPlayerTokenRsp; -import emu.grasscutter.net.proto.QueryCurrRegionHttpRspOuterClass.QueryCurrRegionHttpRsp; - -import static emu.grasscutter.Configuration.*; public final class Crypto { private static final SecureRandom secureRandom = new SecureRandom(); @@ -18,15 +18,34 @@ public final class Crypto { public static byte[] ENCRYPT_KEY; public static long ENCRYPT_SEED = Long.parseUnsignedLong("11468049314633205968"); public static byte[] ENCRYPT_SEED_BUFFER = new byte[0]; - + + public static PublicKey CUR_OS_ENCRYPT_KEY; + public static PublicKey CUR_CN_ENCRYPT_KEY; + public static PrivateKey CUR_SIGNING_KEY; + public static void loadKeys() { DISPATCH_KEY = FileUtils.readResource("/keys/dispatchKey.bin"); DISPATCH_SEED = FileUtils.readResource("/keys/dispatchSeed.bin"); ENCRYPT_KEY = FileUtils.readResource("/keys/secretKey.bin"); ENCRYPT_SEED_BUFFER = FileUtils.readResource("/keys/secretKeyBuffer.bin"); + + try { + //These should be loaded from ChannelConfig_whatever.json + CUR_SIGNING_KEY = KeyFactory.getInstance("RSA") + .generatePrivate(new PKCS8EncodedKeySpec(FileUtils.readResource("/keys/SigningKey.der"))); + + CUR_OS_ENCRYPT_KEY = KeyFactory.getInstance("RSA") + .generatePublic(new X509EncodedKeySpec(FileUtils.readResource("/keys/OSCB_Pub.der"))); + + CUR_CN_ENCRYPT_KEY = KeyFactory.getInstance("RSA") + .generatePublic(new X509EncodedKeySpec(FileUtils.readResource("/keys/OSCN_Pub.der"))); + } + catch (Exception e) { + Grasscutter.getLogger().error("An error occurred while loading keys.", e); + } } - + public static void xor(byte[] packet, byte[] key) { try { for (int i = 0; i < packet.length; i++) { @@ -36,7 +55,7 @@ public final class Crypto { Grasscutter.getLogger().error("Crypto error.", e); } } - + public static byte[] createSessionKey(int length) { byte[] bytes = new byte[length]; secureRandom.nextBytes(bytes); diff --git a/src/main/resources/languages/en-US.json b/src/main/resources/languages/en-US.json index 6dc5a0c43..0e6c45415 100644 --- a/src/main/resources/languages/en-US.json +++ b/src/main/resources/languages/en-US.json @@ -28,6 +28,8 @@ "login_token_attempt": "[Dispatch] Client %s is trying to log in via token.", "login_token_error": "[Dispatch] Client %s failed to log in via token.", "login_token_success": "[Dispatch] Client %s logged in via token as %s.", + "login_password_error": "[Dispatch] Client %s failed to log in via password.", + "login_password_storage_error": "[Dispatch] Client %s failed to log in via password because there is no password in the database.", "combo_token_success": "[Dispatch] Client %s succeed to exchange combo token.", "combo_token_error": "[Dispatch] Client %s failed to exchange combo token.", "account_login_create_success": "[Dispatch] Client %s failed to log in: Account %s created.", @@ -37,6 +39,9 @@ "session_key_error": "Wrong session key.", "username_error": "Username not found.", "username_create_error": "Username not found, create failed.", + "password_error": "Invalid Password", + "password_length_error": "Password length must be greater then or equal to 8", + "password_storage_error": "You don't have a password for your account. Please contact an administrator.", "server_max_player_limit": "The number of online players has reached the limit" }, "router_error": "[Dispatch] Unable to attach router." From 591ca4805ac0969c2ecfd5042128fa63d4b58ae1 Mon Sep 17 00:00:00 2001 From: AnimeGitB Date: Wed, 13 Jul 2022 12:09:02 +0930 Subject: [PATCH 10/61] Some proto name changes --- .../musicgame/MusicGameActivityHandler.java | 3 +- .../musicgame/MusicGamePlayerData.java | 3 +- .../grasscutter/game/entity/EntityAvatar.java | 2 +- .../game/managers/SotSManager.java | 2 +- .../deforestation/DeforestationManager.java | 4 +- .../grasscutter/net/packet/BasePacket.java | 2 +- .../packet/recv/HandlerGetAllMailReq.java | 2 +- .../packet/recv/HandlerHomeUnknown2Req.java | 2 +- .../send/PacketAllWidgetDataNotify.java | 43 +++++++++---------- .../packet/send/PacketGetAllMailRsp.java | 6 +-- .../packet/send/PacketHomeUnknown1Notify.java | 12 +++--- .../packet/send/PacketHomeUnknown2Rsp.java | 6 +-- .../packet/send/PacketMailChangeNotify.java | 2 +- ...PacketQueryCodexMonsterBeKilledNumRsp.java | 6 +-- 14 files changed, 46 insertions(+), 49 deletions(-) diff --git a/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGameActivityHandler.java b/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGameActivityHandler.java index 1fec26c56..18f937c9e 100644 --- a/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGameActivityHandler.java +++ b/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGameActivityHandler.java @@ -29,13 +29,12 @@ public class MusicGameActivityHandler extends ActivityHandler { .putAllMusicGameRecordMap( musicGamePlayerData.getMusicGameRecord().values().stream() .collect(Collectors.toMap(MusicGamePlayerData.MusicGameRecord::getMusicId, MusicGamePlayerData.MusicGameRecord::toProto))) - .addAllPersonCustomBeatmap(musicGamePlayerData.getPersonalCustomBeatmapRecord().values().stream() .map(MusicGamePlayerData.CustomBeatmapRecord::toPersonalBriefProto) .map(MusicBriefInfoOuterClass.MusicBriefInfo.Builder::build) .toList()) - .addAllPersonCustomBeatmap(musicGamePlayerData.getOthersCustomBeatmapRecord().values().stream() + .addAllOthersCustomBeatmap(musicGamePlayerData.getOthersCustomBeatmapRecord().values().stream() .map(MusicGamePlayerData.CustomBeatmapRecord::toOthersBriefProto) .map(MusicBriefInfoOuterClass.MusicBriefInfo.Builder::build) .toList()) diff --git a/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGamePlayerData.java b/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGamePlayerData.java index 9b1b97197..4fd25c5bb 100644 --- a/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGamePlayerData.java +++ b/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGamePlayerData.java @@ -71,8 +71,7 @@ public class MusicGamePlayerData { .setMaxScore(musicGameBeatmap.getMaxScore()) .setPosition(musicGameBeatmap.getSavePosition()) .setMusicNoteCount(musicGameBeatmap.getMusicNoteCount()) - .setMusicShareId(musicShareId) - ; + .setMusicShareId(musicShareId); } public MusicBriefInfoOuterClass.MusicBriefInfo.Builder toOthersBriefProto(){ diff --git a/src/main/java/emu/grasscutter/game/entity/EntityAvatar.java b/src/main/java/emu/grasscutter/game/entity/EntityAvatar.java index 311f25a89..f200a6559 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityAvatar.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityAvatar.java @@ -125,7 +125,7 @@ public class EntityAvatar extends GameEntity { if (healed > 0f) { getScene().broadcastPacket( - new PacketEntityFightPropChangeReasonNotify(this, FightProperty.FIGHT_PROP_CUR_HP, healed, PropChangeReason.PROP_CHANGE_REASON_ABILITY, ChangeHpReason.CHANGE_HP_REASON_CHANGE_HP_ADD_ABILITY) + new PacketEntityFightPropChangeReasonNotify(this, FightProperty.FIGHT_PROP_CUR_HP, healed, PropChangeReason.PROP_CHANGE_REASON_ABILITY, ChangeHpReason.CHANGE_HP_REASON_ADD_ABILITY) ); } diff --git a/src/main/java/emu/grasscutter/game/managers/SotSManager.java b/src/main/java/emu/grasscutter/game/managers/SotSManager.java index 5f394a800..c1d1326a6 100644 --- a/src/main/java/emu/grasscutter/game/managers/SotSManager.java +++ b/src/main/java/emu/grasscutter/game/managers/SotSManager.java @@ -158,7 +158,7 @@ public class SotSManager { player.getTeamManager().healAvatar(entity.getAvatar(), 0, needHP); player.getSession().send(new PacketEntityFightPropChangeReasonNotify(entity, FightProperty.FIGHT_PROP_CUR_HP, ((float) needHP / 100), List.of(3), PropChangeReason.PROP_CHANGE_REASON_STATUE_RECOVER, - ChangeHpReason.CHANGE_HP_REASON_CHANGE_HP_ADD_STATUE)); + ChangeHpReason.CHANGE_HP_REASON_ADD_STATUE)); player.getSession().send(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CUR_HP)); } diff --git a/src/main/java/emu/grasscutter/game/managers/deforestation/DeforestationManager.java b/src/main/java/emu/grasscutter/game/managers/deforestation/DeforestationManager.java index 36e1c0e22..3650bdb31 100644 --- a/src/main/java/emu/grasscutter/game/managers/deforestation/DeforestationManager.java +++ b/src/main/java/emu/grasscutter/game/managers/deforestation/DeforestationManager.java @@ -48,8 +48,8 @@ public class DeforestationManager { public void onDeforestationInvoke(HitTreeNotifyOuterClass.HitTreeNotify hit){ synchronized (currentRecord) { //Grasscutter.getLogger().info("onDeforestationInvoke! Wood records {}", currentRecord); - VectorOuterClass.Vector hitPosition = hit.getHitPostion(); - int woodType = hit.getWoodType(); + VectorOuterClass.Vector hitPosition = hit.getTreePos(); + int woodType = hit.getTreeType(); if (ColliderTypeToWoodItemID.containsKey(woodType)) {// is a available wood type Scene scene = player.getScene(); int itemId = ColliderTypeToWoodItemID.get(woodType); diff --git a/src/main/java/emu/grasscutter/net/packet/BasePacket.java b/src/main/java/emu/grasscutter/net/packet/BasePacket.java index 7fae74c8a..12009ffd3 100644 --- a/src/main/java/emu/grasscutter/net/packet/BasePacket.java +++ b/src/main/java/emu/grasscutter/net/packet/BasePacket.java @@ -84,7 +84,7 @@ public class BasePacket { if (this.getHeader() != null && clientSequence == 0) { return this; } - setHeader(PacketHead.newBuilder().setClientSequenceId(clientSequence).setTimestamp(System.currentTimeMillis()).build().toByteArray()); + setHeader(PacketHead.newBuilder().setClientSequenceId(clientSequence).setSentMs(System.currentTimeMillis()).build().toByteArray()); return this; } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetAllMailReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetAllMailReq.java index 2a7fdc295..8e47b1159 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetAllMailReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetAllMailReq.java @@ -16,6 +16,6 @@ public class HandlerGetAllMailReq extends PacketHandler { @Override public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { GetAllMailReqOuterClass.GetAllMailReq req = GetAllMailReqOuterClass.GetAllMailReq.parseFrom(payload); - session.send(new PacketGetAllMailRsp(session.getPlayer(), req.getANKKGPJCINB())); + session.send(new PacketGetAllMailRsp(session.getPlayer(), req.getUnk2700OPEHLDAGICF())); } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeUnknown2Req.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeUnknown2Req.java index 8e05c08bb..517f9c17e 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeUnknown2Req.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeUnknown2Req.java @@ -6,7 +6,7 @@ import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.server.game.GameSession; import emu.grasscutter.server.packet.send.PacketHomeUnknown2Rsp; -@Opcodes(PacketOpcodes.HomeUnknown2Req) +@Opcodes(PacketOpcodes.Unk2700_ACILPONNGGK_ClientReq) public class HandlerHomeUnknown2Req extends PacketHandler { @Override diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketAllWidgetDataNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketAllWidgetDataNotify.java index 8d3d42261..275909c04 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketAllWidgetDataNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketAllWidgetDataNotify.java @@ -9,7 +9,6 @@ import emu.grasscutter.net.proto.WidgetSlotDataOuterClass; import emu.grasscutter.net.proto.WidgetSlotTagOuterClass; import java.util.List; -import java.util.Map; public class PacketAllWidgetDataNotify extends BasePacket { @@ -19,35 +18,35 @@ public class PacketAllWidgetDataNotify extends BasePacket { // TODO: Implement this AllWidgetDataNotify.Builder proto = AllWidgetDataNotify.newBuilder() - // If you want to implement this, feel free to do so. :) - .setLunchBoxData( - LunchBoxDataOuterClass.LunchBoxData.newBuilder().build() - ) - // Maybe it's a little difficult, or it makes you upset :( - .addAllOneoffGatherPointDetectorDataList(List.of()) - // So, goodbye, and hopefully sometime in the future o(* ̄▽ ̄*)ブ - .addAllCoolDownGroupDataList(List.of()) - // I'll see your PR with a title that says (・∀・(・∀・(・∀・*) - .addAllAnchorPointList(List.of()) - // "Complete implementation of widget functionality" b( ̄▽ ̄)d  - .addAllClientCollectorDataList(List.of()) - // Good luck, my boy. - .addAllNormalCoolDownDataList(List.of()); + // If you want to implement this, feel free to do so. :) + .setLunchBoxData( + LunchBoxDataOuterClass.LunchBoxData.newBuilder().build() + ) + // Maybe it's a little difficult, or it makes you upset :( + .addAllOneofGatherPointDetectorDataList(List.of()) + // So, goodbye, and hopefully sometime in the future o(* ̄▽ ̄*)ブ + .addAllCoolDownGroupDataList(List.of()) + // I'll see your PR with a title that says (・∀・(・∀・(・∀・*) + .addAllAnchorPointList(List.of()) + // "Complete implementation of widget functionality" b( ̄▽ ̄)d  + .addAllClientCollectorDataList(List.of()) + // Good luck, my boy. + .addAllNormalCoolDownDataList(List.of()); if (player.getWidgetId() == null) { proto.addAllSlotList(List.of()); } else { proto.addSlotList( - WidgetSlotDataOuterClass.WidgetSlotData.newBuilder() - .setIsActive(true) - .setMaterialId(player.getWidgetId()) - .build() + WidgetSlotDataOuterClass.WidgetSlotData.newBuilder() + .setIsActive(true) + .setMaterialId(player.getWidgetId()) + .build() ); proto.addSlotList( - WidgetSlotDataOuterClass.WidgetSlotData.newBuilder() - .setTag(WidgetSlotTagOuterClass.WidgetSlotTag.WIDGET_SLOT_TAG_ATTACH_AVATAR) - .build() + WidgetSlotDataOuterClass.WidgetSlotData.newBuilder() + .setTag(WidgetSlotTagOuterClass.WidgetSlotTag.WIDGET_SLOT_TAG_ATTACH_AVATAR) + .build() ); } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketGetAllMailRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketGetAllMailRsp.java index ff7f83721..c6f2b7194 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketGetAllMailRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketGetAllMailRsp.java @@ -24,9 +24,9 @@ public class PacketGetAllMailRsp extends BasePacket { GetAllMailRsp.Builder proto = GetAllMailRsp.newBuilder(); if (isGiftMail) { - proto.setANKKGPJCINB(true); + proto.setUnk2700OPEHLDAGICF(true); } else { - proto.setANKKGPJCINB(false); + proto.setUnk2700OPEHLDAGICF(false); if (player.getAllMail().size() != 0) { // Make sure the player has mail List mailDataList = new ArrayList(); @@ -61,7 +61,7 @@ public class PacketGetAllMailRsp extends BasePacket { mailData.setImportance(message.importance); mailData.setIsRead(message.isRead); mailData.setIsAttachmentGot(message.isAttachmentGot); - mailData.setBHCAHLJIKFFValue(1); + mailData.setUnk2700NDPPGJKJOMHValue(1); mailDataList.add(mailData.build()); } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketHomeUnknown1Notify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketHomeUnknown1Notify.java index ec22dce27..8fdaca533 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketHomeUnknown1Notify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketHomeUnknown1Notify.java @@ -6,13 +6,13 @@ import emu.grasscutter.net.proto.HomeUnknown1NotifyOuterClass; public class PacketHomeUnknown1Notify extends BasePacket { - public PacketHomeUnknown1Notify(boolean isEnterEditMode) { - super(PacketOpcodes.HomeUnknown1Notify); + public PacketHomeUnknown1Notify(boolean isEnterEditMode) { + super(PacketOpcodes.Unk2700_JDMPECKFGIG_ServerNotify); - var proto = HomeUnknown1NotifyOuterClass.HomeUnknown1Notify.newBuilder(); + var proto = HomeUnknown1NotifyOuterClass.HomeUnknown1Notify.newBuilder(); - proto.setIsEnterEditMode(isEnterEditMode); + proto.setIsEnterEditMode(isEnterEditMode); - this.setData(proto); - } + this.setData(proto); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketHomeUnknown2Rsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketHomeUnknown2Rsp.java index 8766531e8..1aac1f721 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketHomeUnknown2Rsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketHomeUnknown2Rsp.java @@ -5,8 +5,8 @@ import emu.grasscutter.net.packet.PacketOpcodes; public class PacketHomeUnknown2Rsp extends BasePacket { - public PacketHomeUnknown2Rsp() { - super(PacketOpcodes.HomeUnknown2Rsp); + public PacketHomeUnknown2Rsp() { + super(PacketOpcodes.Unk2700_KIIOGMKFNNP_ServerRsp); - } + } } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketMailChangeNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketMailChangeNotify.java index 0a43a1c61..d0ea5d96b 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketMailChangeNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketMailChangeNotify.java @@ -54,7 +54,7 @@ public class PacketMailChangeNotify extends BasePacket { mailData.setImportance(message.importance); mailData.setIsRead(message.isRead); mailData.setIsAttachmentGot(message.isAttachmentGot); - mailData.setBHCAHLJIKFFValue(message.stateValue); + mailData.setUnk2700NDPPGJKJOMHValue(message.stateValue); proto.addMailList(mailData.build()); } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketQueryCodexMonsterBeKilledNumRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketQueryCodexMonsterBeKilledNumRsp.java index 8da5c4fe2..5d68fc625 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketQueryCodexMonsterBeKilledNumRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketQueryCodexMonsterBeKilledNumRsp.java @@ -14,10 +14,10 @@ public class PacketQueryCodexMonsterBeKilledNumRsp extends BasePacket { QueryCodexMonsterBeKilledNumRsp.Builder proto = QueryCodexMonsterBeKilledNumRsp.newBuilder(); codexList.forEach(animal -> { - if(player.getCodex().getUnlockedAnimal().containsKey(animal)){ + if (player.getCodex().getUnlockedAnimal().containsKey(animal)) { proto.addCodexIdList(animal) - .addBeKilledNumList(player.getCodex().getUnlockedAnimal().get(animal)) - .addCHPBKCLKPCJ(0); + .addBeKilledNumList(player.getCodex().getUnlockedAnimal().get(animal)) + .addUnk2700MKOBMGGPNMI(0); } }); From 4f070e7d6ec24165c90e3c9e6c8f5f937258b89e Mon Sep 17 00:00:00 2001 From: Kokoboy Date: Tue, 12 Jul 2022 23:26:03 +0530 Subject: [PATCH 11/61] Fix Some Protos #BattlePass Half-Working but still some protos need to be updated From b3d829957cf218a97be27fdbdbef049a5ce03412 Mon Sep 17 00:00:00 2001 From: berrycandii Date: Wed, 13 Jul 2022 03:43:47 +0800 Subject: [PATCH 12/61] more protos fixed by AlienGathering#5634, berryy#9838 (thx koko for cooking protos) pro toes From 0a557ccfcd8088e1b41d9d86a2df8f62978409f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=9C=9F=E5=BF=83?= Date: Wed, 13 Jul 2022 11:30:06 +0800 Subject: [PATCH 13/61] Update GameConstants.java --- src/main/java/emu/grasscutter/GameConstants.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/emu/grasscutter/GameConstants.java b/src/main/java/emu/grasscutter/GameConstants.java index 25441fd49..fccc59ed1 100644 --- a/src/main/java/emu/grasscutter/GameConstants.java +++ b/src/main/java/emu/grasscutter/GameConstants.java @@ -6,7 +6,7 @@ import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Utils; public final class GameConstants { - public static String VERSION = "2.8"; + public static String VERSION = "2.8.0"; public static final int MAX_TEAMS = 4; public static final int MAIN_CHARACTER_MALE = 10000005; From ae8b5e30accb3d985287fa8279f81037891e83a4 Mon Sep 17 00:00:00 2001 From: Yazawazi <47273265+Yazawazi@users.noreply.github.com> Date: Wed, 13 Jul 2022 12:30:56 +0800 Subject: [PATCH 14/61] Full support for both parties --- .../auth/DefaultAuthenticators.java | 29 +++++------- .../server/http/dispatch/RegionHandler.java | 9 +++- .../packet/recv/HandlerGetPlayerTokenReq.java | 46 +++++++++---------- .../grasscutter/utils/ConfigContainer.java | 3 +- 4 files changed, 41 insertions(+), 46 deletions(-) diff --git a/src/main/java/emu/grasscutter/auth/DefaultAuthenticators.java b/src/main/java/emu/grasscutter/auth/DefaultAuthenticators.java index 6c5585ec8..81b463046 100644 --- a/src/main/java/emu/grasscutter/auth/DefaultAuthenticators.java +++ b/src/main/java/emu/grasscutter/auth/DefaultAuthenticators.java @@ -103,26 +103,19 @@ public final class DefaultAuthenticators { String responseMessage = translate("messages.dispatch.account.username_error"); String loggerMessage = ""; String decryptedPassword = ""; + try { + byte[] key = FileUtils.readResource("/keys/auth_private-key.der"); + PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(key); + KeyFactory keyFactory = KeyFactory.getInstance("RSA"); + RSAPrivateKey private_key = (RSAPrivateKey) keyFactory.generatePrivate(keySpec); - // Get Password - if (GAME_OPTIONS.uaPatchCompatible) { - // Make sure your patch can send passwords in plain text + Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + + cipher.init(Cipher.DECRYPT_MODE, private_key); + + decryptedPassword = new String(cipher.doFinal(Utils.base64Decode(request.getPasswordRequest().password)), StandardCharsets.UTF_8); + } catch (Exception ignored) { decryptedPassword = request.getPasswordRequest().password; - } else { - try { - byte[] key = FileUtils.readResource("/keys/auth_private-key.der"); - PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(key); - KeyFactory keyFactory = KeyFactory.getInstance("RSA"); - RSAPrivateKey private_key = (RSAPrivateKey) keyFactory.generatePrivate(keySpec); - - Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); - - cipher.init(Cipher.DECRYPT_MODE, private_key); - - decryptedPassword = new String(cipher.doFinal(Utils.base64Decode(request.getPasswordRequest().password)), StandardCharsets.UTF_8); - } catch (Exception ignored) { - ignored.printStackTrace(); - } } if (decryptedPassword == null) { diff --git a/src/main/java/emu/grasscutter/server/http/dispatch/RegionHandler.java b/src/main/java/emu/grasscutter/server/http/dispatch/RegionHandler.java index c1fdfc7a0..336bda588 100644 --- a/src/main/java/emu/grasscutter/server/http/dispatch/RegionHandler.java +++ b/src/main/java/emu/grasscutter/server/http/dispatch/RegionHandler.java @@ -11,6 +11,7 @@ import emu.grasscutter.server.event.dispatch.QueryCurrentRegionEvent; import emu.grasscutter.server.http.Router; import emu.grasscutter.server.http.objects.QueryCurRegionRspJson; import emu.grasscutter.utils.Crypto; +import emu.grasscutter.utils.FileUtils; import emu.grasscutter.utils.Utils; import express.Express; import express.http.Request; @@ -19,6 +20,11 @@ import io.javalin.Javalin; import javax.crypto.Cipher; import java.io.ByteArrayOutputStream; +import java.security.KeyFactory; +import java.security.PrivateKey; +import java.security.PublicKey; +import java.security.spec.PKCS8EncodedKeySpec; +import java.security.spec.X509EncodedKeySpec; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.security.Signature; @@ -139,9 +145,8 @@ public final class RegionHandler implements Router { try { QueryCurrentRegionEvent event = new QueryCurrentRegionEvent(regionData); event.call(); - if (GAME_OPTIONS.uaPatchCompatible) { + if (request.query("dispatchSeed") == null) { // More love for UA Patch players - var rsp = new QueryCurRegionRspJson(); rsp.content = event.getRegionInfo(); diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetPlayerTokenReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetPlayerTokenReq.java index b598f6d1e..8d1615587 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetPlayerTokenReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetPlayerTokenReq.java @@ -101,9 +101,29 @@ public class HandlerGetPlayerTokenReq extends PacketHandler { // Only >= 2.7.50 has this if (req.getKeyId() > 0) { - if (GAME_OPTIONS.uaPatchCompatible) { - // More love for ua patch plz 😭 + try { + Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); + cipher.init(Cipher.DECRYPT_MODE, Crypto.CUR_SIGNING_KEY); + var client_seed_encrypted = Utils.base64Decode(req.getClientSeed()); + var client_seed = ByteBuffer.wrap(cipher.doFinal(client_seed_encrypted)) + .getLong(); + + byte[] seed_bytes = ByteBuffer.wrap(new byte[8]) + .putLong(Crypto.ENCRYPT_SEED ^ client_seed) + .array(); + + //Kind of a hack, but whatever + cipher.init(Cipher.ENCRYPT_MODE, req.getKeyId() == 3 ? Crypto.CUR_OS_ENCRYPT_KEY : Crypto.CUR_CN_ENCRYPT_KEY); + var seed_encrypted = cipher.doFinal(seed_bytes); + + Signature privateSignature = Signature.getInstance("SHA256withRSA"); + privateSignature.initSign(Crypto.CUR_SIGNING_KEY); + privateSignature.update(seed_bytes); + + session.send(new PacketGetPlayerTokenRsp(session, Utils.base64Encode(seed_encrypted), Utils.base64Encode(privateSignature.sign()))); + } catch (Exception ignore) { + // Only UA Patch users will have exception byte[] clientBytes = Utils.base64Decode(req.getClientSeed()); byte[] seed = ByteHelper.longToBytes(Crypto.ENCRYPT_SEED); Crypto.xor(clientBytes, seed); @@ -111,29 +131,7 @@ public class HandlerGetPlayerTokenReq extends PacketHandler { String base64str = Utils.base64Encode(clientBytes); session.send(new PacketGetPlayerTokenRsp(session, base64str, "bm90aGluZyBoZXJl")); - return; } - - Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding"); - cipher.init(Cipher.DECRYPT_MODE, Crypto.CUR_SIGNING_KEY); - - var client_seed_encrypted = Utils.base64Decode(req.getClientSeed()); - var client_seed = ByteBuffer.wrap(cipher.doFinal(client_seed_encrypted)) - .getLong(); - - byte[] seed_bytes = ByteBuffer.wrap(new byte[8]) - .putLong(Crypto.ENCRYPT_SEED ^ client_seed) - .array(); - - //Kind of a hack, but whatever - cipher.init(Cipher.ENCRYPT_MODE, req.getKeyId() == 3 ? Crypto.CUR_OS_ENCRYPT_KEY : Crypto.CUR_CN_ENCRYPT_KEY); - var seed_encrypted = cipher.doFinal(seed_bytes); - - Signature privateSignature = Signature.getInstance("SHA256withRSA"); - privateSignature.initSign(Crypto.CUR_SIGNING_KEY); - privateSignature.update(seed_bytes); - - session.send(new PacketGetPlayerTokenRsp(session, Utils.base64Encode(seed_encrypted), Utils.base64Encode(privateSignature.sign()))); } else { // Send packet diff --git a/src/main/java/emu/grasscutter/utils/ConfigContainer.java b/src/main/java/emu/grasscutter/utils/ConfigContainer.java index 17ef6b8ca..dd7002482 100644 --- a/src/main/java/emu/grasscutter/utils/ConfigContainer.java +++ b/src/main/java/emu/grasscutter/utils/ConfigContainer.java @@ -211,7 +211,6 @@ public class ConfigContainer { public int cap = 160; public int rechargeTime = 480; } - public boolean uaPatchCompatible = false; } public static class JoinOptions { @@ -271,4 +270,4 @@ public class ConfigContainer { public String Ip = "127.0.0.1"; public int Port = 22102; } -} +} \ No newline at end of file From b5a4ab7524d059af38c4d40e9a4c9a287221a8a6 Mon Sep 17 00:00:00 2001 From: akatatsu27 <43857160+akatatsu27@users.noreply.github.com> Date: Mon, 18 Jul 2022 11:33:57 +0300 Subject: [PATCH 15/61] Open state framework (#1483) * Added more server debug options * made server debug code prettier * fixed initialization bug * Enables logging of packets contained in UnionCmdNotify, when debug level is WHITELIST or BLACKLIST * Fully Implement OpenState Framework * added devOpenStates * Commented out newPlayerOpenStates * Removed OPEN_STATE_NONE from devOpenStates --- .../emu/grasscutter/game/player/Player.java | 15 +- .../game/player/PlayerOpenStateManager.java | 246 ++++++++++++++++++ .../packet/recv/HandlerPlayerLoginReq.java | 10 +- .../packet/recv/HandlerSetOpenStateReq.java | 26 ++ .../send/PacketOpenStateChangeNotify.java | 19 ++ .../send/PacketOpenStateUpdateNotify.java | 21 +- .../packet/send/PacketSetOpenStateRsp.java | 18 ++ 7 files changed, 337 insertions(+), 18 deletions(-) create mode 100644 src/main/java/emu/grasscutter/game/player/PlayerOpenStateManager.java create mode 100644 src/main/java/emu/grasscutter/server/packet/recv/HandlerSetOpenStateReq.java create mode 100644 src/main/java/emu/grasscutter/server/packet/send/PacketOpenStateChangeNotify.java create mode 100644 src/main/java/emu/grasscutter/server/packet/send/PacketSetOpenStateRsp.java diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index a2d23a26f..3238de22e 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -104,7 +104,7 @@ public class Player { private Position rotation; private PlayerBirthday birthday; private PlayerCodex codex; - + @Getter private PlayerOpenStateManager openStateManager; private Map properties; private Set nameCardList; private Set flyCloakList; @@ -187,7 +187,7 @@ public class Player { @Transient private FurnitureManager furnitureManager; @Transient private BattlePassManager battlePassManager; @Transient private CookingManager cookingManager; - // @Transient private + // @Transient private @Getter @Transient private ActivityManager activityManager; @Transient private CollectionManager collectionManager; @@ -248,7 +248,7 @@ public class Player { this.rewardedLevels = new HashSet<>(); this.moonCardGetTimes = new HashSet<>(); this.codex = new PlayerCodex(this); - + this.openStateManager = new PlayerOpenStateManager(this); this.shopLimit = new ArrayList<>(); this.expeditionInfo = new HashMap<>(); this.messageHandler = null; @@ -468,7 +468,7 @@ public class Player { public int getWorldLevel() { return this.getProperty(PlayerProperty.PROP_PLAYER_WORLD_LEVEL); } - + public boolean setWorldLevel(int level) { if (this.setProperty(PlayerProperty.PROP_PLAYER_WORLD_LEVEL, level)) { if (this.world.getHost() == this) // Don't update World's WL if we are in someone else's world @@ -1445,6 +1445,7 @@ public class Player { @PostLoad private void onLoad() { this.getCodex().setPlayer(this); + this.getOpenStateManager().setPlayer(this); this.getTeamManager().setPlayer(this); this.getTowerManager().setPlayer(this); } @@ -1465,6 +1466,9 @@ public class Player { if (this.getCodex() == null) { this.codex = new PlayerCodex(this); } + if (this.getOpenStateManager() == null) { + this.openStateManager = new PlayerOpenStateManager(this); + } if (this.getProfile().getUid() == 0) { this.getProfile().syncWithCharacter(this); } @@ -1525,6 +1529,7 @@ public class Player { this.forgingManager.sendForgeDataNotify(); this.resinManager.onPlayerLogin(); this.cookingManager.sendCookDataNofity(); + this.openStateManager.onPlayerLogin(); getTodayMoonCard(); // The timer works at 0:0, some users log in after that, use this method to check if they have received a reward today or not. If not, send the reward. // Battle Pass trigger @@ -1539,7 +1544,7 @@ public class Player { session.send(new PacketPlayerEnterSceneNotify(this)); // Enter game world session.send(new PacketPlayerLevelRewardUpdateNotify(rewardedLevels)); - session.send(new PacketOpenStateUpdateNotify()); + // First notify packets sent this.setHasSentAvatarDataNotify(true); diff --git a/src/main/java/emu/grasscutter/game/player/PlayerOpenStateManager.java b/src/main/java/emu/grasscutter/game/player/PlayerOpenStateManager.java new file mode 100644 index 000000000..3bf1bf8cc --- /dev/null +++ b/src/main/java/emu/grasscutter/game/player/PlayerOpenStateManager.java @@ -0,0 +1,246 @@ +package emu.grasscutter.game.player; + +import dev.morphia.annotations.Entity; +import dev.morphia.annotations.Transient; +import emu.grasscutter.Grasscutter; +import emu.grasscutter.game.player.Player; +import emu.grasscutter.game.props.OpenState; +import emu.grasscutter.server.packet.send.PacketOpenStateChangeNotify; +import emu.grasscutter.server.packet.send.PacketOpenStateUpdateNotify; +import lombok.Getter; + +import java.util.*; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static emu.grasscutter.game.props.OpenState.*; + +@Entity +public class PlayerOpenStateManager { + + @Transient private Player player; + @Getter private Map openStateMap; + /* + //DO NOT MODIFY. Based on conversation of official server and client, game version 2.7 + private static Set newPlayerOpenStates = Set.of(OPEN_STATE_DERIVATIVE_MALL,OPEN_STATE_PHOTOGRAPH,OPEN_STATE_BATTLE_PASS,OPEN_STATE_SHOP_TYPE_GENESISCRYSTAL,OPEN_STATE_SHOP_TYPE_RECOMMANDED, + OPEN_STATE_SHOP_TYPE_GIFTPACKAGE,OPEN_STATE_GUIDE_RELIC_PROM,OPEN_STATE_GUIDE_TALENT,OPEN_STATE_SHOP_TYPE_BLACKSMITH,OPEN_STATE_SHOP_TYPE_PAIMON,OPEN_STATE_WEAPON_AWAKEN, + OPEN_STATE_WEAPON_PROMOTE,OPEN_STATE_AVATAR_PROMOTE,OPEN_STATE_AVATAR_TALENT,OPEN_STATE_WEAPON_UPGRADE,OPEN_STATE_RESIN,OPEN_STATE_RELIQUARY_UPGRADE, + OPEN_STATE_SHOP_TYPE_VIRTUAL_SHOP,OPEN_STATE_RELIQUARY_PROMOTE); + */ + //For development. Remove entry when properly implemented + private static Set devOpenStates = Set.of( + OPEN_STATE_PAIMON, + OPEN_STATE_PAIMON_NAVIGATION, + OPEN_STATE_AVATAR_PROMOTE, + OPEN_STATE_AVATAR_TALENT, + OPEN_STATE_WEAPON_PROMOTE, + OPEN_STATE_WEAPON_AWAKEN, + OPEN_STATE_QUEST_REMIND, + OPEN_STATE_GAME_GUIDE, + OPEN_STATE_COOK, + OPEN_STATE_WEAPON_UPGRADE, + OPEN_STATE_RELIQUARY_UPGRADE, + OPEN_STATE_RELIQUARY_PROMOTE, + OPEN_STATE_WEAPON_PROMOTE_GUIDE, + OPEN_STATE_WEAPON_CHANGE_GUIDE, + OPEN_STATE_PLAYER_LVUP_GUIDE, + OPEN_STATE_FRESHMAN_GUIDE, + OPEN_STATE_SKIP_FRESHMAN_GUIDE, + OPEN_STATE_GUIDE_MOVE_CAMERA, + OPEN_STATE_GUIDE_SCALE_CAMERA, + OPEN_STATE_GUIDE_KEYBOARD, + OPEN_STATE_GUIDE_MOVE, + OPEN_STATE_GUIDE_JUMP, + OPEN_STATE_GUIDE_SPRINT, + OPEN_STATE_GUIDE_MAP, + OPEN_STATE_GUIDE_ATTACK, + OPEN_STATE_GUIDE_FLY, + OPEN_STATE_GUIDE_TALENT, + OPEN_STATE_GUIDE_RELIC, + OPEN_STATE_GUIDE_RELIC_PROM, + OPEN_STATE_COMBINE, + OPEN_STATE_GACHA, + OPEN_STATE_GUIDE_GACHA, + OPEN_STATE_GUIDE_TEAM, + OPEN_STATE_GUIDE_PROUD, + OPEN_STATE_GUIDE_AVATAR_PROMOTE, + OPEN_STATE_GUIDE_ADVENTURE_CARD, + OPEN_STATE_FORGE, + OPEN_STATE_GUIDE_BAG, + OPEN_STATE_EXPEDITION, + OPEN_STATE_GUIDE_ADVENTURE_DAILYTASK, + OPEN_STATE_GUIDE_ADVENTURE_DUNGEON, + OPEN_STATE_TOWER, + OPEN_STATE_WORLD_STAMINA, + OPEN_STATE_TOWER_FIRST_ENTER, + OPEN_STATE_RESIN, + OPEN_STATE_LIMIT_REGION_FRESHMEAT, + OPEN_STATE_LIMIT_REGION_GLOBAL, + OPEN_STATE_MULTIPLAYER, + OPEN_STATE_GUIDE_MOUSEPC, + OPEN_STATE_GUIDE_MULTIPLAYER, + OPEN_STATE_GUIDE_DUNGEONREWARD, + OPEN_STATE_GUIDE_BLOSSOM, + OPEN_STATE_AVATAR_FASHION, + OPEN_STATE_PHOTOGRAPH, + OPEN_STATE_GUIDE_KSLQUEST, + OPEN_STATE_PERSONAL_LINE, + OPEN_STATE_GUIDE_PERSONAL_LINE, + OPEN_STATE_GUIDE_APPEARANCE, + OPEN_STATE_GUIDE_PROCESS, + OPEN_STATE_GUIDE_PERSONAL_LINE_KEY, + OPEN_STATE_GUIDE_WIDGET, + OPEN_STATE_GUIDE_ACTIVITY_SKILL_ASTER, + OPEN_STATE_GUIDE_COLDCLIMATE, + OPEN_STATE_DERIVATIVE_MALL, + OPEN_STATE_GUIDE_EXITMULTIPLAYER, + OPEN_STATE_GUIDE_THEATREMACHANICUS_BUILD, + OPEN_STATE_GUIDE_THEATREMACHANICUS_REBUILD, + OPEN_STATE_GUIDE_THEATREMACHANICUS_CARD, + OPEN_STATE_GUIDE_THEATREMACHANICUS_MONSTER, + OPEN_STATE_GUIDE_THEATREMACHANICUS_MISSION_CHECK, + OPEN_STATE_GUIDE_THEATREMACHANICUS_BUILD_SELECT, + OPEN_STATE_GUIDE_THEATREMACHANICUS_CHALLENGE_START, + OPEN_STATE_GUIDE_CONVERT, + OPEN_STATE_GUIDE_THEATREMACHANICUS_MULTIPLAYER, + OPEN_STATE_GUIDE_COOP_TASK, + OPEN_STATE_GUIDE_HOMEWORLD_ADEPTIABODE, + OPEN_STATE_GUIDE_HOMEWORLD_DEPLOY, + OPEN_STATE_GUIDE_CHANNELLERSLAB_EQUIP, + OPEN_STATE_GUIDE_CHANNELLERSLAB_MP_SOLUTION, + OPEN_STATE_GUIDE_CHANNELLERSLAB_POWER, + OPEN_STATE_GUIDE_HIDEANDSEEK_SKILL, + OPEN_STATE_GUIDE_HOMEWORLD_MAPLIST, + OPEN_STATE_GUIDE_RELICRESOLVE, + OPEN_STATE_GUIDE_GGUIDE, + OPEN_STATE_GUIDE_GGUIDE_HINT, + OPEN_STATE_GUIDE_RIGHT_TEAM, // mobile phone only! + OPEN_STATE_CITY_REPUATION_MENGDE, + OPEN_STATE_CITY_REPUATION_LIYUE, + OPEN_STATE_CITY_REPUATION_UI_HINT, + OPEN_STATE_CITY_REPUATION_INAZUMA, + OPEN_STATE_SHOP_TYPE_MALL, + OPEN_STATE_SHOP_TYPE_RECOMMANDED, + OPEN_STATE_SHOP_TYPE_GENESISCRYSTAL, + OPEN_STATE_SHOP_TYPE_GIFTPACKAGE, + OPEN_STATE_SHOP_TYPE_PAIMON, + OPEN_STATE_SHOP_TYPE_CITY, + OPEN_STATE_SHOP_TYPE_BLACKSMITH, + OPEN_STATE_SHOP_TYPE_GROCERY, + OPEN_STATE_SHOP_TYPE_FOOD, + OPEN_STATE_SHOP_TYPE_SEA_LAMP, + OPEN_STATE_SHOP_TYPE_VIRTUAL_SHOP, + OPEN_STATE_SHOP_TYPE_LIYUE_GROCERY, + OPEN_STATE_SHOP_TYPE_LIYUE_SOUVENIR, + OPEN_STATE_SHOP_TYPE_LIYUE_RESTAURANT, + OPEN_STATE_SHOP_TYPE_INAZUMA_SOUVENIR, + OPEN_STATE_SHOP_TYPE_NPC_TOMOKI, + OPEN_ADVENTURE_MANUAL, + OPEN_ADVENTURE_MANUAL_CITY_MENGDE, + OPEN_ADVENTURE_MANUAL_CITY_LIYUE, + OPEN_ADVENTURE_MANUAL_MONSTER, + OPEN_ADVENTURE_MANUAL_BOSS_DUNGEON, + OPEN_STATE_ACTIVITY_SEALAMP, + OPEN_STATE_ACTIVITY_SEALAMP_TAB2, + OPEN_STATE_ACTIVITY_SEALAMP_TAB3, + OPEN_STATE_BATTLE_PASS, + OPEN_STATE_BATTLE_PASS_ENTRY, + OPEN_STATE_ACTIVITY_CRUCIBLE, + OPEN_STATE_ACTIVITY_NEWBEEBOUNS_OPEN, + OPEN_STATE_ACTIVITY_NEWBEEBOUNS_CLOSE, + OPEN_STATE_ACTIVITY_ENTRY_OPEN, + OPEN_STATE_MENGDE_INFUSEDCRYSTAL, + OPEN_STATE_LIYUE_INFUSEDCRYSTAL, + OPEN_STATE_SNOW_MOUNTAIN_ELDER_TREE, + OPEN_STATE_MIRACLE_RING, + OPEN_STATE_COOP_LINE, + OPEN_STATE_INAZUMA_INFUSEDCRYSTAL, + OPEN_STATE_FISH, + OPEN_STATE_GUIDE_SUMO_TEAM_SKILL, + OPEN_STATE_GUIDE_FISH_RECIPE, + OPEN_STATE_HOME, + OPEN_STATE_ACTIVITY_HOMEWORLD, + OPEN_STATE_ADEPTIABODE, + OPEN_STATE_HOME_AVATAR, + OPEN_STATE_HOME_EDIT, + OPEN_STATE_HOME_EDIT_TIPS, + OPEN_STATE_RELIQUARY_DECOMPOSE, + OPEN_STATE_ACTIVITY_H5, + OPEN_STATE_ORAIONOKAMI, + OPEN_STATE_GUIDE_CHESS_MISSION_CHECK, + OPEN_STATE_GUIDE_CHESS_BUILD, + OPEN_STATE_GUIDE_CHESS_WIND_TOWER_CIRCLE, + OPEN_STATE_GUIDE_CHESS_CARD_SELECT, + OPEN_STATE_INAZUMA_MAINQUEST_FINISHED, + OPEN_STATE_PAIMON_LVINFO, + OPEN_STATE_TELEPORT_HUD, + OPEN_STATE_GUIDE_MAP_UNLOCK, + OPEN_STATE_GUIDE_PAIMON_LVINFO, + OPEN_STATE_GUIDE_AMBORTRANSPORT, + OPEN_STATE_GUIDE_FLY_SECOND, + OPEN_STATE_GUIDE_KAEYA_CLUE, + OPEN_STATE_CAPTURE_CODEX, + OPEN_STATE_ACTIVITY_FISH_OPEN, + OPEN_STATE_ACTIVITY_FISH_CLOSE, + OPEN_STATE_GUIDE_ROGUE_MAP, + OPEN_STATE_GUIDE_ROGUE_RUNE, + OPEN_STATE_GUIDE_BARTENDER_FORMULA, + OPEN_STATE_GUIDE_BARTENDER_MIX, + OPEN_STATE_GUIDE_BARTENDER_CUP, + OPEN_STATE_GUIDE_MAIL_FAVORITES, + OPEN_STATE_GUIDE_POTION_CONFIGURE, + OPEN_STATE_GUIDE_LANV2_FIREWORK, + OPEN_STATE_LOADINGTIPS_ENKANOMIYA, + OPEN_STATE_MICHIAE_CASKET, + OPEN_STATE_MAIL_COLLECT_UNLOCK_RED_POINT, + OPEN_STATE_LUMEN_STONE, + OPEN_STATE_GUIDE_CRYSTALLINK_BUFF + ); + + public PlayerOpenStateManager(Player player) { + this.openStateMap = new HashMap<>(); + this.player = player; + } + + public void setPlayer(Player player) { + this.player = player; + } + + public Integer getOpenState(OpenState openState) { + return this.openStateMap.getOrDefault(openState.getValue(), 0); + } + public void setOpenState(OpenState openState, Integer value) { + Integer previousValue = this.openStateMap.getOrDefault(openState.getValue(),0); + if(!(value == previousValue)) { + this.openStateMap.put(openState.getValue(), value); + player.getSession().send(new PacketOpenStateChangeNotify(openState.getValue(),value)); + } else { + Grasscutter.getLogger().debug("Warning: OpenState {} is already set to {}!", openState, value); + } + } + + public void setOpenStates(Map openStatesChanged) { + for(Map.Entry entry : openStatesChanged.entrySet()) { + setOpenState(entry.getKey(), entry.getValue()); + } + } + + public void onNewPlayerCreate() { + //newPlayerOpenStates.forEach(os -> this.setOpenState(os, 1)); + //setAllOpenStates(); + devOpenStates.forEach(os -> this.setOpenState(os, 1)); + } + public void onPlayerLogin() { + /* + //little hack to give all openStates on second login + if(openStateMap.containsKey(OPEN_STATE_FRESHMAN_GUIDE.getValue())) { + setAllOpenStates(); + } + */ + player.getSession().send(new PacketOpenStateUpdateNotify(player)); + } + + public void setAllOpenStates() { + Stream.of(OpenState.values()).forEach(os -> this.setOpenState(os, 1)); + } +} \ No newline at end of file diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerLoginReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerLoginReq.java index d5aea0db1..4578e7d1f 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerLoginReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerLoginReq.java @@ -17,7 +17,7 @@ import static emu.grasscutter.Configuration.ACCOUNT; @Opcodes(PacketOpcodes.PlayerLoginReq) // Sends initial data packets public class HandlerPlayerLoginReq extends PacketHandler { - + @Override public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { // Check @@ -28,18 +28,20 @@ public class HandlerPlayerLoginReq extends PacketHandler { // Parse request PlayerLoginReq req = PlayerLoginReq.parseFrom(payload); - + // Authenticate session if (!req.getToken().equals(session.getAccount().getToken())) { session.close(); return; } - + // Load character from db Player player = session.getPlayer(); - + // Show opening cutscene if player has no avatars if (player.getAvatars().getAvatarCount() == 0) { + // Set New Player OpenStates + player.getOpenStateManager().onNewPlayerCreate(); // Pick character session.setState(SessionState.PICKING_CHARACTER); session.send(new BasePacket(PacketOpcodes.DoSetPlayerBornDataNotify)); diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetOpenStateReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetOpenStateReq.java new file mode 100644 index 000000000..f7f259a32 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetOpenStateReq.java @@ -0,0 +1,26 @@ +package emu.grasscutter.server.packet.recv; + +import emu.grasscutter.game.props.OpenState; +import emu.grasscutter.net.packet.Opcodes; +import emu.grasscutter.net.packet.PacketHandler; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.SetOpenStateReqOuterClass.SetOpenStateReq; +import emu.grasscutter.server.game.GameSession; +import emu.grasscutter.server.packet.send.PacketSetOpenStateRsp; + +@Opcodes(PacketOpcodes.SetOpenStateReq) +public class HandlerSetOpenStateReq extends PacketHandler { + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + var req = SetOpenStateReq.parseFrom(payload); + int openState = req.getKey(); + int value = req.getValue(); + + session.getPlayer().getOpenStateManager().setOpenState(OpenState.getTypeByValue(openState), value); + //Client Automatically Updates its OpenStateMap, no need to send OpenStateUpdateNotify + + session.send(new PacketSetOpenStateRsp(openState,value)); + } + +} \ No newline at end of file diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketOpenStateChangeNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketOpenStateChangeNotify.java new file mode 100644 index 000000000..fafc5dc8f --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketOpenStateChangeNotify.java @@ -0,0 +1,19 @@ +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.net.packet.BasePacket; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.OpenStateChangeNotifyOuterClass.OpenStateChangeNotify; + +//Sets openState to value +public class PacketOpenStateChangeNotify extends BasePacket { + + public PacketOpenStateChangeNotify(int openState, int value) { + super(PacketOpcodes.OpenStateChangeNotify); + + OpenStateChangeNotify proto = OpenStateChangeNotify.newBuilder() + .putOpenStateMap(openState,value).build(); + + this.setData(proto); + } + +} \ No newline at end of file diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketOpenStateUpdateNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketOpenStateUpdateNotify.java index df74264ca..62ec01ea7 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketOpenStateUpdateNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketOpenStateUpdateNotify.java @@ -1,22 +1,25 @@ package emu.grasscutter.server.packet.send; +import emu.grasscutter.game.player.Player; +import emu.grasscutter.game.player.PlayerOpenStateManager; import emu.grasscutter.game.props.OpenState; import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.proto.OpenStateUpdateNotifyOuterClass.OpenStateUpdateNotify; +import java.util.Map; +/* + Must be sent on login for openStates to work + Tells the client to update its openStateMap for the keys sent. value is irrelevant + */ public class PacketOpenStateUpdateNotify extends BasePacket { - - public PacketOpenStateUpdateNotify() { + + public PacketOpenStateUpdateNotify(Player player) { super(PacketOpcodes.OpenStateUpdateNotify); - + OpenStateUpdateNotify.Builder proto = OpenStateUpdateNotify.newBuilder(); - - for (OpenState type : OpenState.values()) { - if (type.getValue() > 0) { - proto.putOpenStateMap(type.getValue(), 1); - } - } + + proto.putAllOpenStateMap(player.getOpenStateManager().getOpenStateMap()).build(); this.setData(proto); } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketSetOpenStateRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketSetOpenStateRsp.java new file mode 100644 index 000000000..de94fdc90 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketSetOpenStateRsp.java @@ -0,0 +1,18 @@ +package emu.grasscutter.server.packet.send; + +import emu.grasscutter.net.packet.BasePacket; +import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.net.proto.SetOpenStateRspOuterClass.SetOpenStateRsp; + +public class PacketSetOpenStateRsp extends BasePacket { + + public PacketSetOpenStateRsp(int openState, int value) { + super(PacketOpcodes.SetOpenStateRsp); + + SetOpenStateRsp proto = SetOpenStateRsp.newBuilder() + .setKey(openState).setValue(value).build(); + + this.setData(proto); + } + +} \ No newline at end of file From 3eb9a44e513ed16d332b20297102faa11519237b Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Mon, 18 Jul 2022 01:56:26 -0700 Subject: [PATCH 16/61] Update dependencies --- build.gradle | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/build.gradle b/build.gradle index 6872c1e49..6ff91114b 100644 --- a/build.gradle +++ b/build.gradle @@ -61,15 +61,18 @@ repositories { dependencies { implementation fileTree(dir: 'lib', include: ['*.jar']) - implementation group: 'org.slf4j', name: 'slf4j-api', version: '1.7.32' - implementation group: 'ch.qos.logback', name: 'logback-core', version: '1.2.9' - implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.9' + implementation group: 'org.slf4j', name: 'slf4j-api', version: '1.7.36' + implementation group: 'ch.qos.logback', name: 'logback-core', version: '1.2.11' + implementation group: 'ch.qos.logback', name: 'logback-classic', version: '1.2.11' implementation group: 'org.jline', name: 'jline', version: '3.21.0' implementation group: 'org.jline', name: 'jline-terminal-jna', version: '3.21.0' implementation group: 'net.java.dev.jna', name: 'jna', version: '5.10.0' - implementation group: 'io.netty', name: 'netty-all', version: '4.1.71.Final' + implementation group: 'io.netty', name: 'netty-common', version: '4.1.79.Final' + implementation group: 'io.netty', name: 'netty-handler', version: '4.1.79.Final' + implementation group: 'io.netty', name: 'netty-transport-native-epoll', version: '4.1.79.Final' + implementation group: 'io.netty', name: 'netty-transport-native-kqueue', version: '4.1.79.Final' implementation group: 'com.google.code.gson', name: 'gson', version: '2.9.0' implementation group: 'com.google.protobuf', name: 'protobuf-java', version: '3.18.2' From 2e85834e9caf027baa2b5657038ec125b41d7623 Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Mon, 18 Jul 2022 02:28:38 -0700 Subject: [PATCH 17/61] Update OpenState protos and rework OpenStateManager OpenState map no longer contains default openstates, they should not be saved in the database for efficiency reasons. --- .../game/player/PlayerOpenStateManager.java | 49 ++- .../emu/grasscutter/game/props/OpenState.java | 347 +++++++++--------- .../packet/recv/HandlerPlayerLoginReq.java | 2 - .../send/PacketOpenStateUpdateNotify.java | 14 +- 4 files changed, 211 insertions(+), 201 deletions(-) diff --git a/src/main/java/emu/grasscutter/game/player/PlayerOpenStateManager.java b/src/main/java/emu/grasscutter/game/player/PlayerOpenStateManager.java index 3bf1bf8cc..562c81ec9 100644 --- a/src/main/java/emu/grasscutter/game/player/PlayerOpenStateManager.java +++ b/src/main/java/emu/grasscutter/game/player/PlayerOpenStateManager.java @@ -17,9 +17,11 @@ import static emu.grasscutter.game.props.OpenState.*; @Entity public class PlayerOpenStateManager { - @Transient private Player player; - @Getter private Map openStateMap; + + // Map of all open states that this player has. Do not put default values here. + private Map map; + /* //DO NOT MODIFY. Based on conversation of official server and client, game version 2.7 private static Set newPlayerOpenStates = Set.of(OPEN_STATE_DERIVATIVE_MALL,OPEN_STATE_PHOTOGRAPH,OPEN_STATE_BATTLE_PASS,OPEN_STATE_SHOP_TYPE_GENESISCRYSTAL,OPEN_STATE_SHOP_TYPE_RECOMMANDED, @@ -27,8 +29,10 @@ public class PlayerOpenStateManager { OPEN_STATE_WEAPON_PROMOTE,OPEN_STATE_AVATAR_PROMOTE,OPEN_STATE_AVATAR_TALENT,OPEN_STATE_WEAPON_UPGRADE,OPEN_STATE_RESIN,OPEN_STATE_RELIQUARY_UPGRADE, OPEN_STATE_SHOP_TYPE_VIRTUAL_SHOP,OPEN_STATE_RELIQUARY_PROMOTE); */ - //For development. Remove entry when properly implemented - private static Set devOpenStates = Set.of( + + // For development. Remove entry when properly implemented + // TODO - Set as boolean in OpenState + public static final Set DEV_OPEN_STATES = Set.of( OPEN_STATE_PAIMON, OPEN_STATE_PAIMON_NAVIGATION, OPEN_STATE_AVATAR_PROMOTE, @@ -75,7 +79,6 @@ public class PlayerOpenStateManager { OPEN_STATE_TOWER_FIRST_ENTER, OPEN_STATE_RESIN, OPEN_STATE_LIMIT_REGION_FRESHMEAT, - OPEN_STATE_LIMIT_REGION_GLOBAL, OPEN_STATE_MULTIPLAYER, OPEN_STATE_GUIDE_MOUSEPC, OPEN_STATE_GUIDE_MULTIPLAYER, @@ -114,7 +117,7 @@ public class PlayerOpenStateManager { OPEN_STATE_GUIDE_RELICRESOLVE, OPEN_STATE_GUIDE_GGUIDE, OPEN_STATE_GUIDE_GGUIDE_HINT, - OPEN_STATE_GUIDE_RIGHT_TEAM, // mobile phone only! + OPEN_STATE_GUIDE_QUICK_TEAMMEMBERCHANGE, OPEN_STATE_CITY_REPUATION_MENGDE, OPEN_STATE_CITY_REPUATION_LIYUE, OPEN_STATE_CITY_REPUATION_UI_HINT, @@ -195,10 +198,9 @@ public class PlayerOpenStateManager { OPEN_STATE_MAIL_COLLECT_UNLOCK_RED_POINT, OPEN_STATE_LUMEN_STONE, OPEN_STATE_GUIDE_CRYSTALLINK_BUFF - ); + ); public PlayerOpenStateManager(Player player) { - this.openStateMap = new HashMap<>(); this.player = player; } @@ -206,13 +208,19 @@ public class PlayerOpenStateManager { this.player = player; } - public Integer getOpenState(OpenState openState) { - return this.openStateMap.getOrDefault(openState.getValue(), 0); + public Map getOpenStateMap() { + if (this.map == null) this.map = new HashMap<>(); + return this.map; + } + + public int getOpenState(OpenState openState) { + return this.map.getOrDefault(openState.getValue(), 0); } + public void setOpenState(OpenState openState, Integer value) { - Integer previousValue = this.openStateMap.getOrDefault(openState.getValue(),0); + Integer previousValue = this.map.getOrDefault(openState.getValue(),0); if(!(value == previousValue)) { - this.openStateMap.put(openState.getValue(), value); + this.map.put(openState.getValue(), value); player.getSession().send(new PacketOpenStateChangeNotify(openState.getValue(),value)); } else { Grasscutter.getLogger().debug("Warning: OpenState {} is already set to {}!", openState, value); @@ -225,22 +233,7 @@ public class PlayerOpenStateManager { } } - public void onNewPlayerCreate() { - //newPlayerOpenStates.forEach(os -> this.setOpenState(os, 1)); - //setAllOpenStates(); - devOpenStates.forEach(os -> this.setOpenState(os, 1)); - } public void onPlayerLogin() { - /* - //little hack to give all openStates on second login - if(openStateMap.containsKey(OPEN_STATE_FRESHMAN_GUIDE.getValue())) { - setAllOpenStates(); - } - */ - player.getSession().send(new PacketOpenStateUpdateNotify(player)); - } - - public void setAllOpenStates() { - Stream.of(OpenState.values()).forEach(os -> this.setOpenState(os, 1)); + player.getSession().send(new PacketOpenStateUpdateNotify(this)); } } \ No newline at end of file diff --git a/src/main/java/emu/grasscutter/game/props/OpenState.java b/src/main/java/emu/grasscutter/game/props/OpenState.java index d566e9051..560edf5f2 100644 --- a/src/main/java/emu/grasscutter/game/props/OpenState.java +++ b/src/main/java/emu/grasscutter/game/props/OpenState.java @@ -8,173 +8,186 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; public enum OpenState { - OPEN_STATE_NONE(0), - OPEN_STATE_PAIMON(1), - OPEN_STATE_PAIMON_NAVIGATION(2), - OPEN_STATE_AVATAR_PROMOTE(3), - OPEN_STATE_AVATAR_TALENT(4), - OPEN_STATE_WEAPON_PROMOTE(5), - OPEN_STATE_WEAPON_AWAKEN(6), - OPEN_STATE_QUEST_REMIND(7), - OPEN_STATE_GAME_GUIDE(8), - OPEN_STATE_COOK(9), - OPEN_STATE_WEAPON_UPGRADE(10), - OPEN_STATE_RELIQUARY_UPGRADE(11), - OPEN_STATE_RELIQUARY_PROMOTE(12), - OPEN_STATE_WEAPON_PROMOTE_GUIDE(13), - OPEN_STATE_WEAPON_CHANGE_GUIDE(14), - OPEN_STATE_PLAYER_LVUP_GUIDE(15), - OPEN_STATE_FRESHMAN_GUIDE(16), - OPEN_STATE_SKIP_FRESHMAN_GUIDE(17), - OPEN_STATE_GUIDE_MOVE_CAMERA(18), - OPEN_STATE_GUIDE_SCALE_CAMERA(19), - OPEN_STATE_GUIDE_KEYBOARD(20), - OPEN_STATE_GUIDE_MOVE(21), - OPEN_STATE_GUIDE_JUMP(22), - OPEN_STATE_GUIDE_SPRINT(23), - OPEN_STATE_GUIDE_MAP(24), - OPEN_STATE_GUIDE_ATTACK(25), - OPEN_STATE_GUIDE_FLY(26), - OPEN_STATE_GUIDE_TALENT(27), - OPEN_STATE_GUIDE_RELIC(28), - OPEN_STATE_GUIDE_RELIC_PROM(29), - OPEN_STATE_COMBINE(30), - OPEN_STATE_GACHA(31), - OPEN_STATE_GUIDE_GACHA(32), - OPEN_STATE_GUIDE_TEAM(33), - OPEN_STATE_GUIDE_PROUD(34), - OPEN_STATE_GUIDE_AVATAR_PROMOTE(35), - OPEN_STATE_GUIDE_ADVENTURE_CARD(36), - OPEN_STATE_FORGE(37), - OPEN_STATE_GUIDE_BAG(38), - OPEN_STATE_EXPEDITION(39), - OPEN_STATE_GUIDE_ADVENTURE_DAILYTASK(40), - OPEN_STATE_GUIDE_ADVENTURE_DUNGEON(41), - OPEN_STATE_TOWER(42), - OPEN_STATE_WORLD_STAMINA(43), - OPEN_STATE_TOWER_FIRST_ENTER(44), - OPEN_STATE_RESIN(45), - OPEN_STATE_LIMIT_REGION_FRESHMEAT(47), - OPEN_STATE_LIMIT_REGION_GLOBAL(48), - OPEN_STATE_MULTIPLAYER(49), - OPEN_STATE_GUIDE_MOUSEPC(50), - OPEN_STATE_GUIDE_MULTIPLAYER(51), - OPEN_STATE_GUIDE_DUNGEONREWARD(52), - OPEN_STATE_GUIDE_BLOSSOM(53), - OPEN_STATE_AVATAR_FASHION(54), - OPEN_STATE_PHOTOGRAPH(55), - OPEN_STATE_GUIDE_KSLQUEST(56), - OPEN_STATE_PERSONAL_LINE(57), - OPEN_STATE_GUIDE_PERSONAL_LINE(58), - OPEN_STATE_GUIDE_APPEARANCE(59), - OPEN_STATE_GUIDE_PROCESS(60), - OPEN_STATE_GUIDE_PERSONAL_LINE_KEY(61), - OPEN_STATE_GUIDE_WIDGET(62), - OPEN_STATE_GUIDE_ACTIVITY_SKILL_ASTER(63), - OPEN_STATE_GUIDE_COLDCLIMATE(64), - OPEN_STATE_DERIVATIVE_MALL(65), - OPEN_STATE_GUIDE_EXITMULTIPLAYER(66), - OPEN_STATE_GUIDE_THEATREMACHANICUS_BUILD(67), - OPEN_STATE_GUIDE_THEATREMACHANICUS_REBUILD(68), - OPEN_STATE_GUIDE_THEATREMACHANICUS_CARD(69), - OPEN_STATE_GUIDE_THEATREMACHANICUS_MONSTER(70), - OPEN_STATE_GUIDE_THEATREMACHANICUS_MISSION_CHECK(71), - OPEN_STATE_GUIDE_THEATREMACHANICUS_BUILD_SELECT(72), - OPEN_STATE_GUIDE_THEATREMACHANICUS_CHALLENGE_START(73), - OPEN_STATE_GUIDE_CONVERT(74), - OPEN_STATE_GUIDE_THEATREMACHANICUS_MULTIPLAYER(75), - OPEN_STATE_GUIDE_COOP_TASK(76), - OPEN_STATE_GUIDE_HOMEWORLD_ADEPTIABODE(77), - OPEN_STATE_GUIDE_HOMEWORLD_DEPLOY(78), - OPEN_STATE_GUIDE_CHANNELLERSLAB_EQUIP(79), - OPEN_STATE_GUIDE_CHANNELLERSLAB_MP_SOLUTION(80), - OPEN_STATE_GUIDE_CHANNELLERSLAB_POWER(81), - OPEN_STATE_GUIDE_HIDEANDSEEK_SKILL(82), - OPEN_STATE_GUIDE_HOMEWORLD_MAPLIST(83), - OPEN_STATE_GUIDE_RELICRESOLVE(84), - OPEN_STATE_GUIDE_GGUIDE(85), - OPEN_STATE_GUIDE_GGUIDE_HINT(86), - OPEN_STATE_GUIDE_RIGHT_TEAM(90), // mobile phone only! - OPEN_STATE_CITY_REPUATION_MENGDE(800), - OPEN_STATE_CITY_REPUATION_LIYUE(801), - OPEN_STATE_CITY_REPUATION_UI_HINT(802), - OPEN_STATE_CITY_REPUATION_INAZUMA(803), - OPEN_STATE_SHOP_TYPE_MALL(900), - OPEN_STATE_SHOP_TYPE_RECOMMANDED(901), - OPEN_STATE_SHOP_TYPE_GENESISCRYSTAL(902), - OPEN_STATE_SHOP_TYPE_GIFTPACKAGE(903), - OPEN_STATE_SHOP_TYPE_PAIMON(1001), - OPEN_STATE_SHOP_TYPE_CITY(1002), - OPEN_STATE_SHOP_TYPE_BLACKSMITH(1003), - OPEN_STATE_SHOP_TYPE_GROCERY(1004), - OPEN_STATE_SHOP_TYPE_FOOD(1005), - OPEN_STATE_SHOP_TYPE_SEA_LAMP(1006), - OPEN_STATE_SHOP_TYPE_VIRTUAL_SHOP(1007), - OPEN_STATE_SHOP_TYPE_LIYUE_GROCERY(1008), - OPEN_STATE_SHOP_TYPE_LIYUE_SOUVENIR(1009), - OPEN_STATE_SHOP_TYPE_LIYUE_RESTAURANT(1010), - OPEN_STATE_SHOP_TYPE_INAZUMA_SOUVENIR(1011), - OPEN_STATE_SHOP_TYPE_NPC_TOMOKI(1012), - OPEN_ADVENTURE_MANUAL(1100), - OPEN_ADVENTURE_MANUAL_CITY_MENGDE(1101), - OPEN_ADVENTURE_MANUAL_CITY_LIYUE(1102), - OPEN_ADVENTURE_MANUAL_MONSTER(1103), - OPEN_ADVENTURE_MANUAL_BOSS_DUNGEON(1104), - OPEN_STATE_ACTIVITY_SEALAMP(1200), - OPEN_STATE_ACTIVITY_SEALAMP_TAB2(1201), - OPEN_STATE_ACTIVITY_SEALAMP_TAB3(1202), - OPEN_STATE_BATTLE_PASS(1300), - OPEN_STATE_BATTLE_PASS_ENTRY(1301), - OPEN_STATE_ACTIVITY_CRUCIBLE(1400), - OPEN_STATE_ACTIVITY_NEWBEEBOUNS_OPEN(1401), - OPEN_STATE_ACTIVITY_NEWBEEBOUNS_CLOSE(1402), - OPEN_STATE_ACTIVITY_ENTRY_OPEN(1403), - OPEN_STATE_MENGDE_INFUSEDCRYSTAL(1404), - OPEN_STATE_LIYUE_INFUSEDCRYSTAL(1405), - OPEN_STATE_SNOW_MOUNTAIN_ELDER_TREE(1406), - OPEN_STATE_MIRACLE_RING(1407), - OPEN_STATE_COOP_LINE(1408), - OPEN_STATE_INAZUMA_INFUSEDCRYSTAL(1409), - OPEN_STATE_FISH(1410), - OPEN_STATE_GUIDE_SUMO_TEAM_SKILL(1411), - OPEN_STATE_GUIDE_FISH_RECIPE(1412), - OPEN_STATE_HOME(1500), - OPEN_STATE_ACTIVITY_HOMEWORLD(1501), - OPEN_STATE_ADEPTIABODE(1502), - OPEN_STATE_HOME_AVATAR(1503), - OPEN_STATE_HOME_EDIT(1504), - OPEN_STATE_HOME_EDIT_TIPS(1505), - OPEN_STATE_RELIQUARY_DECOMPOSE(1600), - OPEN_STATE_ACTIVITY_H5(1700), - OPEN_STATE_ORAIONOKAMI(2000), - OPEN_STATE_GUIDE_CHESS_MISSION_CHECK(2001), - OPEN_STATE_GUIDE_CHESS_BUILD(2002), - OPEN_STATE_GUIDE_CHESS_WIND_TOWER_CIRCLE(2003), - OPEN_STATE_GUIDE_CHESS_CARD_SELECT(2004), - OPEN_STATE_INAZUMA_MAINQUEST_FINISHED(2005), - OPEN_STATE_PAIMON_LVINFO(2100), - OPEN_STATE_TELEPORT_HUD(2101), - OPEN_STATE_GUIDE_MAP_UNLOCK(2102), - OPEN_STATE_GUIDE_PAIMON_LVINFO(2103), - OPEN_STATE_GUIDE_AMBORTRANSPORT(2104), - OPEN_STATE_GUIDE_FLY_SECOND(2105), - OPEN_STATE_GUIDE_KAEYA_CLUE(2106), - OPEN_STATE_CAPTURE_CODEX(2107), - OPEN_STATE_ACTIVITY_FISH_OPEN(2200), - OPEN_STATE_ACTIVITY_FISH_CLOSE(2201), - OPEN_STATE_GUIDE_ROGUE_MAP(2205), - OPEN_STATE_GUIDE_ROGUE_RUNE(2206), - OPEN_STATE_GUIDE_BARTENDER_FORMULA(2210), - OPEN_STATE_GUIDE_BARTENDER_MIX(2211), - OPEN_STATE_GUIDE_BARTENDER_CUP(2212), - OPEN_STATE_GUIDE_MAIL_FAVORITES(2400), - OPEN_STATE_GUIDE_POTION_CONFIGURE(2401), - OPEN_STATE_GUIDE_LANV2_FIREWORK(2402), - OPEN_STATE_LOADINGTIPS_ENKANOMIYA(2403), - OPEN_STATE_MICHIAE_CASKET(2500), - OPEN_STATE_MAIL_COLLECT_UNLOCK_RED_POINT(2501), - OPEN_STATE_LUMEN_STONE(2600), - OPEN_STATE_GUIDE_CRYSTALLINK_BUFF(2601); + OPEN_STATE_NONE (0), + OPEN_STATE_PAIMON (1), + OPEN_STATE_PAIMON_NAVIGATION (2), + OPEN_STATE_AVATAR_PROMOTE (3), + OPEN_STATE_AVATAR_TALENT (4), + OPEN_STATE_WEAPON_PROMOTE (5), + OPEN_STATE_WEAPON_AWAKEN (6), + OPEN_STATE_QUEST_REMIND (7), + OPEN_STATE_GAME_GUIDE (8), + OPEN_STATE_COOK (9), + OPEN_STATE_WEAPON_UPGRADE (10), + OPEN_STATE_RELIQUARY_UPGRADE (11), + OPEN_STATE_RELIQUARY_PROMOTE (12), + OPEN_STATE_WEAPON_PROMOTE_GUIDE (13), + OPEN_STATE_WEAPON_CHANGE_GUIDE (14), + OPEN_STATE_PLAYER_LVUP_GUIDE (15), + OPEN_STATE_FRESHMAN_GUIDE (16), + OPEN_STATE_SKIP_FRESHMAN_GUIDE (17), + OPEN_STATE_GUIDE_MOVE_CAMERA (18), + OPEN_STATE_GUIDE_SCALE_CAMERA (19), + OPEN_STATE_GUIDE_KEYBOARD (20), + OPEN_STATE_GUIDE_MOVE (21), + OPEN_STATE_GUIDE_JUMP (22), + OPEN_STATE_GUIDE_SPRINT (23), + OPEN_STATE_GUIDE_MAP (24), + OPEN_STATE_GUIDE_ATTACK (25), + OPEN_STATE_GUIDE_FLY (26), + OPEN_STATE_GUIDE_TALENT (27), + OPEN_STATE_GUIDE_RELIC (28), + OPEN_STATE_GUIDE_RELIC_PROM (29), + OPEN_STATE_COMBINE (30), + OPEN_STATE_GACHA (31), + OPEN_STATE_GUIDE_GACHA (32), + OPEN_STATE_GUIDE_TEAM (33), + OPEN_STATE_GUIDE_PROUD (34), + OPEN_STATE_GUIDE_AVATAR_PROMOTE (35), + OPEN_STATE_GUIDE_ADVENTURE_CARD (36), + OPEN_STATE_FORGE (37), + OPEN_STATE_GUIDE_BAG (38), + OPEN_STATE_EXPEDITION (39), + OPEN_STATE_GUIDE_ADVENTURE_DAILYTASK (40), + OPEN_STATE_GUIDE_ADVENTURE_DUNGEON (41), + OPEN_STATE_TOWER (42), + OPEN_STATE_WORLD_STAMINA (43), + OPEN_STATE_TOWER_FIRST_ENTER (44), + OPEN_STATE_RESIN (45), + OPEN_STATE_LIMIT_REGION_FRESHMEAT (47), + OPEN_STATE_LIMIT_REGION_GLOBAL (48), + OPEN_STATE_MULTIPLAYER (49), + OPEN_STATE_GUIDE_MOUSEPC (50), + OPEN_STATE_GUIDE_MULTIPLAYER (51), + OPEN_STATE_GUIDE_DUNGEONREWARD (52), + OPEN_STATE_GUIDE_BLOSSOM (53), + OPEN_STATE_AVATAR_FASHION (54), + OPEN_STATE_PHOTOGRAPH (55), + OPEN_STATE_GUIDE_KSLQUEST (56), + OPEN_STATE_PERSONAL_LINE (57), + OPEN_STATE_GUIDE_PERSONAL_LINE (58), + OPEN_STATE_GUIDE_APPEARANCE (59), + OPEN_STATE_GUIDE_PROCESS (60), + OPEN_STATE_GUIDE_PERSONAL_LINE_KEY (61), + OPEN_STATE_GUIDE_WIDGET (62), + OPEN_STATE_GUIDE_ACTIVITY_SKILL_ASTER (63), + OPEN_STATE_GUIDE_COLDCLIMATE (64), + OPEN_STATE_DERIVATIVE_MALL (65), + OPEN_STATE_GUIDE_EXITMULTIPLAYER (66), + OPEN_STATE_GUIDE_THEATREMACHANICUS_BUILD (67), + OPEN_STATE_GUIDE_THEATREMACHANICUS_REBUILD (68), + OPEN_STATE_GUIDE_THEATREMACHANICUS_CARD (69), + OPEN_STATE_GUIDE_THEATREMACHANICUS_MONSTER (70), + OPEN_STATE_GUIDE_THEATREMACHANICUS_MISSION_CHECK (71), + OPEN_STATE_GUIDE_THEATREMACHANICUS_BUILD_SELECT (72), + OPEN_STATE_GUIDE_THEATREMACHANICUS_CHALLENGE_START (73), + OPEN_STATE_GUIDE_CONVERT (74), + OPEN_STATE_GUIDE_THEATREMACHANICUS_MULTIPLAYER (75), + OPEN_STATE_GUIDE_COOP_TASK (76), + OPEN_STATE_GUIDE_HOMEWORLD_ADEPTIABODE (77), + OPEN_STATE_GUIDE_HOMEWORLD_DEPLOY (78), + OPEN_STATE_GUIDE_CHANNELLERSLAB_EQUIP (79), + OPEN_STATE_GUIDE_CHANNELLERSLAB_MP_SOLUTION (80), + OPEN_STATE_GUIDE_CHANNELLERSLAB_POWER (81), + OPEN_STATE_GUIDE_HIDEANDSEEK_SKILL (82), + OPEN_STATE_GUIDE_HOMEWORLD_MAPLIST (83), + OPEN_STATE_GUIDE_RELICRESOLVE (84), + OPEN_STATE_GUIDE_GGUIDE (85), + OPEN_STATE_GUIDE_GGUIDE_HINT (86), + OPEN_STATE_GUIDE_CHANNELLERSLAB_EQUIP_V2 (87), + OPEN_STATE_GUIDE_CHANNELLERSLAB_MP_SOLUTION_V2 (88), + OPEN_STATE_GUIDE_CHANNELLERSLAB_POWER_V2 (89), + OPEN_STATE_GUIDE_QUICK_TEAMMEMBERCHANGE (90), // Mobile only + OPEN_STATE_GGUIDE_FIRSTSHOW (91), + OPEN_STATE_GGUIDE_MAINPAGE_ENTRY_DISAPPEAR (92), + OPEN_STATE_CITY_REPUATION_MENGDE (800), + OPEN_STATE_CITY_REPUATION_LIYUE (801), + OPEN_STATE_CITY_REPUATION_UI_HINT (802), + OPEN_STATE_CITY_REPUATION_INAZUMA (803), + OPEN_STATE_SHOP_TYPE_MALL (900), + OPEN_STATE_SHOP_TYPE_RECOMMANDED (901), + OPEN_STATE_SHOP_TYPE_GENESISCRYSTAL (902), + OPEN_STATE_SHOP_TYPE_GIFTPACKAGE (903), + OPEN_STATE_SHOP_TYPE_PAIMON (1001), + OPEN_STATE_SHOP_TYPE_CITY (1002), + OPEN_STATE_SHOP_TYPE_BLACKSMITH (1003), + OPEN_STATE_SHOP_TYPE_GROCERY (1004), + OPEN_STATE_SHOP_TYPE_FOOD (1005), + OPEN_STATE_SHOP_TYPE_SEA_LAMP (1006), + OPEN_STATE_SHOP_TYPE_VIRTUAL_SHOP (1007), + OPEN_STATE_SHOP_TYPE_LIYUE_GROCERY (1008), + OPEN_STATE_SHOP_TYPE_LIYUE_SOUVENIR (1009), + OPEN_STATE_SHOP_TYPE_LIYUE_RESTAURANT (1010), + OPEN_STATE_SHOP_TYPE_INAZUMA_SOUVENIR (1011), + OPEN_STATE_SHOP_TYPE_NPC_TOMOKI (1012), + OPEN_STATE_SHOP_TYPE_INAZUMA_SOUVENIR_BLACK_BAR (1013), + OPEN_ADVENTURE_MANUAL (1100), + OPEN_ADVENTURE_MANUAL_CITY_MENGDE (1101), + OPEN_ADVENTURE_MANUAL_CITY_LIYUE (1102), + OPEN_ADVENTURE_MANUAL_MONSTER (1103), + OPEN_ADVENTURE_MANUAL_BOSS_DUNGEON (1104), + OPEN_STATE_ACTIVITY_SEALAMP (1200), + OPEN_STATE_ACTIVITY_SEALAMP_TAB2 (1201), + OPEN_STATE_ACTIVITY_SEALAMP_TAB3 (1202), + OPEN_STATE_BATTLE_PASS (1300), + OPEN_STATE_BATTLE_PASS_ENTRY (1301), + OPEN_STATE_ACTIVITY_CRUCIBLE (1400), + OPEN_STATE_ACTIVITY_NEWBEEBOUNS_OPEN (1401), + OPEN_STATE_ACTIVITY_NEWBEEBOUNS_CLOSE (1402), + OPEN_STATE_ACTIVITY_ENTRY_OPEN (1403), + OPEN_STATE_MENGDE_INFUSEDCRYSTAL (1404), + OPEN_STATE_LIYUE_INFUSEDCRYSTAL (1405), + OPEN_STATE_SNOW_MOUNTAIN_ELDER_TREE (1406), + OPEN_STATE_MIRACLE_RING (1407), + OPEN_STATE_COOP_LINE (1408), + OPEN_STATE_INAZUMA_INFUSEDCRYSTAL (1409), + OPEN_STATE_FISH (1410), + OPEN_STATE_GUIDE_SUMO_TEAM_SKILL (1411), + OPEN_STATE_GUIDE_FISH_RECIPE (1412), + OPEN_STATE_HOME (1500), + OPEN_STATE_ACTIVITY_HOMEWORLD (1501), + OPEN_STATE_ADEPTIABODE (1502), + OPEN_STATE_HOME_AVATAR (1503), + OPEN_STATE_HOME_EDIT (1504), + OPEN_STATE_HOME_EDIT_TIPS (1505), + OPEN_STATE_RELIQUARY_DECOMPOSE (1600), + OPEN_STATE_ACTIVITY_H5 (1700), + OPEN_STATE_ORAIONOKAMI (2000), + OPEN_STATE_GUIDE_CHESS_MISSION_CHECK (2001), + OPEN_STATE_GUIDE_CHESS_BUILD (2002), + OPEN_STATE_GUIDE_CHESS_WIND_TOWER_CIRCLE (2003), + OPEN_STATE_GUIDE_CHESS_CARD_SELECT (2004), + OPEN_STATE_INAZUMA_MAINQUEST_FINISHED (2005), + OPEN_STATE_PAIMON_LVINFO (2100), + OPEN_STATE_TELEPORT_HUD (2101), + OPEN_STATE_GUIDE_MAP_UNLOCK (2102), + OPEN_STATE_GUIDE_PAIMON_LVINFO (2103), + OPEN_STATE_GUIDE_AMBORTRANSPORT (2104), + OPEN_STATE_GUIDE_FLY_SECOND (2105), + OPEN_STATE_GUIDE_KAEYA_CLUE (2106), + OPEN_STATE_CAPTURE_CODEX (2107), + OPEN_STATE_ACTIVITY_FISH_OPEN (2200), + OPEN_STATE_ACTIVITY_FISH_CLOSE (2201), + OPEN_STATE_GUIDE_ROGUE_MAP (2205), + OPEN_STATE_GUIDE_ROGUE_RUNE (2206), + OPEN_STATE_GUIDE_BARTENDER_FORMULA (2210), + OPEN_STATE_GUIDE_BARTENDER_MIX (2211), + OPEN_STATE_GUIDE_BARTENDER_CUP (2212), + OPEN_STATE_GUIDE_MAIL_FAVORITES (2400), + OPEN_STATE_GUIDE_POTION_CONFIGURE (2401), + OPEN_STATE_GUIDE_LANV2_FIREWORK (2402), + OPEN_STATE_LOADINGTIPS_ENKANOMIYA (2403), + OPEN_STATE_MICHIAE_CASKET (2500), + OPEN_STATE_MAIL_COLLECT_UNLOCK_RED_POINT (2501), + OPEN_STATE_LUMEN_STONE (2600), + OPEN_STATE_GUIDE_CRYSTALLINK_BUFF (2601), + OPEN_STATE_GUIDE_MUSIC_GAME_V3 (2700), + OPEN_STATE_GUIDE_MUSIC_GAME_V3_REAL_TIME_EDIT (2701), + OPEN_STATE_GUIDE_MUSIC_GAME_V3_TIMELINE_EDIT (2702), + OPEN_STATE_GUIDE_MUSIC_GAME_V3_SETTING (2703), + OPEN_STATE_GUIDE_ROBOTGACHA (2704), + OPEN_STATE_GUIDE_FRAGILE_RESIN (2800), + OPEN_ADVENTURE_MANUAL_EDUCATION (2801); private final int value; private static final Int2ObjectMap map = new Int2ObjectOpenHashMap<>(); diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerLoginReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerLoginReq.java index 4578e7d1f..45810b16c 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerLoginReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerLoginReq.java @@ -40,8 +40,6 @@ public class HandlerPlayerLoginReq extends PacketHandler { // Show opening cutscene if player has no avatars if (player.getAvatars().getAvatarCount() == 0) { - // Set New Player OpenStates - player.getOpenStateManager().onNewPlayerCreate(); // Pick character session.setState(SessionState.PICKING_CHARACTER); session.send(new BasePacket(PacketOpcodes.DoSetPlayerBornDataNotify)); diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketOpenStateUpdateNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketOpenStateUpdateNotify.java index 62ec01ea7..dc18ba836 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketOpenStateUpdateNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketOpenStateUpdateNotify.java @@ -1,25 +1,31 @@ package emu.grasscutter.server.packet.send; -import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.PlayerOpenStateManager; import emu.grasscutter.game.props.OpenState; import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.proto.OpenStateUpdateNotifyOuterClass.OpenStateUpdateNotify; -import java.util.Map; /* Must be sent on login for openStates to work Tells the client to update its openStateMap for the keys sent. value is irrelevant */ public class PacketOpenStateUpdateNotify extends BasePacket { - public PacketOpenStateUpdateNotify(Player player) { + public PacketOpenStateUpdateNotify(PlayerOpenStateManager manager) { super(PacketOpcodes.OpenStateUpdateNotify); OpenStateUpdateNotify.Builder proto = OpenStateUpdateNotify.newBuilder(); - proto.putAllOpenStateMap(player.getOpenStateManager().getOpenStateMap()).build(); + for (OpenState state : OpenState.values()) { + // If the player has an open state stored in their map, then it would always override any default value + if (manager.getOpenStateMap().containsKey(state.getValue())) { + proto.putOpenStateMap(state.getValue(), manager.getOpenState(state)); + } else if (PlayerOpenStateManager.DEV_OPEN_STATES.contains(state)) { + // Add default value here. TODO properly put default values somewhere + proto.putOpenStateMap(state.getValue(), 1); + } + } this.setData(proto); } From 7f898417b01261eeb40653b16d53cff7ba85be49 Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Mon, 18 Jul 2022 02:33:13 -0700 Subject: [PATCH 18/61] Fix a few null pointer issues. --- .../grasscutter/data/excels/ReliquaryLevelData.java | 10 ++++++---- .../server/packet/recv/HandlerQueryPathReq.java | 8 ++++++-- src/main/java/emu/grasscutter/tools/Tools.java | 4 +++- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/src/main/java/emu/grasscutter/data/excels/ReliquaryLevelData.java b/src/main/java/emu/grasscutter/data/excels/ReliquaryLevelData.java index 488cca1e6..f9580ef7d 100644 --- a/src/main/java/emu/grasscutter/data/excels/ReliquaryLevelData.java +++ b/src/main/java/emu/grasscutter/data/excels/ReliquaryLevelData.java @@ -5,13 +5,15 @@ import java.util.List; import emu.grasscutter.data.GameResource; import emu.grasscutter.data.ResourceType; import emu.grasscutter.game.props.FightProperty; +import it.unimi.dsi.fastutil.ints.Int2FloatMap; +import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; @ResourceType(name = "ReliquaryLevelExcelConfigData.json") public class ReliquaryLevelData extends GameResource { private int id; - private Int2ObjectMap propMap; + private Int2FloatMap propMap; private int rank; private int level; @@ -40,15 +42,15 @@ public class ReliquaryLevelData extends GameResource { } public float getPropValue(int id) { - return propMap.get(id); + return propMap.getOrDefault(id, 0f); } @Override public void onLoad() { this.id = (rank << 8) + this.getLevel(); - this.propMap = new Int2ObjectOpenHashMap<>(); + this.propMap = new Int2FloatOpenHashMap(); for (RelicLevelProperty p : addProps) { - this.propMap.put(FightProperty.getPropByName(p.getPropType()).getId(), (Float) p.getValue()); + this.propMap.put(FightProperty.getPropByName(p.getPropType()).getId(), p.getValue()); } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerQueryPathReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerQueryPathReq.java index 1184d5b17..62aad5da8 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerQueryPathReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerQueryPathReq.java @@ -4,6 +4,7 @@ import emu.grasscutter.net.packet.Opcodes; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.packet.PacketHandler; import emu.grasscutter.net.proto.QueryPathReqOuterClass; +import emu.grasscutter.net.proto.QueryPathReqOuterClass.QueryPathReq; import emu.grasscutter.server.game.GameSession; import emu.grasscutter.server.packet.send.PacketQueryPathRsp; @@ -12,12 +13,15 @@ public class HandlerQueryPathReq extends PacketHandler { @Override public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - var req = QueryPathReqOuterClass.QueryPathReq.parseFrom(payload); + var req = QueryPathReq.parseFrom(payload); /** * It is not the actual work */ - session.send(new PacketQueryPathRsp(req)); + + if (req.getDestinationPosList().size() > 0) { + session.send(new PacketQueryPathRsp(req)); + } } } diff --git a/src/main/java/emu/grasscutter/tools/Tools.java b/src/main/java/emu/grasscutter/tools/Tools.java index 1a1ac2196..f6d425ee2 100644 --- a/src/main/java/emu/grasscutter/tools/Tools.java +++ b/src/main/java/emu/grasscutter/tools/Tools.java @@ -159,7 +159,9 @@ final class ToolsWithLanguageOption { for (Integer id : list) { QuestData data = GameData.getQuestDataMap().get(id); MainQuestData mainQuest = GameData.getMainQuestDataMap().get(data.getMainId()); - writer.println(data.getId() + " : " + map.get(mainQuest.getTitleTextMapHash()) + " - " + map.get(data.getDescTextMapHash())); + if (mainQuest != null) { + writer.println(data.getId() + " : " + map.get(mainQuest.getTitleTextMapHash()) + " - " + map.get(data.getDescTextMapHash())); + } } writer.println(); From 6c49fab137e3ea37e5c7c5eec02df578d95a6df9 Mon Sep 17 00:00:00 2001 From: zhaodice <63996691+zhaodice@users.noreply.github.com> Date: Mon, 18 Jul 2022 18:13:55 +0800 Subject: [PATCH 19/61] Block loader (sort and merge gadgets into different blocks) (#1517) Original commits: * block loader * fix * fix * fix foolish bug * add scales * rename * set to 600 * nitpick Co-authored-by: AnimeGitB --- build.gradle | 2 +- .../java/emu/grasscutter/data/GameDepot.java | 40 +++++------ .../emu/grasscutter/data/ResourceLoader.java | 52 +++++++------- .../emu/grasscutter/game/world/Scene.java | 46 ++++++------ .../game/world/SpawnDataEntry.java | 71 +++++++++++++++++-- 5 files changed, 134 insertions(+), 77 deletions(-) diff --git a/build.gradle b/build.gradle index 6ff91114b..524778302 100644 --- a/build.gradle +++ b/build.gradle @@ -82,7 +82,7 @@ dependencies { implementation group: 'dev.morphia.morphia', name: 'morphia-core', version: '2.2.7' implementation group: 'org.greenrobot', name: 'eventbus-java', version: '3.3.1' - implementation group: 'org.danilopianini', name: 'java-quadtree', version: '0.1.9' + //implementation group: 'org.danilopianini', name: 'java-quadtree', version: '0.1.9' implementation group: 'org.quartz-scheduler', name: 'quartz', version: '2.3.2' implementation group: 'org.quartz-scheduler', name: 'quartz-jobs', version: '2.3.2' diff --git a/src/main/java/emu/grasscutter/data/GameDepot.java b/src/main/java/emu/grasscutter/data/GameDepot.java index 0b44ac44a..76b9b7c6f 100644 --- a/src/main/java/emu/grasscutter/data/GameDepot.java +++ b/src/main/java/emu/grasscutter/data/GameDepot.java @@ -5,29 +5,27 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import org.danilopianini.util.FlexibleQuadTree; -import org.danilopianini.util.SpatialIndex; import emu.grasscutter.Grasscutter; import emu.grasscutter.data.ResourceLoader.AvatarConfig; -import emu.grasscutter.data.ResourceLoader.AvatarConfigAbility; import emu.grasscutter.data.excels.ReliquaryAffixData; import emu.grasscutter.data.excels.ReliquaryMainPropData; import emu.grasscutter.game.world.SpawnDataEntry; -import emu.grasscutter.game.world.SpawnDataEntry.SpawnGroupEntry; import emu.grasscutter.utils.WeightedList; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; public class GameDepot { + public static final int[] BLOCK_SIZE = new int[]{50,500};//Scales + private static Int2ObjectMap> relicRandomMainPropDepot = new Int2ObjectOpenHashMap<>(); private static Int2ObjectMap> relicMainPropDepot = new Int2ObjectOpenHashMap<>(); private static Int2ObjectMap> relicAffixDepot = new Int2ObjectOpenHashMap<>(); - + private static Map playerAbilities = new HashMap<>(); - private static Int2ObjectMap> spawnLists = new Int2ObjectOpenHashMap<>(); - - public static void load() { + private static HashMap> spawnLists = new HashMap<>(); + + public static void load() { for (ReliquaryMainPropData data : GameData.getReliquaryMainPropDataMap().values()) { if (data.getWeight() <= 0 || data.getPropDepotId() <= 0) { continue; @@ -49,7 +47,7 @@ public class GameDepot { Grasscutter.getLogger().error("Relic properties are missing weights! Please check your ReliquaryMainPropExcelConfigData or ReliquaryAffixExcelConfigData files in your ExcelBinOutput folder."); } } - + public static ReliquaryMainPropData getRandomRelicMainProp(int depot) { WeightedList depotList = relicRandomMainPropDepot.get(depot); if (depotList == null) { @@ -57,7 +55,7 @@ public class GameDepot { } return depotList.next(); } - + public static List getRelicMainPropList(int depot) { return relicMainPropDepot.get(depot); } @@ -65,20 +63,20 @@ public class GameDepot { public static List getRelicAffixList(int depot) { return relicAffixDepot.get(depot); } - - public static Int2ObjectMap> getSpawnLists() { - return spawnLists; - } - - public static SpatialIndex getSpawnListById(int sceneId) { - return getSpawnLists().computeIfAbsent(sceneId, id -> new FlexibleQuadTree<>()); - } - public static Map getPlayerAbilities() { - return playerAbilities; - } + public static HashMap> getSpawnLists() { + return spawnLists; + } + + public static void addSpawnListById(HashMap> data) { + spawnLists.putAll(data); + } public static void setPlayerAbilities(Map playerAbilities) { GameDepot.playerAbilities = playerAbilities; } + + public static Map getPlayerAbilities() { + return playerAbilities; + } } diff --git a/src/main/java/emu/grasscutter/data/ResourceLoader.java b/src/main/java/emu/grasscutter/data/ResourceLoader.java index 29e05addd..5d93b7245 100644 --- a/src/main/java/emu/grasscutter/data/ResourceLoader.java +++ b/src/main/java/emu/grasscutter/data/ResourceLoader.java @@ -9,8 +9,8 @@ import java.util.Map.Entry; import java.util.regex.Matcher; import java.util.regex.Pattern; -import com.google.gson.Gson; import emu.grasscutter.data.binout.*; +import emu.grasscutter.game.world.SpawnDataEntry; import emu.grasscutter.scripts.SceneIndexManager; import emu.grasscutter.utils.Utils; import lombok.SneakyThrows; @@ -28,7 +28,6 @@ import emu.grasscutter.data.common.PointData; import emu.grasscutter.data.common.ScenePointConfig; import emu.grasscutter.game.world.SpawnDataEntry.*; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import static emu.grasscutter.Configuration.*; import static emu.grasscutter.utils.Language.translate; @@ -309,34 +308,39 @@ public class ResourceLoader { private static void loadSpawnData() { String[] spawnDataNames = {"Spawns.json", "GadgetSpawns.json"}; - Int2ObjectMap spawnEntryMap = new Int2ObjectOpenHashMap<>(); + ArrayList spawnEntryMap = new ArrayList<>(); + + for (String name : spawnDataNames) { + // Load spawn entries from file + try (InputStream spawnDataEntries = DataLoader.load(name)) { + Type type = TypeToken.getParameterized(Collection.class, SpawnGroupEntry.class).getType(); + List list = Grasscutter.getGsonFactory().fromJson(new InputStreamReader(spawnDataEntries), type); + + // Add spawns to group if it already exists in our spawn group map + spawnEntryMap.addAll(list); + } catch (Exception ignored) {} + } - for (String name : spawnDataNames) { - // Load spawn entries from file - try (InputStream spawnDataEntries = DataLoader.load(name)) { - Type type = TypeToken.getParameterized(Collection.class, SpawnGroupEntry.class).getType(); - List list = Grasscutter.getGsonFactory().fromJson(new InputStreamReader(spawnDataEntries), type); - - // Add spawns to group if it already exists in our spawn group map - for (SpawnGroupEntry group : list) { - if (spawnEntryMap.containsKey(group.getGroupId())) { - spawnEntryMap.get(group.getGroupId()).getSpawns().addAll(group.getSpawns()); - } else { - spawnEntryMap.put(group.getGroupId(), group); - } - } - } catch (Exception ignored) {} - } - if (spawnEntryMap.isEmpty()) { Grasscutter.getLogger().error("No spawn data loaded!"); return; } - for (SpawnGroupEntry entry : spawnEntryMap.values()) { - entry.getSpawns().forEach(s -> s.setGroup(entry)); - GameDepot.getSpawnListById(entry.getSceneId()).insert(entry, entry.getPos().getX(), entry.getPos().getZ()); - } + HashMap> areaSort = new HashMap<>(); + //key = sceneId,x,z , value = ArrayList + for (SpawnGroupEntry entry : spawnEntryMap) { + entry.getSpawns().forEach( + s -> { + s.setGroup(entry); + GridBlockId point = s.getBlockId(); + if(!areaSort.containsKey(point)) { + areaSort.put(point, new ArrayList<>()); + } + areaSort.get(point).add(s); + } + ); + } + GameDepot.addSpawnListById(areaSort); } private static void loadOpenConfig() { diff --git a/src/main/java/emu/grasscutter/game/world/Scene.java b/src/main/java/emu/grasscutter/game/world/Scene.java index 82f534e5e..d3af36c9f 100644 --- a/src/main/java/emu/grasscutter/game/world/Scene.java +++ b/src/main/java/emu/grasscutter/game/world/Scene.java @@ -9,12 +9,10 @@ import emu.grasscutter.game.dungeons.DungeonSettleListener; import emu.grasscutter.game.entity.*; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.TeamInfo; -import emu.grasscutter.game.props.ClimateType; import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.props.LifeState; import emu.grasscutter.game.props.SceneType; import emu.grasscutter.game.quest.QuestGroupSuite; -import emu.grasscutter.game.world.SpawnDataEntry.SpawnGroupEntry; import emu.grasscutter.game.dungeons.challenge.WorldChallenge; import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult; @@ -26,15 +24,10 @@ import emu.grasscutter.scripts.data.SceneGadget; import emu.grasscutter.scripts.data.SceneGroup; import emu.grasscutter.server.packet.send.*; import emu.grasscutter.utils.Position; -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import org.danilopianini.util.SpatialIndex; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; -import java.util.stream.Collectors; public class Scene { private final World world; @@ -44,6 +37,7 @@ public class Scene { private final Set spawnedEntities; private final Set deadSpawnedEntities; private final Set loadedBlocks; + private Set loadedGridBlocks; private boolean dontDestroyWhenEmpty; private int autoCloseTime; @@ -68,6 +62,7 @@ public class Scene { this.spawnedEntities = ConcurrentHashMap.newKeySet(); this.deadSpawnedEntities = ConcurrentHashMap.newKeySet(); this.loadedBlocks = ConcurrentHashMap.newKeySet(); + this.loadedGridBlocks = new HashSet<>(); this.npcBornEntrySet = ConcurrentHashMap.newKeySet(); this.scriptManager = new SceneScriptManager(this); } @@ -461,25 +456,24 @@ public class Scene { this.npcBornEntrySet = npcBornEntries; } - // TODO - Test - public synchronized void checkSpawns() { - int RANGE = 100; - - SpatialIndex list = GameDepot.getSpawnListById(this.getId()); - Set visible = new HashSet<>(); - - for (Player player : this.getPlayers()) { - Position position = player.getPos(); - Collection entries = list.query( - new double[] {position.getX() - RANGE, position.getZ() - RANGE}, - new double[] {position.getX() + RANGE, position.getZ() + RANGE} - ); - for (SpawnGroupEntry entry : entries) { - for (SpawnDataEntry spawnData : entry.getSpawns()) { - visible.add(spawnData); - } - } - } + public synchronized void checkSpawns() { + Set loadedGridBlocks = new HashSet<>(); + for (Player player : this.getPlayers()) { + for (SpawnDataEntry.GridBlockId block : SpawnDataEntry.GridBlockId.getAdjacentGridBlockIds(player.getSceneId(), player.getPos())) + loadedGridBlocks.add(block); + } + if (this.loadedGridBlocks.containsAll(loadedGridBlocks)) { // Don't recalculate static spawns if nothing has changed + return; + } + this.loadedGridBlocks = loadedGridBlocks; + var spawnLists = GameDepot.getSpawnLists(); + Set visible = new HashSet<>(); + for (var block : loadedGridBlocks) { + var spawns = spawnLists.get(block); + if(spawns!=null) { + visible.addAll(spawns); + } + } // World level WorldLevelData worldLevelData = GameData.getWorldLevelDataMap().get(getWorld().getWorldLevel()); diff --git a/src/main/java/emu/grasscutter/game/world/SpawnDataEntry.java b/src/main/java/emu/grasscutter/game/world/SpawnDataEntry.java index 3789f71c0..456197c7c 100644 --- a/src/main/java/emu/grasscutter/game/world/SpawnDataEntry.java +++ b/src/main/java/emu/grasscutter/game/world/SpawnDataEntry.java @@ -1,7 +1,9 @@ package emu.grasscutter.game.world; import java.util.List; +import java.util.Objects; +import emu.grasscutter.data.GameDepot; import emu.grasscutter.utils.Position; public class SpawnDataEntry { @@ -60,11 +62,18 @@ public class SpawnDataEntry { return rot; } + public GridBlockId getBlockId(){ + int scale = GridBlockId.getScale(gadgetId); + return new GridBlockId(group.sceneId,scale, + (int)(pos.getX() / GameDepot.BLOCK_SIZE[scale]), + (int)(pos.getZ() / GameDepot.BLOCK_SIZE[scale]) + ); + } + public static class SpawnGroupEntry { private int sceneId; private int groupId; private int blockId; - private Position pos; private List spawns; public int getSceneId() { @@ -83,12 +92,64 @@ public class SpawnDataEntry { this.blockId = blockId; } - public Position getPos() { - return pos; - } - public List getSpawns() { return spawns; } } + + public static class GridBlockId { + int sceneId; + int scale; + int x; + int z; + + public GridBlockId(int sceneId, int scale, int x, int z) { + this.sceneId = sceneId; + this.scale = scale; + this.x = x; + this.z = z; + } + + @Override + public String toString() { + return "SpawnDataEntryScaledPoint{" + + "sceneId=" + sceneId + + ", scale=" + scale + + ", x=" + x + + ", z=" + z + + '}'; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + GridBlockId that = (GridBlockId) o; + return sceneId == that.sceneId && scale == that.scale && x == that.x && z == that.z; + } + + @Override + public int hashCode() { + return Objects.hash(sceneId, scale, x, z); + } + + public static GridBlockId[] getAdjacentGridBlockIds(int sceneId, Position pos){ + GridBlockId[] results = new GridBlockId[5*5*GameDepot.BLOCK_SIZE.length]; + int t=0; + for (int scale = 0; scale < GameDepot.BLOCK_SIZE.length; scale++) { + int x = ((int)(pos.getX()/GameDepot.BLOCK_SIZE[scale])); + int z = ((int)(pos.getZ()/GameDepot.BLOCK_SIZE[scale])); + for (int i=x-2; i Date: Mon, 18 Jul 2022 20:19:31 -0700 Subject: [PATCH 20/61] Set certain OpenStates on level-up. --- .../emu/grasscutter/game/player/Player.java | 14 +- .../game/player/PlayerOpenStateManager.java | 176 +----------------- .../emu/grasscutter/game/props/OpenState.java | 60 +++--- 3 files changed, 54 insertions(+), 196 deletions(-) diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index 3238de22e..8f1d2ceb6 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -453,9 +453,18 @@ public class Player { } public boolean setLevel(int level) { + if (this.getLevel() == level) { + return true; + } + if (this.setProperty(PlayerProperty.PROP_PLAYER_LEVEL, level)) { + // Update world level and profile. this.updateWorldLevel(); this.updateProfile(); + + // Handle OpenState unlocks from level-up. + this.getOpenStateManager().onPlayerLevelUp(); + return true; } return false; @@ -538,7 +547,6 @@ public class Player { // Directly give player exp public void addExpDirectly(int gain) { - boolean hasLeveledUp = false; int level = getLevel(); int exp = getExp(); int reqExp = getExpRequired(level); @@ -549,10 +557,8 @@ public class Player { exp -= reqExp; level += 1; reqExp = getExpRequired(level); - hasLeveledUp = true; - } - if (hasLeveledUp) { + // Set level each time to allow level-up specific logic to run. this.setLevel(level); } diff --git a/src/main/java/emu/grasscutter/game/player/PlayerOpenStateManager.java b/src/main/java/emu/grasscutter/game/player/PlayerOpenStateManager.java index 562c81ec9..ae569106c 100644 --- a/src/main/java/emu/grasscutter/game/player/PlayerOpenStateManager.java +++ b/src/main/java/emu/grasscutter/game/player/PlayerOpenStateManager.java @@ -32,173 +32,9 @@ public class PlayerOpenStateManager { // For development. Remove entry when properly implemented // TODO - Set as boolean in OpenState - public static final Set DEV_OPEN_STATES = Set.of( - OPEN_STATE_PAIMON, - OPEN_STATE_PAIMON_NAVIGATION, - OPEN_STATE_AVATAR_PROMOTE, - OPEN_STATE_AVATAR_TALENT, - OPEN_STATE_WEAPON_PROMOTE, - OPEN_STATE_WEAPON_AWAKEN, - OPEN_STATE_QUEST_REMIND, - OPEN_STATE_GAME_GUIDE, - OPEN_STATE_COOK, - OPEN_STATE_WEAPON_UPGRADE, - OPEN_STATE_RELIQUARY_UPGRADE, - OPEN_STATE_RELIQUARY_PROMOTE, - OPEN_STATE_WEAPON_PROMOTE_GUIDE, - OPEN_STATE_WEAPON_CHANGE_GUIDE, - OPEN_STATE_PLAYER_LVUP_GUIDE, - OPEN_STATE_FRESHMAN_GUIDE, - OPEN_STATE_SKIP_FRESHMAN_GUIDE, - OPEN_STATE_GUIDE_MOVE_CAMERA, - OPEN_STATE_GUIDE_SCALE_CAMERA, - OPEN_STATE_GUIDE_KEYBOARD, - OPEN_STATE_GUIDE_MOVE, - OPEN_STATE_GUIDE_JUMP, - OPEN_STATE_GUIDE_SPRINT, - OPEN_STATE_GUIDE_MAP, - OPEN_STATE_GUIDE_ATTACK, - OPEN_STATE_GUIDE_FLY, - OPEN_STATE_GUIDE_TALENT, - OPEN_STATE_GUIDE_RELIC, - OPEN_STATE_GUIDE_RELIC_PROM, - OPEN_STATE_COMBINE, - OPEN_STATE_GACHA, - OPEN_STATE_GUIDE_GACHA, - OPEN_STATE_GUIDE_TEAM, - OPEN_STATE_GUIDE_PROUD, - OPEN_STATE_GUIDE_AVATAR_PROMOTE, - OPEN_STATE_GUIDE_ADVENTURE_CARD, - OPEN_STATE_FORGE, - OPEN_STATE_GUIDE_BAG, - OPEN_STATE_EXPEDITION, - OPEN_STATE_GUIDE_ADVENTURE_DAILYTASK, - OPEN_STATE_GUIDE_ADVENTURE_DUNGEON, - OPEN_STATE_TOWER, - OPEN_STATE_WORLD_STAMINA, - OPEN_STATE_TOWER_FIRST_ENTER, - OPEN_STATE_RESIN, - OPEN_STATE_LIMIT_REGION_FRESHMEAT, - OPEN_STATE_MULTIPLAYER, - OPEN_STATE_GUIDE_MOUSEPC, - OPEN_STATE_GUIDE_MULTIPLAYER, - OPEN_STATE_GUIDE_DUNGEONREWARD, - OPEN_STATE_GUIDE_BLOSSOM, - OPEN_STATE_AVATAR_FASHION, - OPEN_STATE_PHOTOGRAPH, - OPEN_STATE_GUIDE_KSLQUEST, - OPEN_STATE_PERSONAL_LINE, - OPEN_STATE_GUIDE_PERSONAL_LINE, - OPEN_STATE_GUIDE_APPEARANCE, - OPEN_STATE_GUIDE_PROCESS, - OPEN_STATE_GUIDE_PERSONAL_LINE_KEY, - OPEN_STATE_GUIDE_WIDGET, - OPEN_STATE_GUIDE_ACTIVITY_SKILL_ASTER, - OPEN_STATE_GUIDE_COLDCLIMATE, - OPEN_STATE_DERIVATIVE_MALL, - OPEN_STATE_GUIDE_EXITMULTIPLAYER, - OPEN_STATE_GUIDE_THEATREMACHANICUS_BUILD, - OPEN_STATE_GUIDE_THEATREMACHANICUS_REBUILD, - OPEN_STATE_GUIDE_THEATREMACHANICUS_CARD, - OPEN_STATE_GUIDE_THEATREMACHANICUS_MONSTER, - OPEN_STATE_GUIDE_THEATREMACHANICUS_MISSION_CHECK, - OPEN_STATE_GUIDE_THEATREMACHANICUS_BUILD_SELECT, - OPEN_STATE_GUIDE_THEATREMACHANICUS_CHALLENGE_START, - OPEN_STATE_GUIDE_CONVERT, - OPEN_STATE_GUIDE_THEATREMACHANICUS_MULTIPLAYER, - OPEN_STATE_GUIDE_COOP_TASK, - OPEN_STATE_GUIDE_HOMEWORLD_ADEPTIABODE, - OPEN_STATE_GUIDE_HOMEWORLD_DEPLOY, - OPEN_STATE_GUIDE_CHANNELLERSLAB_EQUIP, - OPEN_STATE_GUIDE_CHANNELLERSLAB_MP_SOLUTION, - OPEN_STATE_GUIDE_CHANNELLERSLAB_POWER, - OPEN_STATE_GUIDE_HIDEANDSEEK_SKILL, - OPEN_STATE_GUIDE_HOMEWORLD_MAPLIST, - OPEN_STATE_GUIDE_RELICRESOLVE, - OPEN_STATE_GUIDE_GGUIDE, - OPEN_STATE_GUIDE_GGUIDE_HINT, - OPEN_STATE_GUIDE_QUICK_TEAMMEMBERCHANGE, - OPEN_STATE_CITY_REPUATION_MENGDE, - OPEN_STATE_CITY_REPUATION_LIYUE, - OPEN_STATE_CITY_REPUATION_UI_HINT, - OPEN_STATE_CITY_REPUATION_INAZUMA, - OPEN_STATE_SHOP_TYPE_MALL, - OPEN_STATE_SHOP_TYPE_RECOMMANDED, - OPEN_STATE_SHOP_TYPE_GENESISCRYSTAL, - OPEN_STATE_SHOP_TYPE_GIFTPACKAGE, - OPEN_STATE_SHOP_TYPE_PAIMON, - OPEN_STATE_SHOP_TYPE_CITY, - OPEN_STATE_SHOP_TYPE_BLACKSMITH, - OPEN_STATE_SHOP_TYPE_GROCERY, - OPEN_STATE_SHOP_TYPE_FOOD, - OPEN_STATE_SHOP_TYPE_SEA_LAMP, - OPEN_STATE_SHOP_TYPE_VIRTUAL_SHOP, - OPEN_STATE_SHOP_TYPE_LIYUE_GROCERY, - OPEN_STATE_SHOP_TYPE_LIYUE_SOUVENIR, - OPEN_STATE_SHOP_TYPE_LIYUE_RESTAURANT, - OPEN_STATE_SHOP_TYPE_INAZUMA_SOUVENIR, - OPEN_STATE_SHOP_TYPE_NPC_TOMOKI, - OPEN_ADVENTURE_MANUAL, - OPEN_ADVENTURE_MANUAL_CITY_MENGDE, - OPEN_ADVENTURE_MANUAL_CITY_LIYUE, - OPEN_ADVENTURE_MANUAL_MONSTER, - OPEN_ADVENTURE_MANUAL_BOSS_DUNGEON, - OPEN_STATE_ACTIVITY_SEALAMP, - OPEN_STATE_ACTIVITY_SEALAMP_TAB2, - OPEN_STATE_ACTIVITY_SEALAMP_TAB3, - OPEN_STATE_BATTLE_PASS, - OPEN_STATE_BATTLE_PASS_ENTRY, - OPEN_STATE_ACTIVITY_CRUCIBLE, - OPEN_STATE_ACTIVITY_NEWBEEBOUNS_OPEN, - OPEN_STATE_ACTIVITY_NEWBEEBOUNS_CLOSE, - OPEN_STATE_ACTIVITY_ENTRY_OPEN, - OPEN_STATE_MENGDE_INFUSEDCRYSTAL, - OPEN_STATE_LIYUE_INFUSEDCRYSTAL, - OPEN_STATE_SNOW_MOUNTAIN_ELDER_TREE, - OPEN_STATE_MIRACLE_RING, - OPEN_STATE_COOP_LINE, - OPEN_STATE_INAZUMA_INFUSEDCRYSTAL, - OPEN_STATE_FISH, - OPEN_STATE_GUIDE_SUMO_TEAM_SKILL, - OPEN_STATE_GUIDE_FISH_RECIPE, - OPEN_STATE_HOME, - OPEN_STATE_ACTIVITY_HOMEWORLD, - OPEN_STATE_ADEPTIABODE, - OPEN_STATE_HOME_AVATAR, - OPEN_STATE_HOME_EDIT, - OPEN_STATE_HOME_EDIT_TIPS, - OPEN_STATE_RELIQUARY_DECOMPOSE, - OPEN_STATE_ACTIVITY_H5, - OPEN_STATE_ORAIONOKAMI, - OPEN_STATE_GUIDE_CHESS_MISSION_CHECK, - OPEN_STATE_GUIDE_CHESS_BUILD, - OPEN_STATE_GUIDE_CHESS_WIND_TOWER_CIRCLE, - OPEN_STATE_GUIDE_CHESS_CARD_SELECT, - OPEN_STATE_INAZUMA_MAINQUEST_FINISHED, - OPEN_STATE_PAIMON_LVINFO, - OPEN_STATE_TELEPORT_HUD, - OPEN_STATE_GUIDE_MAP_UNLOCK, - OPEN_STATE_GUIDE_PAIMON_LVINFO, - OPEN_STATE_GUIDE_AMBORTRANSPORT, - OPEN_STATE_GUIDE_FLY_SECOND, - OPEN_STATE_GUIDE_KAEYA_CLUE, - OPEN_STATE_CAPTURE_CODEX, - OPEN_STATE_ACTIVITY_FISH_OPEN, - OPEN_STATE_ACTIVITY_FISH_CLOSE, - OPEN_STATE_GUIDE_ROGUE_MAP, - OPEN_STATE_GUIDE_ROGUE_RUNE, - OPEN_STATE_GUIDE_BARTENDER_FORMULA, - OPEN_STATE_GUIDE_BARTENDER_MIX, - OPEN_STATE_GUIDE_BARTENDER_CUP, - OPEN_STATE_GUIDE_MAIL_FAVORITES, - OPEN_STATE_GUIDE_POTION_CONFIGURE, - OPEN_STATE_GUIDE_LANV2_FIREWORK, - OPEN_STATE_LOADINGTIPS_ENKANOMIYA, - OPEN_STATE_MICHIAE_CASKET, - OPEN_STATE_MAIL_COLLECT_UNLOCK_RED_POINT, - OPEN_STATE_LUMEN_STONE, - OPEN_STATE_GUIDE_CRYSTALLINK_BUFF - ); + public static final Set DEV_OPEN_STATES = Stream.of(OpenState.values()) + .filter(s -> s != OpenState.OPEN_STATE_NONE && s.getUnlockLevel() <= 1) + .collect(Collectors.toSet()); public PlayerOpenStateManager(Player player) { this.player = player; @@ -236,4 +72,10 @@ public class PlayerOpenStateManager { public void onPlayerLogin() { player.getSession().send(new PacketOpenStateUpdateNotify(this)); } + + public void onPlayerLevelUp() { + Stream.of(OpenState.values()) + .filter(s -> s.getUnlockLevel() == this.player.getLevel()) + .forEach(s -> this.setOpenState(s, 1)); + } } \ No newline at end of file diff --git a/src/main/java/emu/grasscutter/game/props/OpenState.java b/src/main/java/emu/grasscutter/game/props/OpenState.java index 560edf5f2..536c57d45 100644 --- a/src/main/java/emu/grasscutter/game/props/OpenState.java +++ b/src/main/java/emu/grasscutter/game/props/OpenState.java @@ -38,16 +38,16 @@ public enum OpenState { OPEN_STATE_GUIDE_TALENT (27), OPEN_STATE_GUIDE_RELIC (28), OPEN_STATE_GUIDE_RELIC_PROM (29), - OPEN_STATE_COMBINE (30), + OPEN_STATE_COMBINE (30, 2), OPEN_STATE_GACHA (31), OPEN_STATE_GUIDE_GACHA (32), OPEN_STATE_GUIDE_TEAM (33), OPEN_STATE_GUIDE_PROUD (34), OPEN_STATE_GUIDE_AVATAR_PROMOTE (35), OPEN_STATE_GUIDE_ADVENTURE_CARD (36), - OPEN_STATE_FORGE (37), + OPEN_STATE_FORGE (37, 2), OPEN_STATE_GUIDE_BAG (38), - OPEN_STATE_EXPEDITION (39), + OPEN_STATE_EXPEDITION (39, 14), OPEN_STATE_GUIDE_ADVENTURE_DAILYTASK (40), OPEN_STATE_GUIDE_ADVENTURE_DUNGEON (41), OPEN_STATE_TOWER (42), @@ -56,15 +56,15 @@ public enum OpenState { OPEN_STATE_RESIN (45), OPEN_STATE_LIMIT_REGION_FRESHMEAT (47), OPEN_STATE_LIMIT_REGION_GLOBAL (48), - OPEN_STATE_MULTIPLAYER (49), + OPEN_STATE_MULTIPLAYER (49, 16), OPEN_STATE_GUIDE_MOUSEPC (50), OPEN_STATE_GUIDE_MULTIPLAYER (51), OPEN_STATE_GUIDE_DUNGEONREWARD (52), - OPEN_STATE_GUIDE_BLOSSOM (53), + OPEN_STATE_GUIDE_BLOSSOM (53, 8), OPEN_STATE_AVATAR_FASHION (54), OPEN_STATE_PHOTOGRAPH (55), OPEN_STATE_GUIDE_KSLQUEST (56), - OPEN_STATE_PERSONAL_LINE (57), + OPEN_STATE_PERSONAL_LINE (57, 26), OPEN_STATE_GUIDE_PERSONAL_LINE (58), OPEN_STATE_GUIDE_APPEARANCE (59), OPEN_STATE_GUIDE_PROCESS (60), @@ -102,35 +102,35 @@ public enum OpenState { OPEN_STATE_GGUIDE_MAINPAGE_ENTRY_DISAPPEAR (92), OPEN_STATE_CITY_REPUATION_MENGDE (800), OPEN_STATE_CITY_REPUATION_LIYUE (801), - OPEN_STATE_CITY_REPUATION_UI_HINT (802), + OPEN_STATE_CITY_REPUATION_UI_HINT (802, 25), OPEN_STATE_CITY_REPUATION_INAZUMA (803), OPEN_STATE_SHOP_TYPE_MALL (900), - OPEN_STATE_SHOP_TYPE_RECOMMANDED (901), - OPEN_STATE_SHOP_TYPE_GENESISCRYSTAL (902), - OPEN_STATE_SHOP_TYPE_GIFTPACKAGE (903), + OPEN_STATE_SHOP_TYPE_RECOMMANDED (901, 1), + OPEN_STATE_SHOP_TYPE_GENESISCRYSTAL (902, 1), + OPEN_STATE_SHOP_TYPE_GIFTPACKAGE (903, 1), OPEN_STATE_SHOP_TYPE_PAIMON (1001), OPEN_STATE_SHOP_TYPE_CITY (1002), OPEN_STATE_SHOP_TYPE_BLACKSMITH (1003), - OPEN_STATE_SHOP_TYPE_GROCERY (1004), - OPEN_STATE_SHOP_TYPE_FOOD (1005), - OPEN_STATE_SHOP_TYPE_SEA_LAMP (1006), + OPEN_STATE_SHOP_TYPE_GROCERY (1004, 5), + OPEN_STATE_SHOP_TYPE_FOOD (1005, 5), + OPEN_STATE_SHOP_TYPE_SEA_LAMP (1006, 13), OPEN_STATE_SHOP_TYPE_VIRTUAL_SHOP (1007), - OPEN_STATE_SHOP_TYPE_LIYUE_GROCERY (1008), + OPEN_STATE_SHOP_TYPE_LIYUE_GROCERY (1008, 5), OPEN_STATE_SHOP_TYPE_LIYUE_SOUVENIR (1009), - OPEN_STATE_SHOP_TYPE_LIYUE_RESTAURANT (1010), + OPEN_STATE_SHOP_TYPE_LIYUE_RESTAURANT (1010, 5), OPEN_STATE_SHOP_TYPE_INAZUMA_SOUVENIR (1011), OPEN_STATE_SHOP_TYPE_NPC_TOMOKI (1012), OPEN_STATE_SHOP_TYPE_INAZUMA_SOUVENIR_BLACK_BAR (1013), OPEN_ADVENTURE_MANUAL (1100), OPEN_ADVENTURE_MANUAL_CITY_MENGDE (1101), OPEN_ADVENTURE_MANUAL_CITY_LIYUE (1102), - OPEN_ADVENTURE_MANUAL_MONSTER (1103), + OPEN_ADVENTURE_MANUAL_MONSTER (1103, 8), OPEN_ADVENTURE_MANUAL_BOSS_DUNGEON (1104), OPEN_STATE_ACTIVITY_SEALAMP (1200), OPEN_STATE_ACTIVITY_SEALAMP_TAB2 (1201), OPEN_STATE_ACTIVITY_SEALAMP_TAB3 (1202), - OPEN_STATE_BATTLE_PASS (1300), - OPEN_STATE_BATTLE_PASS_ENTRY (1301), + OPEN_STATE_BATTLE_PASS (1300, 1), + OPEN_STATE_BATTLE_PASS_ENTRY (1301, 20), OPEN_STATE_ACTIVITY_CRUCIBLE (1400), OPEN_STATE_ACTIVITY_NEWBEEBOUNS_OPEN (1401), OPEN_STATE_ACTIVITY_NEWBEEBOUNS_CLOSE (1402), @@ -139,27 +139,27 @@ public enum OpenState { OPEN_STATE_LIYUE_INFUSEDCRYSTAL (1405), OPEN_STATE_SNOW_MOUNTAIN_ELDER_TREE (1406), OPEN_STATE_MIRACLE_RING (1407), - OPEN_STATE_COOP_LINE (1408), + OPEN_STATE_COOP_LINE (1408, 26), OPEN_STATE_INAZUMA_INFUSEDCRYSTAL (1409), OPEN_STATE_FISH (1410), OPEN_STATE_GUIDE_SUMO_TEAM_SKILL (1411), OPEN_STATE_GUIDE_FISH_RECIPE (1412), OPEN_STATE_HOME (1500), - OPEN_STATE_ACTIVITY_HOMEWORLD (1501), + OPEN_STATE_ACTIVITY_HOMEWORLD (1501, 28), OPEN_STATE_ADEPTIABODE (1502), OPEN_STATE_HOME_AVATAR (1503), OPEN_STATE_HOME_EDIT (1504), OPEN_STATE_HOME_EDIT_TIPS (1505), - OPEN_STATE_RELIQUARY_DECOMPOSE (1600), - OPEN_STATE_ACTIVITY_H5 (1700), + OPEN_STATE_RELIQUARY_DECOMPOSE (1600, 45), + OPEN_STATE_ACTIVITY_H5 (1700, 10), OPEN_STATE_ORAIONOKAMI (2000), OPEN_STATE_GUIDE_CHESS_MISSION_CHECK (2001), OPEN_STATE_GUIDE_CHESS_BUILD (2002), OPEN_STATE_GUIDE_CHESS_WIND_TOWER_CIRCLE (2003), OPEN_STATE_GUIDE_CHESS_CARD_SELECT (2004), OPEN_STATE_INAZUMA_MAINQUEST_FINISHED (2005), - OPEN_STATE_PAIMON_LVINFO (2100), - OPEN_STATE_TELEPORT_HUD (2101), + OPEN_STATE_PAIMON_LVINFO (2100, 7), + OPEN_STATE_TELEPORT_HUD (2101, 2), OPEN_STATE_GUIDE_MAP_UNLOCK (2102), OPEN_STATE_GUIDE_PAIMON_LVINFO (2103), OPEN_STATE_GUIDE_AMBORTRANSPORT (2104), @@ -177,7 +177,7 @@ public enum OpenState { OPEN_STATE_GUIDE_POTION_CONFIGURE (2401), OPEN_STATE_GUIDE_LANV2_FIREWORK (2402), OPEN_STATE_LOADINGTIPS_ENKANOMIYA (2403), - OPEN_STATE_MICHIAE_CASKET (2500), + OPEN_STATE_MICHIAE_CASKET (2500, 30), OPEN_STATE_MAIL_COLLECT_UNLOCK_RED_POINT (2501), OPEN_STATE_LUMEN_STONE (2600), OPEN_STATE_GUIDE_CRYSTALLINK_BUFF (2601), @@ -190,6 +190,7 @@ public enum OpenState { OPEN_ADVENTURE_MANUAL_EDUCATION (2801); private final int value; + private final int unlockLevel; private static final Int2ObjectMap map = new Int2ObjectOpenHashMap<>(); private static final Map stringMap = new HashMap<>(); @@ -202,11 +203,20 @@ public enum OpenState { private OpenState(int value) { this.value = value; + this.unlockLevel = -1; + } + private OpenState(int value, int unlockLevel) { + this.value = value; + this.unlockLevel = unlockLevel; } public int getValue() { return value; } + + public int getUnlockLevel() { + return this.unlockLevel; + } public static OpenState getTypeByValue(int value) { return map.getOrDefault(value, OPEN_STATE_NONE); From b266854c72276735cadf702af9ec71bddfda2d27 Mon Sep 17 00:00:00 2001 From: GanyusLeftHorn <1244229+GanyusLeftHorn@users.noreply.github.com> Date: Mon, 18 Jul 2022 20:58:35 -0700 Subject: [PATCH 21/61] Handle existing players who might already have passed a level. --- src/main/java/emu/grasscutter/game/player/Player.java | 6 +++++- .../grasscutter/game/player/PlayerOpenStateManager.java | 8 +++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index 8f1d2ceb6..d4be0f3a6 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -463,7 +463,7 @@ public class Player { this.updateProfile(); // Handle OpenState unlocks from level-up. - this.getOpenStateManager().onPlayerLevelUp(); + this.getOpenStateManager().unlockLevelDependentStates(); return true; } @@ -1535,7 +1535,11 @@ public class Player { this.forgingManager.sendForgeDataNotify(); this.resinManager.onPlayerLogin(); this.cookingManager.sendCookDataNofity(); + + // Unlock in case this is an existing user that reached a level before we implemented unlocking. + this.openStateManager.unlockLevelDependentStates(); this.openStateManager.onPlayerLogin(); + getTodayMoonCard(); // The timer works at 0:0, some users log in after that, use this method to check if they have received a reward today or not. If not, send the reward. // Battle Pass trigger diff --git a/src/main/java/emu/grasscutter/game/player/PlayerOpenStateManager.java b/src/main/java/emu/grasscutter/game/player/PlayerOpenStateManager.java index ae569106c..7d18f059c 100644 --- a/src/main/java/emu/grasscutter/game/player/PlayerOpenStateManager.java +++ b/src/main/java/emu/grasscutter/game/player/PlayerOpenStateManager.java @@ -55,11 +55,9 @@ public class PlayerOpenStateManager { public void setOpenState(OpenState openState, Integer value) { Integer previousValue = this.map.getOrDefault(openState.getValue(),0); - if(!(value == previousValue)) { + if(value != previousValue) { this.map.put(openState.getValue(), value); player.getSession().send(new PacketOpenStateChangeNotify(openState.getValue(),value)); - } else { - Grasscutter.getLogger().debug("Warning: OpenState {} is already set to {}!", openState, value); } } @@ -73,9 +71,9 @@ public class PlayerOpenStateManager { player.getSession().send(new PacketOpenStateUpdateNotify(this)); } - public void onPlayerLevelUp() { + public void unlockLevelDependentStates() { Stream.of(OpenState.values()) - .filter(s -> s.getUnlockLevel() == this.player.getLevel()) + .filter(s -> s.getUnlockLevel() > 1 && s.getUnlockLevel() <= this.player.getLevel()) .forEach(s -> this.setOpenState(s, 1)); } } \ No newline at end of file From 3eb85b82a7d18df15f998cebf229b308f3d7fe98 Mon Sep 17 00:00:00 2001 From: AZthemute <104761702+AZthemute@users.noreply.github.com> Date: Sun, 17 Jul 2022 18:45:03 +0100 Subject: [PATCH 22/61] Updated banners for 2.8, added comments to the banners and removed beginner's banner (it was breaking things) --- src/main/resources/defaults/data/Banners.json | 42 +++++++++++-------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/src/main/resources/defaults/data/Banners.json b/src/main/resources/defaults/data/Banners.json index 7aade0aaf..e08679c63 100644 --- a/src/main/resources/defaults/data/Banners.json +++ b/src/main/resources/defaults/data/Banners.json @@ -1,21 +1,23 @@ [ { - "gachaType": 100, + "comment5": "5 stars: Kaedehara Kazuha", + "comment4": "4 stars: Thoma, Ningguang and Shinakonin Heizou", + "gachaType": 301, "scheduleId": 803, "bannerType": "EVENT", - "prefabPath": "GachaShowPanel_A016", - "previewPrefabPath": "UI_Tab_GachaShowPanel_A016", - "titlePath": "UI_GACHA_SHOW_PANEL_A016_TITLE", - "costItemId": 224, - "costItemAmount10": 8, - "gachaTimesLimit": 20, + "prefabPath": "GachaShowPanel_A086", + "previewPrefabPath": "UI_Tab_GachaShowPanel_A086", + "titlePath": "UI_GACHA_SHOW_PANEL_A045_TITLE", + "costItemId": 223, "beginTime": 0, "endTime": 1924992000, "sortId": 9999, - "rateUpItems5": [], - "rateUpItems4": [1034] + "rateUpItems4": [1059, 1050, 1027], + "rateUpItems5": [1047], + "weights5": [[1,80], [73,80], [90,10000]] }, { + "comment": "Standard", "gachaType": 200, "scheduleId": 893, "bannerType": "STANDARD", @@ -30,34 +32,38 @@ "weights5": [[1,75], [73,150], [90,10000]] }, { + "comment5": "5 stars: Klee", + "comment4": "4 stars: Thoma, Ningguang and Shinakonin Heizou", "gachaType": 301, "scheduleId": 903, "bannerType": "EVENT", - "prefabPath": "GachaShowPanel_A084", - "previewPrefabPath": "UI_Tab_GachaShowPanel_A084", - "titlePath": "UI_GACHA_SHOW_PANEL_A061_TITLE", + "prefabPath": "GachaShowPanel_A087", + "previewPrefabPath": "UI_Tab_GachaShowPanel_A087", + "titlePath": "UI_GACHA_SHOW_PANEL_A018_TITLE", "costItemId": 223, "beginTime": 0, "endTime": 1924992000, "sortId": 9999, - "rateUpItems4": [1065, 1036, 1055], - "rateUpItems5": [1057], + "rateUpItems4": [1059, 1050, 1027], + "rateUpItems5": [1029], "fallbackItems5Pool2": [], "weights5": [[1,80], [73,80], [90,10000]] }, { + "comment5": "5 stars: Freedom-Sworn, Lost Prayer to the Sacred Winds", + "comment4": "4 stars: The Alley Flash, Rainslasher, Favonius Lance, The Widsith, Mitternachts Waltz", "gachaType": 302, "scheduleId": 913, "bannerType": "WEAPON", - "prefabPath": "GachaShowPanel_A085", - "previewPrefabPath": "UI_Tab_GachaShowPanel_A085", + "prefabPath": "GachaShowPanel_A088", + "previewPrefabPath": "UI_Tab_GachaShowPanel_A088", "titlePath": "UI_GACHA_SHOW_PANEL_A013_TITLE", "costItemId": 223, "beginTime": 0, "endTime": 1924992000, "sortId": 9998, - "rateUpItems4": [12410, 11405, 13401, 14403, 15402], - "rateUpItems5": [12510, 14504], + "rateUpItems4":[11410, 12405, 13407, 14402, 15412], + "rateUpItems5": [11503, 14502], "fallbackItems5Pool1": [], "weights4": [[1,600], [7,600], [8,6600], [10,12600]], "weights5": [[1,100], [62,100], [73,7800], [80,10000]], From 3957616b6c30b5128fb8bf5f9b45b12b3488dd89 Mon Sep 17 00:00:00 2001 From: AnimeGitB Date: Tue, 19 Jul 2022 13:31:03 +0930 Subject: [PATCH 23/61] Fix 2.8 banners, readd Beginner's banner --- src/main/resources/defaults/data/Banners.json | 47 ++++++++++++++----- 1 file changed, 34 insertions(+), 13 deletions(-) diff --git a/src/main/resources/defaults/data/Banners.json b/src/main/resources/defaults/data/Banners.json index e08679c63..6828cf297 100644 --- a/src/main/resources/defaults/data/Banners.json +++ b/src/main/resources/defaults/data/Banners.json @@ -1,20 +1,21 @@ [ { - "comment5": "5 stars: Kaedehara Kazuha", - "comment4": "4 stars: Thoma, Ningguang and Shinakonin Heizou", - "gachaType": 301, + "comment": "Beginner's Banner. Do not change for no reason.", + "comment4": "4 stars: Noelle", + "gachaType": 100, "scheduleId": 803, "bannerType": "EVENT", - "prefabPath": "GachaShowPanel_A086", - "previewPrefabPath": "UI_Tab_GachaShowPanel_A086", - "titlePath": "UI_GACHA_SHOW_PANEL_A045_TITLE", - "costItemId": 223, + "prefabPath": "GachaShowPanel_A016", + "previewPrefabPath": "UI_Tab_GachaShowPanel_A016", + "titlePath": "UI_GACHA_SHOW_PANEL_A016_TITLE", + "costItemId": 224, + "costItemAmount10": 8, + "gachaTimesLimit": 20, "beginTime": 0, "endTime": 1924992000, "sortId": 9999, - "rateUpItems4": [1059, 1050, 1027], - "rateUpItems5": [1047], - "weights5": [[1,80], [73,80], [90,10000]] + "rateUpItems5": [], + "rateUpItems4": [1034] }, { "comment": "Standard", @@ -32,24 +33,44 @@ "weights5": [[1,75], [73,150], [90,10000]] }, { - "comment5": "5 stars: Klee", + "comment": "Character Event Banner 1", + "comment5": "5 stars: Kaedehara Kazuha", "comment4": "4 stars: Thoma, Ningguang and Shinakonin Heizou", "gachaType": 301, "scheduleId": 903, "bannerType": "EVENT", + "prefabPath": "GachaShowPanel_A086", + "previewPrefabPath": "UI_Tab_GachaShowPanel_A086", + "titlePath": "UI_GACHA_SHOW_PANEL_A045_TITLE", + "costItemId": 223, + "beginTime": 0, + "endTime": 1924992000, + "sortId": 9998, + "rateUpItems4": [1059, 1050, 1027], + "rateUpItems5": [1047], + "weights5": [[1,80], [73,80], [90,10000]] + }, + { + "comment": "Character Event Banner 2", + "comment5": "5 stars: Klee", + "comment4": "4 stars: Thoma, Ningguang and Shinakonin Heizou", + "gachaType": 400, + "scheduleId": 923, + "bannerType": "EVENT", "prefabPath": "GachaShowPanel_A087", "previewPrefabPath": "UI_Tab_GachaShowPanel_A087", "titlePath": "UI_GACHA_SHOW_PANEL_A018_TITLE", "costItemId": 223, "beginTime": 0, "endTime": 1924992000, - "sortId": 9999, + "sortId": 9998, "rateUpItems4": [1059, 1050, 1027], "rateUpItems5": [1029], "fallbackItems5Pool2": [], "weights5": [[1,80], [73,80], [90,10000]] }, { + "comment": "Weapon Event Banner", "comment5": "5 stars: Freedom-Sworn, Lost Prayer to the Sacred Winds", "comment4": "4 stars: The Alley Flash, Rainslasher, Favonius Lance, The Widsith, Mitternachts Waltz", "gachaType": 302, @@ -61,7 +82,7 @@ "costItemId": 223, "beginTime": 0, "endTime": 1924992000, - "sortId": 9998, + "sortId": 9997, "rateUpItems4":[11410, 12405, 13407, 14402, 15412], "rateUpItems5": [11503, 14502], "fallbackItems5Pool1": [], From d20e9d1f72e28d2cabc48d0bcf35582938c9b50f Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Mon, 18 Jul 2022 20:42:22 -0700 Subject: [PATCH 24/61] Refactor player managers --- .../game/ability/AbilityManager.java | 9 +- .../game/activity/ActivityManager.java | 6 +- .../game/avatar/AvatarProfileData.java | 26 -- .../game/avatar/AvatarStorage.java | 10 +- .../game/battlepass/BattlePassManager.java | 7 +- .../grasscutter/game/friends/FriendsList.java | 11 +- .../grasscutter/game/inventory/Inventory.java | 12 +- .../grasscutter/game/mail/MailHandler.java | 12 +- .../game/managers/CookingManager.java | 7 +- .../game/managers/FurnitureManager.java | 8 +- .../game/managers/InsectCaptureManager.java | 8 +- .../game/managers/ResinManager.java | 6 +- .../game/managers/SotSManager.java | 6 +- .../collection/CollectionManager.java | 74 ----- .../deforestation/DeforestationManager.java | 12 +- .../game/managers/energy/EnergyManager.java | 10 +- .../game/managers/forging/ForgingManager.java | 6 +- .../managers/mapmark/MapMarksManager.java | 31 +- .../game/managers/stamina/StaminaManager.java | 6 +- .../game/player/BasePlayerDataManager.java | 23 ++ .../game/player/BasePlayerManager.java | 15 + .../emu/grasscutter/game/player/Player.java | 312 +++++------------- .../game/player/PlayerOpenStateManager.java | 10 +- .../grasscutter/game/player/TeamManager.java | 17 +- .../grasscutter/game/quest/QuestManager.java | 10 +- .../grasscutter/game/tower/TowerManager.java | 54 +-- .../HandlerEnterTransPointRegionNotify.java | 2 +- .../HandlerExitTransPointRegionNotify.java | 2 +- .../send/PacketHomeBasicInfoNotify.java | 2 +- .../server/packet/send/PacketMarkMapRsp.java | 2 +- 30 files changed, 231 insertions(+), 485 deletions(-) delete mode 100644 src/main/java/emu/grasscutter/game/avatar/AvatarProfileData.java delete mode 100644 src/main/java/emu/grasscutter/game/managers/collection/CollectionManager.java create mode 100644 src/main/java/emu/grasscutter/game/player/BasePlayerDataManager.java create mode 100644 src/main/java/emu/grasscutter/game/player/BasePlayerManager.java diff --git a/src/main/java/emu/grasscutter/game/ability/AbilityManager.java b/src/main/java/emu/grasscutter/game/ability/AbilityManager.java index 394313ef2..1464e5717 100644 --- a/src/main/java/emu/grasscutter/game/ability/AbilityManager.java +++ b/src/main/java/emu/grasscutter/game/ability/AbilityManager.java @@ -21,6 +21,7 @@ import emu.grasscutter.game.entity.EntityItem; import emu.grasscutter.game.entity.GameEntity; import emu.grasscutter.game.entity.gadget.GadgetGatherObject; import emu.grasscutter.game.entity.gadget.GadgetGatherPoint; +import emu.grasscutter.game.player.BasePlayerManager; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.ElementType; import emu.grasscutter.net.proto.AbilityActionGenerateElemBallOuterClass.AbilityActionGenerateElemBall; @@ -35,18 +36,14 @@ import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Utils; import emu.grasscutter.game.props.FightProperty; -public class AbilityManager { +public class AbilityManager extends BasePlayerManager { private Player player; HealAbilityManager healAbilityManager; public AbilityManager(Player player) { - this.player = player; + super(player); this.healAbilityManager = new HealAbilityManager(player); } - - public Player getPlayer() { - return this.player; - } public void onAbilityInvoke(AbilityInvokeEntry invoke) throws Exception { healAbilityManager.healHandler(invoke); diff --git a/src/main/java/emu/grasscutter/game/activity/ActivityManager.java b/src/main/java/emu/grasscutter/game/activity/ActivityManager.java index b511a2629..b3cdb024a 100644 --- a/src/main/java/emu/grasscutter/game/activity/ActivityManager.java +++ b/src/main/java/emu/grasscutter/game/activity/ActivityManager.java @@ -5,6 +5,7 @@ import com.google.gson.reflect.TypeToken; import emu.grasscutter.Grasscutter; import emu.grasscutter.data.DataLoader; import emu.grasscutter.data.GameData; +import emu.grasscutter.game.player.BasePlayerManager; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.ActivityType; import emu.grasscutter.game.props.WatcherTriggerType; @@ -19,9 +20,8 @@ import java.util.*; import java.util.concurrent.ConcurrentHashMap; @Getter -public class ActivityManager { +public class ActivityManager extends BasePlayerManager { private static final Map activityConfigItemMap; - private final Player player; private final Map playerActivityDataMap; static { @@ -79,7 +79,7 @@ public class ActivityManager { } public ActivityManager(Player player){ - this.player = player; + super(player); playerActivityDataMap = new ConcurrentHashMap<>(); // load data for player diff --git a/src/main/java/emu/grasscutter/game/avatar/AvatarProfileData.java b/src/main/java/emu/grasscutter/game/avatar/AvatarProfileData.java deleted file mode 100644 index b38855b81..000000000 --- a/src/main/java/emu/grasscutter/game/avatar/AvatarProfileData.java +++ /dev/null @@ -1,26 +0,0 @@ -package emu.grasscutter.game.avatar; - -import dev.morphia.annotations.Entity; - -@Entity -public class AvatarProfileData { - private int avatarId; - private int level; - - public AvatarProfileData(Avatar avatar) { - this.update(avatar); - } - - public int getAvatarId() { - return avatarId; - } - - public int getLevel() { - return level; - } - - public void update(Avatar avatar) { - this.avatarId = avatar.getAvatarId(); - this.level = avatar.getLevel(); - } -} diff --git a/src/main/java/emu/grasscutter/game/avatar/AvatarStorage.java b/src/main/java/emu/grasscutter/game/avatar/AvatarStorage.java index 8feae29c6..3c3596277 100644 --- a/src/main/java/emu/grasscutter/game/avatar/AvatarStorage.java +++ b/src/main/java/emu/grasscutter/game/avatar/AvatarStorage.java @@ -9,6 +9,7 @@ import emu.grasscutter.data.excels.AvatarSkillDepotData; import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.game.entity.EntityAvatar; import emu.grasscutter.game.inventory.GameItem; +import emu.grasscutter.game.player.BasePlayerManager; import emu.grasscutter.game.player.Player; import emu.grasscutter.server.packet.send.PacketAvatarChangeCostumeNotify; import emu.grasscutter.server.packet.send.PacketAvatarFlycloakChangeNotify; @@ -17,20 +18,15 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; -public class AvatarStorage implements Iterable { - private final Player player; +public class AvatarStorage extends BasePlayerManager implements Iterable { private final Int2ObjectMap avatars; private final Long2ObjectMap avatarsGuid; public AvatarStorage(Player player) { - this.player = player; + super(player); this.avatars = new Int2ObjectOpenHashMap<>(); this.avatarsGuid = new Long2ObjectOpenHashMap<>(); } - - public Player getPlayer() { - return player; - } public Int2ObjectMap getAvatars() { return avatars; diff --git a/src/main/java/emu/grasscutter/game/battlepass/BattlePassManager.java b/src/main/java/emu/grasscutter/game/battlepass/BattlePassManager.java index 028312d90..2f74819f1 100644 --- a/src/main/java/emu/grasscutter/game/battlepass/BattlePassManager.java +++ b/src/main/java/emu/grasscutter/game/battlepass/BattlePassManager.java @@ -15,7 +15,6 @@ import org.bson.types.ObjectId; import dev.morphia.annotations.Entity; import dev.morphia.annotations.Id; import dev.morphia.annotations.Indexed; -import dev.morphia.annotations.Transient; import emu.grasscutter.GameConstants; import emu.grasscutter.Grasscutter; import emu.grasscutter.data.GameData; @@ -26,6 +25,7 @@ import emu.grasscutter.data.excels.RewardData; import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.game.inventory.GameItem; import emu.grasscutter.game.inventory.MaterialType; +import emu.grasscutter.game.player.BasePlayerDataManager; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.BattlePassMissionRefreshType; import emu.grasscutter.game.props.BattlePassMissionStatus; @@ -41,9 +41,8 @@ import emu.grasscutter.server.packet.send.PacketTakeBattlePassRewardRsp; import lombok.Getter; @Entity(value = "battlepass", useDiscriminator = false) -public class BattlePassManager { +public class BattlePassManager extends BasePlayerDataManager { @Id @Getter private ObjectId id; - @Transient @Getter private Player player; @Indexed private int ownerUid; @Getter private int point; @@ -60,7 +59,7 @@ public class BattlePassManager { public BattlePassManager() {} public BattlePassManager(Player player) { - this.setPlayer(player); + super(player); } public void setPlayer(Player player) { diff --git a/src/main/java/emu/grasscutter/game/friends/FriendsList.java b/src/main/java/emu/grasscutter/game/friends/FriendsList.java index 70eace5ca..399406295 100644 --- a/src/main/java/emu/grasscutter/game/friends/FriendsList.java +++ b/src/main/java/emu/grasscutter/game/friends/FriendsList.java @@ -3,6 +3,7 @@ package emu.grasscutter.game.friends; import java.util.List; import emu.grasscutter.database.DatabaseHelper; +import emu.grasscutter.game.player.BasePlayerManager; import emu.grasscutter.game.player.Player; import emu.grasscutter.net.proto.DealAddFriendResultTypeOuterClass.DealAddFriendResultType; import emu.grasscutter.server.packet.send.PacketAskAddFriendNotify; @@ -13,24 +14,18 @@ import emu.grasscutter.server.packet.send.PacketDeleteFriendRsp; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -public class FriendsList { - private final Player player; - +public class FriendsList extends BasePlayerManager { private final Int2ObjectMap friends; private final Int2ObjectMap pendingFriends; private boolean loaded = false; public FriendsList(Player player) { - this.player = player; + super(player); this.friends = new Int2ObjectOpenHashMap(); this.pendingFriends = new Int2ObjectOpenHashMap(); } - public Player getPlayer() { - return player; - } - public boolean hasLoaded() { return loaded; } diff --git a/src/main/java/emu/grasscutter/game/inventory/Inventory.java b/src/main/java/emu/grasscutter/game/inventory/Inventory.java index a40a6ac5a..f5660a955 100644 --- a/src/main/java/emu/grasscutter/game/inventory/Inventory.java +++ b/src/main/java/emu/grasscutter/game/inventory/Inventory.java @@ -15,6 +15,7 @@ import emu.grasscutter.data.excels.ItemData; import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.game.avatar.AvatarStorage; import emu.grasscutter.game.avatar.Avatar; +import emu.grasscutter.game.player.BasePlayerManager; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.ActionReason; import emu.grasscutter.game.props.PlayerProperty; @@ -31,14 +32,13 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; import static emu.grasscutter.Configuration.*; -public class Inventory implements Iterable { - private final Player player; - +public class Inventory extends BasePlayerManager implements Iterable { private final Long2ObjectMap store; private final Int2ObjectMap inventoryTypes; public Inventory(Player player) { - this.player = player; + super(player); + this.store = new Long2ObjectOpenHashMap<>(); this.inventoryTypes = new Int2ObjectOpenHashMap<>(); @@ -48,10 +48,6 @@ public class Inventory implements Iterable { this.createInventoryTab(ItemType.ITEM_FURNITURE, new MaterialInventoryTab(INVENTORY_LIMITS.furniture)); } - public Player getPlayer() { - return player; - } - public AvatarStorage getAvatarStorage() { return this.getPlayer().getAvatars(); } diff --git a/src/main/java/emu/grasscutter/game/mail/MailHandler.java b/src/main/java/emu/grasscutter/game/mail/MailHandler.java index ad2f84694..12e741816 100644 --- a/src/main/java/emu/grasscutter/game/mail/MailHandler.java +++ b/src/main/java/emu/grasscutter/game/mail/MailHandler.java @@ -1,30 +1,26 @@ package emu.grasscutter.game.mail; -import java.time.Instant; import java.util.ArrayList; import java.util.Collections; import java.util.List; import emu.grasscutter.Grasscutter; import emu.grasscutter.database.DatabaseHelper; +import emu.grasscutter.game.player.BasePlayerManager; import emu.grasscutter.game.player.Player; import emu.grasscutter.server.event.player.PlayerReceiveMailEvent; import emu.grasscutter.server.packet.send.PacketDelMailRsp; import emu.grasscutter.server.packet.send.PacketMailChangeNotify; -public class MailHandler { - private final Player player; +public class MailHandler extends BasePlayerManager { private final List mail; public MailHandler(Player player) { - this.player = player; + super(player); + this.mail = new ArrayList<>(); } - public Player getPlayer() { - return player; - } - public List getMail() { return mail; } diff --git a/src/main/java/emu/grasscutter/game/managers/CookingManager.java b/src/main/java/emu/grasscutter/game/managers/CookingManager.java index 855fd56ec..5964d4f19 100644 --- a/src/main/java/emu/grasscutter/game/managers/CookingManager.java +++ b/src/main/java/emu/grasscutter/game/managers/CookingManager.java @@ -10,6 +10,7 @@ import emu.grasscutter.data.GameData; import emu.grasscutter.data.common.ItemParamData; import emu.grasscutter.data.excels.ItemData; import emu.grasscutter.game.inventory.GameItem; +import emu.grasscutter.game.player.BasePlayerManager; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.ActionReason; import emu.grasscutter.net.proto.CookRecipeDataOuterClass; @@ -22,14 +23,12 @@ import emu.grasscutter.server.packet.send.PacketPlayerCookArgsRsp; import emu.grasscutter.server.packet.send.PacketPlayerCookRsp; import io.netty.util.internal.ThreadLocalRandom; -public class CookingManager { +public class CookingManager extends BasePlayerManager { private static final int MANUAL_PERFECT_COOK_QUALITY = 3; - private static Set defaultUnlockedRecipies; - private final Player player; public CookingManager(Player player) { - this.player = player; + super(player); } public static void initialize() { diff --git a/src/main/java/emu/grasscutter/game/managers/FurnitureManager.java b/src/main/java/emu/grasscutter/game/managers/FurnitureManager.java index 33d771df9..d18119405 100644 --- a/src/main/java/emu/grasscutter/game/managers/FurnitureManager.java +++ b/src/main/java/emu/grasscutter/game/managers/FurnitureManager.java @@ -4,6 +4,7 @@ import emu.grasscutter.data.GameData; import emu.grasscutter.data.common.ItemParamData; import emu.grasscutter.game.home.FurnitureMakeSlotItem; import emu.grasscutter.game.inventory.GameItem; +import emu.grasscutter.game.player.BasePlayerManager; import emu.grasscutter.game.player.Player; import emu.grasscutter.net.proto.ItemParamOuterClass; import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode; @@ -13,11 +14,10 @@ import emu.grasscutter.utils.Utils; import java.util.ArrayList; import java.util.List; -public class FurnitureManager { - private final Player player; - +public class FurnitureManager extends BasePlayerManager { + public FurnitureManager(Player player) { - this.player = player; + super(player); } public void onLogin(){ diff --git a/src/main/java/emu/grasscutter/game/managers/InsectCaptureManager.java b/src/main/java/emu/grasscutter/game/managers/InsectCaptureManager.java index 9fe5623b1..42a21bbb3 100644 --- a/src/main/java/emu/grasscutter/game/managers/InsectCaptureManager.java +++ b/src/main/java/emu/grasscutter/game/managers/InsectCaptureManager.java @@ -8,11 +8,17 @@ import emu.grasscutter.game.entity.EntityMonster; import emu.grasscutter.game.entity.EntityVehicle; import emu.grasscutter.game.entity.GameEntity; import emu.grasscutter.game.inventory.GameItem; +import emu.grasscutter.game.player.BasePlayerManager; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.ActionReason; import emu.grasscutter.net.proto.VisionTypeOuterClass; -public record InsectCaptureManager(Player player) { +public class InsectCaptureManager extends BasePlayerManager { + + public InsectCaptureManager(Player player) { + super(player); + } + public void arrestSmallCreature(GameEntity entity) { //System.out.println("arrestSmallCreature!"); EnvAnimalGatherConfigData gather; diff --git a/src/main/java/emu/grasscutter/game/managers/ResinManager.java b/src/main/java/emu/grasscutter/game/managers/ResinManager.java index 76393c7f3..2fefe88e1 100644 --- a/src/main/java/emu/grasscutter/game/managers/ResinManager.java +++ b/src/main/java/emu/grasscutter/game/managers/ResinManager.java @@ -1,5 +1,6 @@ package emu.grasscutter.game.managers; +import emu.grasscutter.game.player.BasePlayerManager; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.PlayerProperty; import emu.grasscutter.game.props.WatcherTriggerType; @@ -9,11 +10,10 @@ import emu.grasscutter.utils.Utils; import static emu.grasscutter.Configuration.GAME_OPTIONS; -public class ResinManager { - private final Player player; +public class ResinManager extends BasePlayerManager { public ResinManager(Player player) { - this.player = player; + super(player); } /******************** diff --git a/src/main/java/emu/grasscutter/game/managers/SotSManager.java b/src/main/java/emu/grasscutter/game/managers/SotSManager.java index c1d1326a6..8002fafa8 100644 --- a/src/main/java/emu/grasscutter/game/managers/SotSManager.java +++ b/src/main/java/emu/grasscutter/game/managers/SotSManager.java @@ -3,6 +3,7 @@ package emu.grasscutter.game.managers; import ch.qos.logback.classic.Logger; import emu.grasscutter.Grasscutter; import emu.grasscutter.game.entity.EntityAvatar; +import emu.grasscutter.game.player.BasePlayerManager; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.props.PlayerProperty; @@ -16,11 +17,10 @@ import java.util.Timer; import java.util.TimerTask; // Statue of the Seven Manager -public class SotSManager { +public class SotSManager extends BasePlayerManager { // NOTE: Spring volume balance *1 = fight prop HP *100 - private final Player player; private final Logger logger = Grasscutter.getLogger(); private Timer autoRecoverTimer; private final boolean enablePriorityHealing = false; @@ -28,7 +28,7 @@ public class SotSManager { public final static int GlobalMaximumSpringVolume = PlayerProperty.PROP_MAX_SPRING_VOLUME.getMax(); public SotSManager(Player player) { - this.player = player; + super(player); } public boolean getIsAutoRecoveryEnabled() { diff --git a/src/main/java/emu/grasscutter/game/managers/collection/CollectionManager.java b/src/main/java/emu/grasscutter/game/managers/collection/CollectionManager.java deleted file mode 100644 index 47f21b459..000000000 --- a/src/main/java/emu/grasscutter/game/managers/collection/CollectionManager.java +++ /dev/null @@ -1,74 +0,0 @@ -package emu.grasscutter.game.managers.collection; - -import java.util.HashMap; -import java.util.List; - -import emu.grasscutter.game.entity.EntityGadget; -import emu.grasscutter.game.player.Player; - -public class CollectionManager { - private static final long SECOND = 1000; //1 Second - private static final long MINUTE = SECOND*60; //1 Minute - private static final long HOUR = MINUTE*60; //1 Hour - private static final long DAY = HOUR*24; //1 Day - private static final HashMap DEFINE_REFRESH_TIME = new HashMap<>();// - private static final long DEFAULT_REFRESH_TIME = HOUR*6; // default 6 Hours - - static { - DEFINE_REFRESH_TIME.put(70590027,3*DAY);//星银矿石 3 Days - DEFINE_REFRESH_TIME.put(70590036,3*DAY);//紫晶块 3 Days - DEFINE_REFRESH_TIME.put(70520003,3*DAY);//水晶 3 Days - - DEFINE_REFRESH_TIME.put(70590013,2*DAY);//嘟嘟莲 2 Days - DEFINE_REFRESH_TIME.put(70540029,2*DAY);//清心 2 Days - DEFINE_REFRESH_TIME.put(70540028,2*DAY);//星螺 2 Days - DEFINE_REFRESH_TIME.put(70540027,2*DAY);//马尾 2 Days - DEFINE_REFRESH_TIME.put(70540026,2*DAY);//琉璃袋 2 Days - DEFINE_REFRESH_TIME.put(70540022,2*DAY);//落落莓 2 Days - DEFINE_REFRESH_TIME.put(70540020,2*DAY);//慕风蘑菇 2 Days - DEFINE_REFRESH_TIME.put(70540019,2*DAY);//风车菊 2 Days - DEFINE_REFRESH_TIME.put(70540018,2*DAY);//塞西莉亚花 2 Days - DEFINE_REFRESH_TIME.put(70540015,2*DAY);//霓裳花 2 Days - DEFINE_REFRESH_TIME.put(70540014,2*DAY);//莲蓬 2 Days - DEFINE_REFRESH_TIME.put(70540013,2*DAY);//钩钩果 2 Days - DEFINE_REFRESH_TIME.put(70540012,2*DAY);//琉璃百合 2 Days - DEFINE_REFRESH_TIME.put(70540008,2*DAY);//绝云椒椒 2 Days - DEFINE_REFRESH_TIME.put(70520018,2*DAY);//夜泊石 2 Days - DEFINE_REFRESH_TIME.put(70520002,2*DAY);//白铁矿 2 Days - DEFINE_REFRESH_TIME.put(70510012,2*DAY);//石珀 2 Days - DEFINE_REFRESH_TIME.put(70510009,2*DAY);//蒲公英 2 Days - DEFINE_REFRESH_TIME.put(70510007,2*DAY);//冰雾花 2 Days - DEFINE_REFRESH_TIME.put(70510006,2*DAY);//烈焰花 2 Days - DEFINE_REFRESH_TIME.put(70510005,2*DAY);//电气水晶 2 Days - DEFINE_REFRESH_TIME.put(70510004,2*DAY);//小灯草 2 Days - - - DEFINE_REFRESH_TIME.put(70540021,DAY);//日落果 1 Day - DEFINE_REFRESH_TIME.put(70540005,DAY);//松果 1 Day - DEFINE_REFRESH_TIME.put(70540003,DAY);//苹果 1 Day - DEFINE_REFRESH_TIME.put(70540001,DAY);//树莓 1 Day - DEFINE_REFRESH_TIME.put(70520019,DAY);//魔晶块 1 Days - DEFINE_REFRESH_TIME.put(70520008,DAY);//金鱼草 1 Days - DEFINE_REFRESH_TIME.put(70520007,DAY);//白萝卜 1 Days - DEFINE_REFRESH_TIME.put(70520006,DAY);//胡萝卜 1 Days - DEFINE_REFRESH_TIME.put(70520004,DAY);//蘑菇 1 Day - DEFINE_REFRESH_TIME.put(70520001,DAY);//铁矿 1 Day - - DEFINE_REFRESH_TIME.put(70520009,12*HOUR);//薄荷 12 Hours - DEFINE_REFRESH_TIME.put(70520005,12*HOUR);//甜甜花 12 Hours - } - - private final static HashMap> CollectionResourcesData = new HashMap<>(); - private final HashMap spawnedEntities = new HashMap<>(); - private CollectionRecordStore collectionRecordStore; - Player player; - - private static long getGadgetRefreshTime(int gadgetId){ - return DEFINE_REFRESH_TIME.getOrDefault(gadgetId,DEFAULT_REFRESH_TIME); - } - - public synchronized void setPlayer(Player player) { - this.player = player; - this.collectionRecordStore = player.getCollectionRecordStore(); - } -} diff --git a/src/main/java/emu/grasscutter/game/managers/deforestation/DeforestationManager.java b/src/main/java/emu/grasscutter/game/managers/deforestation/DeforestationManager.java index 3650bdb31..a0fb46588 100644 --- a/src/main/java/emu/grasscutter/game/managers/deforestation/DeforestationManager.java +++ b/src/main/java/emu/grasscutter/game/managers/deforestation/DeforestationManager.java @@ -7,20 +7,21 @@ import dev.morphia.annotations.Transient; import emu.grasscutter.Grasscutter; import emu.grasscutter.data.GameData; import emu.grasscutter.game.entity.EntityItem; +import emu.grasscutter.game.player.BasePlayerManager; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.world.Scene; import emu.grasscutter.net.proto.HitTreeNotifyOuterClass; import emu.grasscutter.net.proto.VectorOuterClass; import emu.grasscutter.utils.Position; -public class DeforestationManager { +public class DeforestationManager extends BasePlayerManager { final static int RECORD_EXPIRED_SECONDS = 60*5; // 5 min final static int RECORD_MAX_TIMES = 3; // max number of wood final static int RECORD_MAX_TIMES_OTHER_HIT_TREE = 10; // if hit 10 times other trees, reset wood - @Transient private final Player player; - @Transient private final ArrayList currentRecord; - @Transient private final static HashMap ColliderTypeToWoodItemID = new HashMap<>(); + private final ArrayList currentRecord; + private final static HashMap ColliderTypeToWoodItemID = new HashMap<>(); + static { /* define wood types which reflected to item id*/ ColliderTypeToWoodItemID.put(1,101301); @@ -36,8 +37,9 @@ public class DeforestationManager { ColliderTypeToWoodItemID.put(11,101311); ColliderTypeToWoodItemID.put(12,101312); } + public DeforestationManager(Player player){ - this.player = player; + super(player); this.currentRecord = new ArrayList<>(); } public void resetWood(){ diff --git a/src/main/java/emu/grasscutter/game/managers/energy/EnergyManager.java b/src/main/java/emu/grasscutter/game/managers/energy/EnergyManager.java index 0ba5a5dfb..e688267d9 100644 --- a/src/main/java/emu/grasscutter/game/managers/energy/EnergyManager.java +++ b/src/main/java/emu/grasscutter/game/managers/energy/EnergyManager.java @@ -13,6 +13,7 @@ import emu.grasscutter.game.entity.EntityItem; import emu.grasscutter.game.entity.EntityMonster; import emu.grasscutter.game.entity.GameEntity; import emu.grasscutter.game.inventory.GameItem; +import emu.grasscutter.game.player.BasePlayerManager; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.ElementType; import emu.grasscutter.game.props.FightProperty; @@ -46,8 +47,7 @@ import static java.util.Map.entry; import com.google.gson.reflect.TypeToken; import com.google.protobuf.InvalidProtocolBufferException; -public class EnergyManager { - private final Player player; +public class EnergyManager extends BasePlayerManager { private final Map avatarNormalProbabilities; // energyUsage for each player private Boolean energyUsage; @@ -55,15 +55,11 @@ public class EnergyManager { private final static Int2ObjectMap> skillParticleGenerationData = new Int2ObjectOpenHashMap<>(); public EnergyManager(Player player) { - this.player = player; + super(player); this.avatarNormalProbabilities = new HashMap<>(); this.energyUsage=GAME_OPTIONS.energyUsage; } - public Player getPlayer() { - return this.player; - } - public static void initialize() { // Read the data we need for monster energy drops. try (Reader fileReader = new InputStreamReader(DataLoader.load("EnergyDrop.json"))) { diff --git a/src/main/java/emu/grasscutter/game/managers/forging/ForgingManager.java b/src/main/java/emu/grasscutter/game/managers/forging/ForgingManager.java index 54ad374e1..9cd3dc63b 100644 --- a/src/main/java/emu/grasscutter/game/managers/forging/ForgingManager.java +++ b/src/main/java/emu/grasscutter/game/managers/forging/ForgingManager.java @@ -11,6 +11,7 @@ import emu.grasscutter.data.common.ItemParamData; import emu.grasscutter.data.excels.ForgeData; import emu.grasscutter.data.excels.ItemData; import emu.grasscutter.game.inventory.GameItem; +import emu.grasscutter.game.player.BasePlayerManager; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.ActionReason; import emu.grasscutter.game.props.WatcherTriggerType; @@ -27,11 +28,10 @@ import emu.grasscutter.server.packet.send.PacketForgeQueueManipulateRsp; import emu.grasscutter.server.packet.send.PacketForgeStartRsp; import emu.grasscutter.utils.Utils; -public class ForgingManager { - private final Player player; +public class ForgingManager extends BasePlayerManager { public ForgingManager(Player player) { - this.player = player; + super(player); } /********** diff --git a/src/main/java/emu/grasscutter/game/managers/mapmark/MapMarksManager.java b/src/main/java/emu/grasscutter/game/managers/mapmark/MapMarksManager.java index 1fa36ec58..dfde7a0e3 100644 --- a/src/main/java/emu/grasscutter/game/managers/mapmark/MapMarksManager.java +++ b/src/main/java/emu/grasscutter/game/managers/mapmark/MapMarksManager.java @@ -1,5 +1,6 @@ package emu.grasscutter.game.managers.mapmark; +import emu.grasscutter.game.player.BasePlayerManager; import emu.grasscutter.game.player.Player; import emu.grasscutter.net.proto.MapMarkPointTypeOuterClass.MapMarkPointType; import emu.grasscutter.net.proto.MarkMapReqOuterClass.MarkMapReq; @@ -9,16 +10,17 @@ import emu.grasscutter.server.packet.send.PacketSceneEntityAppearNotify; import emu.grasscutter.utils.Position; import java.util.HashMap; +import java.util.Map; -public class MapMarksManager { +public class MapMarksManager extends BasePlayerManager { public static final int mapMarkMaxCount = 150; - private HashMap mapMarks; - private final Player player; public MapMarksManager(Player player) { - this.player = player; - this.mapMarks = player.getMapMarks(); - if (this.mapMarks == null) { this.mapMarks = new HashMap<>(); } + super(player); + } + + public Map getMapMarks() { + return getPlayer().getMapMarks(); } public void handleMapMarkReq(MarkMapReq req) { @@ -45,31 +47,26 @@ public class MapMarksManager { } } if (op != Operation.OPERATION_GET) { - saveMapMarks(); + save(); } player.getSession().send(new PacketMarkMapRsp(getMapMarks())); } - - public HashMap getMapMarks() { - return mapMarks; - } - + public String getMapMarkKey(Position position) { return "x" + (int)position.getX()+ "z" + (int)position.getZ(); } public void removeMapMark(Position position) { - mapMarks.remove(getMapMarkKey(position)); + getMapMarks().remove(getMapMarkKey(position)); } public void addMapMark(MapMark mapMark) { - if (mapMarks.size() < mapMarkMaxCount) { - mapMarks.put(getMapMarkKey(mapMark.getPosition()), mapMark); + if (getMapMarks().size() < mapMarkMaxCount) { + getMapMarks().put(getMapMarkKey(mapMark.getPosition()), mapMark); } } - private void saveMapMarks() { - player.setMapMarks(mapMarks); + private void save() { player.save(); } diff --git a/src/main/java/emu/grasscutter/game/managers/stamina/StaminaManager.java b/src/main/java/emu/grasscutter/game/managers/stamina/StaminaManager.java index 6b9b03022..e72d737ec 100644 --- a/src/main/java/emu/grasscutter/game/managers/stamina/StaminaManager.java +++ b/src/main/java/emu/grasscutter/game/managers/stamina/StaminaManager.java @@ -5,6 +5,7 @@ import emu.grasscutter.Grasscutter; import emu.grasscutter.game.avatar.Avatar; import emu.grasscutter.game.entity.EntityAvatar; import emu.grasscutter.game.entity.GameEntity; +import emu.grasscutter.game.player.BasePlayerManager; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.props.LifeState; @@ -25,10 +26,9 @@ import java.util.*; import static emu.grasscutter.Configuration.GAME_OPTIONS; -public class StaminaManager { +public class StaminaManager extends BasePlayerManager { // TODO: Skiff state detection? - private final Player player; private static final HashMap> MotionStatesCategorized = new HashMap<>() {{ put("CLIMB", new HashSet<>(List.of( MotionState.MOTION_STATE_CLIMB, // sustained, when not moving no cost no recover @@ -163,7 +163,7 @@ public class StaminaManager { } public StaminaManager(Player player) { - this.player = player; + super(player); } // Accessors diff --git a/src/main/java/emu/grasscutter/game/player/BasePlayerDataManager.java b/src/main/java/emu/grasscutter/game/player/BasePlayerDataManager.java new file mode 100644 index 000000000..68447e892 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/player/BasePlayerDataManager.java @@ -0,0 +1,23 @@ +package emu.grasscutter.game.player; + +import lombok.NonNull; + +public abstract class BasePlayerDataManager { + protected transient Player player; + + public BasePlayerDataManager() {} + + public BasePlayerDataManager(@NonNull Player player) { + this.player = player; + } + + public Player getPlayer() { + return this.player; + } + + public void setPlayer(Player player) { + if (this.player == null) { + this.player = player; + } + } +} diff --git a/src/main/java/emu/grasscutter/game/player/BasePlayerManager.java b/src/main/java/emu/grasscutter/game/player/BasePlayerManager.java new file mode 100644 index 000000000..24023f726 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/player/BasePlayerManager.java @@ -0,0 +1,15 @@ +package emu.grasscutter.game.player; + +import lombok.NonNull; + +public abstract class BasePlayerManager { + protected transient final Player player; + + public BasePlayerManager(@NonNull Player player) { + this.player = player; + } + + public Player getPlayer() { + return this.player; + } +} diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index d4be0f3a6..e287fcb1e 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -4,7 +4,6 @@ import dev.morphia.annotations.*; import emu.grasscutter.GameConstants; import emu.grasscutter.Grasscutter; import emu.grasscutter.data.GameData; -import emu.grasscutter.data.excels.PersonalLineData; import emu.grasscutter.data.excels.PlayerLevelData; import emu.grasscutter.data.excels.WeatherData; import emu.grasscutter.database.DatabaseHelper; @@ -13,7 +12,6 @@ import emu.grasscutter.game.CoopRequest; import emu.grasscutter.game.ability.AbilityManager; import emu.grasscutter.game.activity.ActivityManager; import emu.grasscutter.game.avatar.Avatar; -import emu.grasscutter.game.avatar.AvatarProfileData; import emu.grasscutter.game.avatar.AvatarStorage; import emu.grasscutter.game.battlepass.BattlePassManager; import emu.grasscutter.game.entity.EntityMonster; @@ -34,7 +32,6 @@ import emu.grasscutter.game.managers.CookingManager; import emu.grasscutter.game.managers.FurnitureManager; import emu.grasscutter.game.managers.InsectCaptureManager; import emu.grasscutter.game.managers.ResinManager; -import emu.grasscutter.game.managers.collection.CollectionManager; import emu.grasscutter.game.managers.collection.CollectionRecordStore; import emu.grasscutter.game.managers.deforestation.DeforestationManager; import emu.grasscutter.game.managers.energy.EnergyManager; @@ -91,11 +88,11 @@ import static emu.grasscutter.Configuration.*; @Entity(value = "players", useDiscriminator = false) public class Player { - @Id private int id; @Indexed(options = @IndexOptions(unique = true)) private String accountId; - - @Transient private Account account; + private transient Account account; + private transient GameSession session; + private String nickname; private String signature; private int headImage; @@ -104,22 +101,29 @@ public class Player { private Position rotation; private PlayerBirthday birthday; private PlayerCodex codex; - @Getter private PlayerOpenStateManager openStateManager; + private boolean showAvatars; + private List showAvatarList; private Map properties; - private Set nameCardList; - private Set flyCloakList; - private Set costumeList; - private Set unlockedForgingBlueprints; - private Set unlockedCombines; - private Set unlockedFurniture; - private Set unlockedFurnitureSuite; - private List activeForges; - private Map unlockedRecipies; - - private Integer widgetId; - - private Set realmList; - private Integer currentRealmId; + private int currentRealmId; + private int widgetId; + private int sceneId; + private int regionId; + private int mainCharacterId; + private boolean godmode; + private boolean stamina; + + @Getter private Set nameCardList; + @Getter private Set flyCloakList; + @Getter private Set costumeList; + @Getter private Set rewardedLevels; + @Getter private Set realmList; + @Getter private Set unlockedForgingBlueprints; + @Getter private Set unlockedCombines; + @Getter private Set unlockedFurniture; + @Getter private Set unlockedFurnitureSuite; + @Getter private Map expeditionInfo; + @Getter private Map unlockedRecipies; + @Getter private List activeForges; @Transient private long nextGuid = 0; @Transient private int peerId; @@ -127,71 +131,56 @@ public class Player { @Transient private Scene scene; @Transient @Getter private int weatherId = 0; @Transient @Getter private ClimateType climate = ClimateType.CLIMATE_SUNNY; - @Transient private GameSession session; - @Transient private AvatarStorage avatars; - @Transient private Inventory inventory; - @Transient private FriendsList friendsList; - @Transient private MailHandler mailHandler; - @Transient private MessageHandler messageHandler; - @Transient private AbilityManager abilityManager; - @Transient private QuestManager questManager; + + // Player managers go here + @Getter private transient AvatarStorage avatars; + @Getter private transient Inventory inventory; + @Getter private transient FriendsList friendsList; + @Getter private transient MailHandler mailHandler; + @Getter private transient MessageHandler messageHandler; + @Getter private transient AbilityManager abilityManager; + @Getter private transient QuestManager questManager; + @Getter private transient TowerManager towerManager; + @Getter private transient SotSManager sotsManager; + @Getter private transient InsectCaptureManager insectCaptureManager; + @Getter private transient MapMarksManager mapMarksManager; + @Getter private transient StaminaManager staminaManager; + @Getter private transient EnergyManager energyManager; + @Getter private transient ResinManager resinManager; + @Getter private transient ForgingManager forgingManager; + @Getter private transient DeforestationManager deforestationManager; + @Getter private transient FurnitureManager furnitureManager; + @Getter private transient BattlePassManager battlePassManager; + @Getter private transient CookingManager cookingManager; + @Getter private transient ActivityManager activityManager; - @Transient private SotSManager sotsManager; - @Transient private InsectCaptureManager insectCaptureManager; - - private TeamManager teamManager; - - @Transient private TowerManager towerManager; + // Manager data (Save-able to the database) + private PlayerProfile playerProfile; + private TeamManager teamManager; private TowerData towerData; private PlayerGachaInfo gachaInfo; - private PlayerProfile playerProfile; - private boolean showAvatar; - private ArrayList shownAvatars; - private Set rewardedLevels; + private PlayerOpenStateManager openStateManager; + private CollectionRecordStore collectionRecordStore; private ArrayList shopLimit; - private Map expeditionInfo; - - private int sceneId; - private int regionId; - private int mainCharacterId; - private boolean godmode; - private boolean stamina; + + @Getter private transient GameHome home; private boolean moonCard; private Date moonCardStartTime; private int moonCardDuration; private Set moonCardGetTimes; - private List showAvatarList; - private boolean showAvatars; - @Transient private boolean paused; @Transient private int enterSceneToken; @Transient private SceneLoadState sceneState; @Transient private boolean hasSentAvatarDataNotify; @Transient private long nextSendPlayerLocTime = 0; - @Transient private final Int2ObjectMap coopRequests; - @Transient private final Queue attackResults; - @Transient private final InvokeHandler combatInvokeHandler; - @Transient private final InvokeHandler abilityInvokeHandler; - @Transient private final InvokeHandler clientAbilityInitFinishHandler; - - @Transient private MapMarksManager mapMarksManager; - @Transient private StaminaManager staminaManager; - @Transient private EnergyManager energyManager; - @Transient private ResinManager resinManager; - @Transient private ForgingManager forgingManager; - @Transient private DeforestationManager deforestationManager; - @Transient private GameHome home; - @Transient private FurnitureManager furnitureManager; - @Transient private BattlePassManager battlePassManager; - @Transient private CookingManager cookingManager; - // @Transient private - @Getter @Transient private ActivityManager activityManager; - - @Transient private CollectionManager collectionManager; - private CollectionRecordStore collectionRecordStore; + private transient final Int2ObjectMap coopRequests; + private transient final Queue attackResults; + @Getter private transient final InvokeHandler combatInvokeHandler; + @Getter private transient final InvokeHandler abilityInvokeHandler; + @Getter private transient final InvokeHandler clientAbilityInitFinishHandler; private long springLastUsed; private HashMap mapMarks; @@ -209,8 +198,8 @@ public class Player { this.abilityManager = new AbilityManager(this); this.deforestationManager = new DeforestationManager(this); this.insectCaptureManager = new InsectCaptureManager(this); - - this.setQuestManager(new QuestManager(this)); + this.questManager = new QuestManager(this); + this.pos = new Position(); this.rotation = new Position(); this.properties = new HashMap<>(); @@ -374,10 +363,6 @@ public class Player { this.session.send(new PacketSceneAreaWeatherNotify(this)); } - public int getGmLevel() { - return 1; - } - public String getNickname() { return nickname; } @@ -413,10 +398,6 @@ public class Player { this.widgetId = widgetId; } - public Set getRealmList() { - return realmList; - } - public void setRealmList(Set realmList) { this.realmList = realmList; } @@ -430,16 +411,14 @@ public class Player { this.realmList.add(realmId); } - public Integer getCurrentRealmId() { + public int getCurrentRealmId() { return currentRealmId; } - public void setCurrentRealmId(Integer currentRealmId) { + public void setCurrentRealmId(int currentRealmId) { this.currentRealmId = currentRealmId; } - public GameHome getHome(){ - return home; - } + public Position getPos() { return pos; } @@ -598,10 +577,6 @@ public class Player { return this.teamManager; } - public TowerManager getTowerManager() { - return towerManager; - } - public TowerData getTowerData() { if (towerData == null) { // because of mistake, null may be saved as storage at some machine, this if can be removed in future @@ -610,14 +585,6 @@ public class Player { return towerData; } - public QuestManager getQuestManager() { - return questManager; - } - - public void setQuestManager(QuestManager questManager) { - this.questManager = questManager; - } - public PlayerGachaInfo getGachaInfo() { return gachaInfo; } @@ -647,42 +614,6 @@ public class Player { return getProperties().get(prop.getId()); } - public Set getFlyCloakList() { - return flyCloakList; - } - - public Set getCostumeList() { - return costumeList; - } - - public Set getNameCardList() { - return this.nameCardList; - } - - public Set getUnlockedForgingBlueprints() { - return this.unlockedForgingBlueprints; - } - - public Set getUnlockedCombines() { - return this.unlockedCombines; - } - - public Set getUnlockedFurniture() { - return unlockedFurniture; - } - - public Set getUnlockedFurnitureSuite() { - return unlockedFurnitureSuite; - } - - public List getActiveForges() { - return this.activeForges; - } - - public Map getUnlockedRecipies() { - return this.unlockedRecipies; - } - public MpSettingType getMpSetting() { return MpSettingType.MP_SETTING_TYPE_ENTER_AFTER_APPLY; // TEMP } @@ -695,34 +626,6 @@ public class Player { return coopRequests; } - public InvokeHandler getCombatInvokeHandler() { - return this.combatInvokeHandler; - } - - public InvokeHandler getAbilityInvokeHandler() { - return this.abilityInvokeHandler; - } - - public InvokeHandler getClientAbilityInitFinishHandler() { - return clientAbilityInitFinishHandler; - } - - public AvatarStorage getAvatars() { - return avatars; - } - - public Inventory getInventory() { - return inventory; - } - - public FriendsList getFriendsList() { - return this.friendsList; - } - - public MailHandler getMailHandler() { - return mailHandler; - } - public int getEnterSceneToken() { return enterSceneToken; } @@ -931,10 +834,6 @@ public class Player { session.send(new PacketCardProductRewardNotify(getMoonCardRemainDays())); } - public Map getExpeditionInfo() { - return expeditionInfo; - } - public void addExpeditionInfo(long avaterGuid, int expId, int hourTime, int startTime){ ExpeditionInfo exp = new ExpeditionInfo(); exp.setExpId(expId); @@ -1188,10 +1087,8 @@ public class Player { return this.birthday.getDay() > 0; } - public PlayerCodex getCodex(){ return this.codex; } - - public Set getRewardedLevels() { - return rewardedLevels; + public PlayerCodex getCodex() { + return this.codex; } public void setRewardedLevels(Set rewardedLevels) { @@ -1290,59 +1187,12 @@ public class Player { .build(); } - public MapMarksManager getMapMarksManager() { - return mapMarksManager; - } - - public StaminaManager getStaminaManager() { return staminaManager; } - - public SotSManager getSotSManager() { return sotsManager; } - - public EnergyManager getEnergyManager() { - return this.energyManager; - } - - public ResinManager getResinManager() { - return this.resinManager; - } - - public ForgingManager getForgingManager() { - return this.forgingManager; - } - - public FurnitureManager getFurnitureManager() { - return furnitureManager; - } - - public BattlePassManager getBattlePassManager(){ - return battlePassManager; - } - - public CookingManager getCookingManager() { - return cookingManager; - } - public void loadBattlePassManager() { if (this.battlePassManager != null) return; this.battlePassManager = DatabaseHelper.loadBattlePass(this); this.battlePassManager.getMissions().values().removeIf(mission -> mission.getData() == null); } - public AbilityManager getAbilityManager() { - return abilityManager; - } - - public DeforestationManager getDeforestationManager() { - return deforestationManager; - } - - public CollectionManager getCollectionManager() { - if(this.collectionManager==null){ - this.collectionManager = new CollectionManager(); - } - return this.collectionManager; - } - public CollectionRecordStore getCollectionRecordStore() { if(this.collectionRecordStore==null){ this.collectionRecordStore = new CollectionRecordStore(); @@ -1350,11 +1200,21 @@ public class Player { return collectionRecordStore; } - public HashMap getMapMarks() { return mapMarks; } + public Map getMapMarks() { + if (this.mapMarks == null) { + this.mapMarks = new HashMap(); + } + return mapMarks; + } - public void setMapMarks(HashMap newMarks) { mapMarks = newMarks; } + public PlayerOpenStateManager getOpenStateManager() { + if (this.openStateManager == null) { + this.openStateManager = new PlayerOpenStateManager(this); + } + return openStateManager; + } - public synchronized void onTick() { + public synchronized void onTick() { // Check ping if (this.getLastPingTime() > System.currentTimeMillis() + 60000) { this.getSession().close(); @@ -1453,7 +1313,6 @@ public class Player { this.getCodex().setPlayer(this); this.getOpenStateManager().setPlayer(this); this.getTeamManager().setPlayer(this); - this.getTowerManager().setPlayer(this); } public void save() { @@ -1463,24 +1322,15 @@ public class Player { // Called from tokenrsp public void loadFromDatabase() { // Make sure these exist - if (this.getTowerManager() == null) { - this.towerManager = new TowerManager(this); - } if (this.getTeamManager() == null) { this.teamManager = new TeamManager(this); } if (this.getCodex() == null) { this.codex = new PlayerCodex(this); } - if (this.getOpenStateManager() == null) { - this.openStateManager = new PlayerOpenStateManager(this); - } if (this.getProfile().getUid() == 0) { this.getProfile().syncWithCharacter(this); } - //Make sure towerManager's player is online player - this.getTowerManager().setPlayer(this); - this.getCollectionManager().setPlayer(this); // Load from db this.getAvatars().loadFromDatabase(); @@ -1537,8 +1387,8 @@ public class Player { this.cookingManager.sendCookDataNofity(); // Unlock in case this is an existing user that reached a level before we implemented unlocking. - this.openStateManager.unlockLevelDependentStates(); - this.openStateManager.onPlayerLogin(); + this.getOpenStateManager().unlockLevelDependentStates(); + this.getOpenStateManager().onPlayerLogin(); getTodayMoonCard(); // The timer works at 0:0, some users log in after that, use this method to check if they have received a reward today or not. If not, send the reward. diff --git a/src/main/java/emu/grasscutter/game/player/PlayerOpenStateManager.java b/src/main/java/emu/grasscutter/game/player/PlayerOpenStateManager.java index 7d18f059c..8effaadac 100644 --- a/src/main/java/emu/grasscutter/game/player/PlayerOpenStateManager.java +++ b/src/main/java/emu/grasscutter/game/player/PlayerOpenStateManager.java @@ -16,9 +16,7 @@ import java.util.stream.Stream; import static emu.grasscutter.game.props.OpenState.*; @Entity -public class PlayerOpenStateManager { - @Transient private Player player; - +public class PlayerOpenStateManager extends BasePlayerDataManager { // Map of all open states that this player has. Do not put default values here. private Map map; @@ -37,11 +35,7 @@ public class PlayerOpenStateManager { .collect(Collectors.toSet()); public PlayerOpenStateManager(Player player) { - this.player = player; - } - - public void setPlayer(Player player) { - this.player = player; + super(player); } public Map getOpenStateMap() { diff --git a/src/main/java/emu/grasscutter/game/player/TeamManager.java b/src/main/java/emu/grasscutter/game/player/TeamManager.java index f969e694e..cfb1abece 100644 --- a/src/main/java/emu/grasscutter/game/player/TeamManager.java +++ b/src/main/java/emu/grasscutter/game/player/TeamManager.java @@ -41,7 +41,7 @@ import it.unimi.dsi.fastutil.ints.IntSet; import static emu.grasscutter.Configuration.*; @Entity -public class TeamManager { +public class TeamManager extends BasePlayerDataManager { @Transient private Player player; private Map teams; @@ -56,10 +56,7 @@ public class TeamManager { @Transient private final IntSet teamResonancesConfig; @Transient private int useTemporarilyTeamIndex = -1; - /** - * Temporary Team for tower - */ - @Transient private List temporaryTeam; + @Transient private List temporaryTeam; // Temporary Team for tower public TeamManager() { this.mpTeam = new TeamInfo(); @@ -71,7 +68,7 @@ public class TeamManager { public TeamManager(Player player) { this(); - this.player = player; + this.setPlayer(player); this.teams = new HashMap<>(); this.currentTeamIndex = 1; @@ -80,17 +77,9 @@ public class TeamManager { } } - public Player getPlayer() { - return player; - } - public World getWorld() { return player.getWorld(); } - - public void setPlayer(Player player) { - this.player = player; - } public Map getTeams() { return this.teams; diff --git a/src/main/java/emu/grasscutter/game/quest/QuestManager.java b/src/main/java/emu/grasscutter/game/quest/QuestManager.java index d98586991..69ae3819d 100644 --- a/src/main/java/emu/grasscutter/game/quest/QuestManager.java +++ b/src/main/java/emu/grasscutter/game/quest/QuestManager.java @@ -10,6 +10,7 @@ import emu.grasscutter.data.binout.MainQuestData; import emu.grasscutter.data.excels.QuestData; import emu.grasscutter.data.excels.QuestData.QuestCondition; import emu.grasscutter.database.DatabaseHelper; +import emu.grasscutter.game.player.BasePlayerManager; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.quest.enums.ParentQuestState; import emu.grasscutter.game.quest.enums.QuestTrigger; @@ -19,19 +20,14 @@ import emu.grasscutter.server.packet.send.*; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -public class QuestManager { - private final Player player; +public class QuestManager extends BasePlayerManager { private final Int2ObjectMap quests; public QuestManager(Player player) { - this.player = player; + super(player); this.quests = new Int2ObjectOpenHashMap<>(); } - public Player getPlayer() { - return player; - } - public Int2ObjectMap getQuests() { return quests; } diff --git a/src/main/java/emu/grasscutter/game/tower/TowerManager.java b/src/main/java/emu/grasscutter/game/tower/TowerManager.java index 07459f935..a862b1587 100644 --- a/src/main/java/emu/grasscutter/game/tower/TowerManager.java +++ b/src/main/java/emu/grasscutter/game/tower/TowerManager.java @@ -4,6 +4,7 @@ import emu.grasscutter.data.GameData; import emu.grasscutter.data.excels.TowerLevelData; import emu.grasscutter.game.dungeons.DungeonSettleListener; import emu.grasscutter.game.dungeons.TowerDungeonSettleListener; +import emu.grasscutter.game.player.BasePlayerManager; import emu.grasscutter.game.player.Player; import emu.grasscutter.server.packet.send.*; @@ -11,55 +12,54 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -public class TowerManager { - private Player player; - private TowerData towerData; +public class TowerManager extends BasePlayerManager { + public TowerManager(Player player) { - setPlayer(player); + super(player); } - public void setPlayer(Player player) { - this.player = player; - this.towerData = player.getTowerData(); + + public TowerData getTowerData() { + return getPlayer().getTowerData(); } public int getCurrentFloorId() { - return towerData.currentFloorId; + return getTowerData().currentFloorId; } public int getCurrentLevelId(){ - return towerData.currentLevelId + towerData.currentLevel; + return getTowerData().currentLevelId + getTowerData().currentLevel; } /** * form 1-3 */ public int getCurrentLevel(){ - return towerData.currentLevel + 1; + return getTowerData().currentLevel + 1; } private static final List towerDungeonSettleListener = List.of(new TowerDungeonSettleListener()); public Map getRecordMap() { - Map recordMap = towerData.recordMap; + Map recordMap = getTowerData().recordMap; if(recordMap == null || recordMap.size()==0){ recordMap = new HashMap<>(); recordMap.put(1001, new TowerLevelRecord(1001)); - towerData.recordMap = recordMap; + getTowerData().recordMap = recordMap; } return recordMap; } public void teamSelect(int floor, List> towerTeams) { var floorData = GameData.getTowerFloorDataMap().get(floor); - towerData.currentFloorId = floorData.getFloorId(); - towerData.currentLevel = 0; - towerData.currentLevelId = GameData.getTowerLevelDataMap().values().stream() + getTowerData().currentFloorId = floorData.getFloorId(); + getTowerData().currentLevel = 0; + getTowerData().currentLevelId = GameData.getTowerLevelDataMap().values().stream() .filter(x -> x.getLevelGroupId() == floorData.getLevelGroupId() && x.getLevelIndex() == 1) .findFirst() .map(TowerLevelData::getId) .orElse(0); - if (towerData.entryScene == 0){ - towerData.entryScene = player.getSceneId(); + if (getTowerData().entryScene == 0){ + getTowerData().entryScene = player.getSceneId(); } player.getTeamManager().setupTemporaryTeam(towerTeams); @@ -78,22 +78,22 @@ public class TowerManager { towerDungeonSettleListener); // make sure user can exit dungeon correctly - player.getScene().setPrevScene(towerData.entryScene); + player.getScene().setPrevScene(getTowerData().entryScene); player.getScene().setPrevScenePoint(enterPointId); - player.getSession().send(new PacketTowerEnterLevelRsp(towerData.currentFloorId, getCurrentLevel())); + player.getSession().send(new PacketTowerEnterLevelRsp(getTowerData().currentFloorId, getCurrentLevel())); // stop using skill player.getSession().send(new PacketCanUseSkillNotify(false)); // notify the cond of stars - player.getSession().send(new PacketTowerLevelStarCondNotify(towerData.currentFloorId, getCurrentLevel())); + player.getSession().send(new PacketTowerLevelStarCondNotify(getTowerData().currentFloorId, getCurrentLevel())); } public void notifyCurLevelRecordChange(){ - player.getSession().send(new PacketTowerCurLevelRecordChangeNotify(towerData.currentFloorId, getCurrentLevel())); + player.getSession().send(new PacketTowerCurLevelRecordChangeNotify(getTowerData().currentFloorId, getCurrentLevel())); } public void notifyCurLevelRecordChangeWhenDone(int stars){ Map recordMap = getRecordMap(); - int currentFloorId = towerData.currentFloorId; + int currentFloorId = getTowerData().currentFloorId; if(!recordMap.containsKey(currentFloorId)){ recordMap.put(currentFloorId, new TowerLevelRecord(currentFloorId).setLevelStars(getCurrentLevelId(),stars)); @@ -102,7 +102,7 @@ public class TowerManager { recordMap.get(currentFloorId).setLevelStars(getCurrentLevelId(),stars)); } - towerData.currentLevel++; + getTowerData().currentLevel++; if(!hasNextLevel()){ // set up the next floor @@ -113,17 +113,17 @@ public class TowerManager { } } public boolean hasNextLevel(){ - return towerData.currentLevel < 3; + return getTowerData().currentLevel < 3; } public int getNextFloorId() { - return player.getServer().getTowerScheduleManager().getNextFloorId(towerData.currentFloorId); + return player.getServer().getTowerScheduleManager().getNextFloorId(getTowerData().currentFloorId); } public boolean hasNextFloor(){ - return player.getServer().getTowerScheduleManager().getNextFloorId(towerData.currentFloorId) > 0; + return player.getServer().getTowerScheduleManager().getNextFloorId(getTowerData().currentFloorId) > 0; } public void clearEntry() { - towerData.entryScene = 0; + getTowerData().entryScene = 0; } public boolean canEnterScheduleFloor(){ diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerEnterTransPointRegionNotify.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerEnterTransPointRegionNotify.java index 9a5872033..ac1624614 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerEnterTransPointRegionNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerEnterTransPointRegionNotify.java @@ -11,6 +11,6 @@ import emu.grasscutter.server.game.GameSession; public class HandlerEnterTransPointRegionNotify extends PacketHandler { @Override public void handle(GameSession session, byte[] header, byte[] payload) throws Exception{ - session.getPlayer().getSotSManager().handleEnterTransPointRegionNotify(); + session.getPlayer().getSotsManager().handleEnterTransPointRegionNotify(); } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerExitTransPointRegionNotify.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerExitTransPointRegionNotify.java index 03fcd4e3c..6b4c1f934 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerExitTransPointRegionNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerExitTransPointRegionNotify.java @@ -12,6 +12,6 @@ import emu.grasscutter.server.game.GameSession; public class HandlerExitTransPointRegionNotify extends PacketHandler { @Override public void handle(GameSession session, byte[] header, byte[] payload) throws Exception{ - session.getPlayer().getSotSManager().handleExitTransPointRegionNotify(); + session.getPlayer().getSotsManager().handleExitTransPointRegionNotify(); } } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketHomeBasicInfoNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketHomeBasicInfoNotify.java index 846069f5e..a55091f32 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketHomeBasicInfoNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketHomeBasicInfoNotify.java @@ -13,7 +13,7 @@ public class PacketHomeBasicInfoNotify extends BasePacket { public PacketHomeBasicInfoNotify(Player player, boolean editMode) { super(PacketOpcodes.HomeBasicInfoNotify); - if(player.getCurrentRealmId() == null){ + if (player.getCurrentRealmId() <= 0) { return; } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketMarkMapRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketMarkMapRsp.java index 337e28e0b..f904e3892 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketMarkMapRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketMarkMapRsp.java @@ -10,7 +10,7 @@ import java.util.*; public class PacketMarkMapRsp extends BasePacket { - public PacketMarkMapRsp(HashMap mapMarks) { + public PacketMarkMapRsp(Map mapMarks) { super(PacketOpcodes.MarkMapRsp); MarkMapRspOuterClass.MarkMapRsp.Builder proto = MarkMapRspOuterClass.MarkMapRsp.newBuilder(); From 2e19e70fe1e61d74b1f7dd4645eed124efb67bda Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Mon, 18 Jul 2022 22:47:38 -0700 Subject: [PATCH 25/61] Refactor game server managers to systems --- .../command/commands/AnnounceCommand.java | 2 +- .../command/commands/CoopCommand.java | 6 +- .../command/commands/EnterDungeonCommand.java | 2 +- .../command/commands/ReloadCommand.java | 6 +- .../command/commands/SetPropCommand.java | 2 +- .../game/battlepass/BattlePassManager.java | 4 +- ...sionManager.java => BattlePassSystem.java} | 9 +- .../game/combine/CombineManger.java | 12 +- .../{DropManager.java => DropSystem.java} | 21 +-- ...DungeonManager.java => DungeonSystem.java} | 13 +- .../game/entity/gadget/GadgetChest.java | 2 +- .../chest/BossChestInteractHandler.java | 2 +- ...tionManager.java => ExpeditionSystem.java} | 19 +-- .../{GachaManager.java => GachaSystem.java} | 12 +- .../grasscutter/game/inventory/Inventory.java | 4 +- ...ntManager.java => AnnouncementSystem.java} | 17 +- ...ntoryManager.java => InventorySystem.java} | 19 +-- ...yerManager.java => MultiplayerSystem.java} | 12 +- .../emu/grasscutter/game/player/Player.java | 2 +- .../emu/grasscutter/game/quest/GameQuest.java | 6 +- .../grasscutter/game/quest/QuestManager.java | 2 +- ...rverQuestHandler.java => QuestSystem.java} | 9 +- .../{ShopManager.java => ShopSystem.java} | 37 ++--- .../grasscutter/game/tower/TowerManager.java | 10 +- ...rScheduleManager.java => TowerSystem.java} | 14 +- .../emu/grasscutter/game/world/Scene.java | 2 +- ...dDataManager.java => WorldDataSystem.java} | 8 +- .../server/game/BaseGameSystem.java | 13 ++ .../grasscutter/server/game/GameServer.java | 155 +++++++++--------- .../server/http/handlers/GachaHandler.java | 4 +- .../HandlerAvatarExpeditionGetRewardReq.java | 4 +- .../packet/recv/HandlerAvatarPromoteReq.java | 2 +- .../recv/HandlerAvatarSkillUpgradeReq.java | 2 +- .../packet/recv/HandlerAvatarUpgradeReq.java | 2 +- .../packet/recv/HandlerBuyGoodsReq.java | 8 +- ...andlerCalcWeaponUpgradeReturnItemsReq.java | 2 +- .../server/packet/recv/HandlerCombineReq.java | 2 +- .../recv/HandlerDestroyMaterialReq.java | 2 +- .../server/packet/recv/HandlerDoGachaReq.java | 2 +- .../recv/HandlerDungeonEntryInfoReq.java | 2 +- .../packet/recv/HandlerGachaWishReq.java | 2 +- .../packet/recv/HandlerGetGachaInfoReq.java | 2 +- .../HandlerGetInvestigationMonsterReq.java | 2 +- .../recv/HandlerPlayerApplyEnterMpReq.java | 2 +- .../HandlerPlayerApplyEnterMpResultReq.java | 2 +- .../recv/HandlerPlayerEnterDungeonReq.java | 2 +- .../HandlerPlayerGetForceQuitBanInfoReq.java | 2 +- .../recv/HandlerPlayerQuitDungeonReq.java | 2 +- .../recv/HandlerReliquaryDecomposeReq.java | 2 +- .../recv/HandlerReliquaryUpgradeReq.java | 2 +- .../recv/HandlerSceneKickPlayerReq.java | 2 +- .../recv/HandlerSetEquipLockStateReq.java | 2 +- .../packet/recv/HandlerTowerAllDataReq.java | 2 +- .../recv/HandlerUnlockAvatarTalentReq.java | 2 +- .../server/packet/recv/HandlerUseItemReq.java | 2 +- .../packet/recv/HandlerWeaponAwakenReq.java | 2 +- .../packet/recv/HandlerWeaponPromoteReq.java | 2 +- .../packet/recv/HandlerWeaponUpgradeReq.java | 2 +- .../packet/send/PacketGetGachaInfoRsp.java | 4 +- .../PacketGetInvestigationMonsterRsp.java | 4 +- .../server/packet/send/PacketGetShopRsp.java | 6 +- .../packet/send/PacketTowerAllDataRsp.java | 4 +- .../task/tasks/AnnouncementTask.java | 10 +- 63 files changed, 254 insertions(+), 264 deletions(-) rename src/main/java/emu/grasscutter/game/battlepass/{BattlePassMissionManager.java => BattlePassSystem.java} (93%) rename src/main/java/emu/grasscutter/game/drop/{DropManager.java => DropSystem.java} (95%) rename src/main/java/emu/grasscutter/game/dungeons/{DungeonManager.java => DungeonSystem.java} (95%) rename src/main/java/emu/grasscutter/game/expedition/{ExpeditionManager.java => ExpeditionSystem.java} (85%) rename src/main/java/emu/grasscutter/game/gacha/{GachaManager.java => GachaSystem.java} (98%) rename src/main/java/emu/grasscutter/game/managers/{AnnouncementManager.java => AnnouncementSystem.java} (90%) rename src/main/java/emu/grasscutter/game/managers/{InventoryManager.java => InventorySystem.java} (98%) rename src/main/java/emu/grasscutter/game/managers/{MultiplayerManager.java => MultiplayerSystem.java} (96%) rename src/main/java/emu/grasscutter/game/quest/{ServerQuestHandler.java => QuestSystem.java} (93%) rename src/main/java/emu/grasscutter/game/shop/{ShopManager.java => ShopSystem.java} (90%) rename src/main/java/emu/grasscutter/game/tower/{TowerScheduleManager.java => TowerSystem.java} (92%) rename src/main/java/emu/grasscutter/game/world/{WorldDataManager.java => WorldDataSystem.java} (97%) create mode 100644 src/main/java/emu/grasscutter/server/game/BaseGameSystem.java diff --git a/src/main/java/emu/grasscutter/command/commands/AnnounceCommand.java b/src/main/java/emu/grasscutter/command/commands/AnnounceCommand.java index 7f8ed3680..455e79453 100644 --- a/src/main/java/emu/grasscutter/command/commands/AnnounceCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/AnnounceCommand.java @@ -22,7 +22,7 @@ public final class AnnounceCommand implements CommandHandler { @Override public void execute(Player sender, Player targetPlayer, List args) { - var manager = Grasscutter.getGameServer().getAnnouncementManager(); + var manager = Grasscutter.getGameServer().getAnnouncementSystem(); if (args.size() < 1) { CommandHandler.sendTranslatedMessage(sender, "commands.announce.command_usage"); return; diff --git a/src/main/java/emu/grasscutter/command/commands/CoopCommand.java b/src/main/java/emu/grasscutter/command/commands/CoopCommand.java index 86de192bc..8c1479718 100644 --- a/src/main/java/emu/grasscutter/command/commands/CoopCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/CoopCommand.java @@ -41,10 +41,10 @@ public final class CoopCommand implements CommandHandler { // There's no target==host check but this just places them in multiplayer in their own world which seems fine. if (targetPlayer.isInMultiplayer()) { - targetPlayer.getServer().getMultiplayerManager().leaveCoop(targetPlayer); + targetPlayer.getServer().getMultiplayerSystem().leaveCoop(targetPlayer); } - host.getServer().getMultiplayerManager().applyEnterMp(targetPlayer, host.getUid()); - targetPlayer.getServer().getMultiplayerManager().applyEnterMpReply(host, targetPlayer.getUid(), true); + host.getServer().getMultiplayerSystem().applyEnterMp(targetPlayer, host.getUid()); + targetPlayer.getServer().getMultiplayerSystem().applyEnterMpReply(host, targetPlayer.getUid(), true); CommandHandler.sendMessage(sender, translate(sender, "commands.coop.success", targetPlayer.getNickname(), host.getNickname())); } } diff --git a/src/main/java/emu/grasscutter/command/commands/EnterDungeonCommand.java b/src/main/java/emu/grasscutter/command/commands/EnterDungeonCommand.java index b2d21a1b1..94de4a294 100644 --- a/src/main/java/emu/grasscutter/command/commands/EnterDungeonCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/EnterDungeonCommand.java @@ -25,7 +25,7 @@ public final class EnterDungeonCommand implements CommandHandler { return; } - boolean result = targetPlayer.getServer().getDungeonManager().enterDungeon(targetPlayer.getSession().getPlayer(), 0, dungeonId); + boolean result = targetPlayer.getServer().getDungeonSystem().enterDungeon(targetPlayer.getSession().getPlayer(), 0, dungeonId); if (!result) { CommandHandler.sendMessage(sender, translate(sender, "commands.enter_dungeon.not_found_error")); diff --git a/src/main/java/emu/grasscutter/command/commands/ReloadCommand.java b/src/main/java/emu/grasscutter/command/commands/ReloadCommand.java index d18567f9b..0d052da3b 100644 --- a/src/main/java/emu/grasscutter/command/commands/ReloadCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/ReloadCommand.java @@ -18,9 +18,9 @@ public final class ReloadCommand implements CommandHandler { Grasscutter.loadConfig(); Grasscutter.loadLanguage(); - Grasscutter.getGameServer().getGachaManager().load(); - Grasscutter.getGameServer().getDropManager().load(); - Grasscutter.getGameServer().getShopManager().load(); + Grasscutter.getGameServer().getGachaSystem().load(); + Grasscutter.getGameServer().getDropSystem().load(); + Grasscutter.getGameServer().getShopSystem().load(); CommandHandler.sendMessage(sender, translate(sender, "commands.reload.reload_done")); } diff --git a/src/main/java/emu/grasscutter/command/commands/SetPropCommand.java b/src/main/java/emu/grasscutter/command/commands/SetPropCommand.java index 2248d2b1a..122eb782e 100644 --- a/src/main/java/emu/grasscutter/command/commands/SetPropCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/SetPropCommand.java @@ -146,7 +146,7 @@ public final class SetPropCommand implements CommandHandler { } private boolean setTowerLevel(Player sender, Player targetPlayer, int topFloor) { - List floorIds = targetPlayer.getServer().getTowerScheduleManager().getAllFloors(); + List floorIds = targetPlayer.getServer().getTowerSystem().getAllFloors(); if (topFloor < 0 || topFloor > floorIds.size()) { String min = Integer.toString(0); String max = Integer.toString(floorIds.size()); diff --git a/src/main/java/emu/grasscutter/game/battlepass/BattlePassManager.java b/src/main/java/emu/grasscutter/game/battlepass/BattlePassManager.java index 2f74819f1..6c95db479 100644 --- a/src/main/java/emu/grasscutter/game/battlepass/BattlePassManager.java +++ b/src/main/java/emu/grasscutter/game/battlepass/BattlePassManager.java @@ -140,11 +140,11 @@ public class BattlePassManager extends BasePlayerDataManager { // Mission triggers public void triggerMission(WatcherTriggerType triggerType) { - getPlayer().getServer().getBattlePassMissionManager().triggerMission(getPlayer(), triggerType); + getPlayer().getServer().getBattlePassSystem().triggerMission(getPlayer(), triggerType); } public void triggerMission(WatcherTriggerType triggerType, int param, int progress) { - getPlayer().getServer().getBattlePassMissionManager().triggerMission(getPlayer(), triggerType, param, progress); + getPlayer().getServer().getBattlePassSystem().triggerMission(getPlayer(), triggerType, param, progress); } // Handlers diff --git a/src/main/java/emu/grasscutter/game/battlepass/BattlePassMissionManager.java b/src/main/java/emu/grasscutter/game/battlepass/BattlePassSystem.java similarity index 93% rename from src/main/java/emu/grasscutter/game/battlepass/BattlePassMissionManager.java rename to src/main/java/emu/grasscutter/game/battlepass/BattlePassSystem.java index d45c4d978..240bcb473 100644 --- a/src/main/java/emu/grasscutter/game/battlepass/BattlePassMissionManager.java +++ b/src/main/java/emu/grasscutter/game/battlepass/BattlePassSystem.java @@ -11,16 +11,17 @@ import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.BattlePassMissionRefreshType; import emu.grasscutter.game.props.BattlePassMissionStatus; import emu.grasscutter.game.props.WatcherTriggerType; +import emu.grasscutter.server.game.BaseGameSystem; import emu.grasscutter.server.game.GameServer; import emu.grasscutter.server.packet.send.PacketBattlePassMissionUpdateNotify; -public class BattlePassMissionManager { - private final GameServer server; +public class BattlePassSystem extends BaseGameSystem { private final Map> cachedTriggers; // BP Mission manager for the server, contains cached triggers so we dont have to load it for each player - public BattlePassMissionManager(GameServer server) { - this.server = server; + public BattlePassSystem(GameServer server) { + super(server); + this.cachedTriggers = new HashMap<>(); for (BattlePassMissionData missionData : GameData.getBattlePassMissionDataMap().values()) { diff --git a/src/main/java/emu/grasscutter/game/combine/CombineManger.java b/src/main/java/emu/grasscutter/game/combine/CombineManger.java index dbe179c43..555440a85 100644 --- a/src/main/java/emu/grasscutter/game/combine/CombineManger.java +++ b/src/main/java/emu/grasscutter/game/combine/CombineManger.java @@ -12,6 +12,7 @@ import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.ActionReason; import emu.grasscutter.net.proto.RetcodeOuterClass; import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode; +import emu.grasscutter.server.game.BaseGameSystem; import emu.grasscutter.server.game.GameServer; import emu.grasscutter.server.packet.send.PacketCombineFormulaDataNotify; import emu.grasscutter.server.packet.send.PacketCombineRsp; @@ -29,16 +30,11 @@ import java.util.List; import com.google.gson.reflect.TypeToken; -public class CombineManger { - private final GameServer gameServer; +public class CombineManger extends BaseGameSystem { private final static Int2ObjectMap> reliquaryDecomposeData = new Int2ObjectOpenHashMap<>(); - public GameServer getGameServer() { - return gameServer; - } - - public CombineManger(GameServer gameServer) { - this.gameServer = gameServer; + public CombineManger(GameServer server) { + super(server); } public static void initialize() { diff --git a/src/main/java/emu/grasscutter/game/drop/DropManager.java b/src/main/java/emu/grasscutter/game/drop/DropSystem.java similarity index 95% rename from src/main/java/emu/grasscutter/game/drop/DropManager.java rename to src/main/java/emu/grasscutter/game/drop/DropSystem.java index a19e0b28b..4e94bfe98 100644 --- a/src/main/java/emu/grasscutter/game/drop/DropManager.java +++ b/src/main/java/emu/grasscutter/game/drop/DropSystem.java @@ -12,6 +12,7 @@ import emu.grasscutter.game.inventory.ItemType; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.ActionReason; import emu.grasscutter.game.world.Scene; +import emu.grasscutter.server.game.BaseGameSystem; import emu.grasscutter.server.game.GameServer; import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Utils; @@ -23,24 +24,18 @@ import java.io.Reader; import java.util.Collection; import java.util.List; -public class DropManager { - public GameServer getGameServer() { - return gameServer; - } - - private final GameServer gameServer; - - public Int2ObjectMap> getDropData() { - return dropData; - } - +public class DropSystem extends BaseGameSystem { private final Int2ObjectMap> dropData; - public DropManager(GameServer gameServer) { - this.gameServer = gameServer; + public DropSystem(GameServer server) { + super(server); this.dropData = new Int2ObjectOpenHashMap<>(); this.load(); } + + public Int2ObjectMap> getDropData() { + return dropData; + } public synchronized void load() { try (Reader fileReader = new InputStreamReader(DataLoader.load("Drop.json"))) { diff --git a/src/main/java/emu/grasscutter/game/dungeons/DungeonManager.java b/src/main/java/emu/grasscutter/game/dungeons/DungeonSystem.java similarity index 95% rename from src/main/java/emu/grasscutter/game/dungeons/DungeonManager.java rename to src/main/java/emu/grasscutter/game/dungeons/DungeonSystem.java index 011b233a3..7ed773baa 100644 --- a/src/main/java/emu/grasscutter/game/dungeons/DungeonManager.java +++ b/src/main/java/emu/grasscutter/game/dungeons/DungeonSystem.java @@ -11,6 +11,7 @@ import emu.grasscutter.game.quest.enums.QuestTrigger; import emu.grasscutter.game.world.Scene; import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.PacketOpcodes; +import emu.grasscutter.server.game.BaseGameSystem; import emu.grasscutter.server.game.GameServer; import emu.grasscutter.server.packet.send.PacketDungeonEntryInfoRsp; import emu.grasscutter.server.packet.send.PacketPlayerEnterDungeonRsp; @@ -18,15 +19,11 @@ import emu.grasscutter.utils.Position; import java.util.List; -public class DungeonManager { - private final GameServer server; +public class DungeonSystem extends BaseGameSystem { private static final BasicDungeonSettleListener basicDungeonSettleObserver = new BasicDungeonSettleListener(); - public DungeonManager(GameServer server) { - this.server = server; - } - - public GameServer getServer() { - return server; + + public DungeonSystem(GameServer server) { + super(server); } public void getEntryInfo(Player player, int pointId) { diff --git a/src/main/java/emu/grasscutter/game/entity/gadget/GadgetChest.java b/src/main/java/emu/grasscutter/game/entity/gadget/GadgetChest.java index 371919b27..02da258fc 100644 --- a/src/main/java/emu/grasscutter/game/entity/gadget/GadgetChest.java +++ b/src/main/java/emu/grasscutter/game/entity/gadget/GadgetChest.java @@ -19,7 +19,7 @@ public class GadgetChest extends GadgetContent { } public boolean onInteract(Player player, GadgetInteractReq req) { - var chestInteractHandlerMap = getGadget().getScene().getWorld().getServer().getWorldDataManager().getChestInteractHandlerMap(); + var chestInteractHandlerMap = getGadget().getScene().getWorld().getServer().getWorldDataSystem().getChestInteractHandlerMap(); var handler = chestInteractHandlerMap.get(getGadget().getGadgetData().getJsonName()); if(handler == null){ Grasscutter.getLogger().warn("Could not found the handler of this type of Chests {}", getGadget().getGadgetData().getJsonName()); diff --git a/src/main/java/emu/grasscutter/game/entity/gadget/chest/BossChestInteractHandler.java b/src/main/java/emu/grasscutter/game/entity/gadget/chest/BossChestInteractHandler.java index 491bfd9bd..3bc62f4f9 100644 --- a/src/main/java/emu/grasscutter/game/entity/gadget/chest/BossChestInteractHandler.java +++ b/src/main/java/emu/grasscutter/game/entity/gadget/chest/BossChestInteractHandler.java @@ -19,7 +19,7 @@ public class BossChestInteractHandler implements ChestInteractHandler{ @Override public boolean onInteract(GadgetChest chest, Player player) { - var worldDataManager = chest.getGadget().getScene().getWorld().getServer().getWorldDataManager(); + var worldDataManager = chest.getGadget().getScene().getWorld().getServer().getWorldDataSystem(); var monster = chest.getGadget().getMetaGadget().group.monsters.get(chest.getGadget().getMetaGadget().boss_chest.monster_config_id); var reward = worldDataManager.getRewardByBossId(monster.monster_id); diff --git a/src/main/java/emu/grasscutter/game/expedition/ExpeditionManager.java b/src/main/java/emu/grasscutter/game/expedition/ExpeditionSystem.java similarity index 85% rename from src/main/java/emu/grasscutter/game/expedition/ExpeditionManager.java rename to src/main/java/emu/grasscutter/game/expedition/ExpeditionSystem.java index 9b129259e..9dba624a6 100644 --- a/src/main/java/emu/grasscutter/game/expedition/ExpeditionManager.java +++ b/src/main/java/emu/grasscutter/game/expedition/ExpeditionSystem.java @@ -3,6 +3,7 @@ package emu.grasscutter.game.expedition; import com.google.gson.reflect.TypeToken; import emu.grasscutter.Grasscutter; import emu.grasscutter.data.DataLoader; +import emu.grasscutter.server.game.BaseGameSystem; import emu.grasscutter.server.game.GameServer; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; @@ -15,22 +16,18 @@ import java.util.List; import static emu.grasscutter.Configuration.*; -public class ExpeditionManager { - public GameServer getGameServer() { - return gameServer; - } - - private final GameServer gameServer; - - public Int2ObjectMap> getExpeditionRewardDataList() { return expeditionRewardData; } - +public class ExpeditionSystem extends BaseGameSystem { private final Int2ObjectMap> expeditionRewardData; - public ExpeditionManager(GameServer gameServer) { - this.gameServer = gameServer; + public ExpeditionSystem(GameServer server) { + super(server); this.expeditionRewardData = new Int2ObjectOpenHashMap<>(); this.load(); } + + public Int2ObjectMap> getExpeditionRewardDataList() { + return expeditionRewardData; + } public synchronized void load() { try (Reader fileReader = new InputStreamReader(DataLoader.load("ExpeditionReward.json"))) { diff --git a/src/main/java/emu/grasscutter/game/gacha/GachaManager.java b/src/main/java/emu/grasscutter/game/gacha/GachaSystem.java similarity index 98% rename from src/main/java/emu/grasscutter/game/gacha/GachaManager.java rename to src/main/java/emu/grasscutter/game/gacha/GachaSystem.java index 661bfca5e..6365561eb 100644 --- a/src/main/java/emu/grasscutter/game/gacha/GachaManager.java +++ b/src/main/java/emu/grasscutter/game/gacha/GachaSystem.java @@ -33,6 +33,7 @@ import emu.grasscutter.net.proto.GachaTransferItemOuterClass.GachaTransferItem; import emu.grasscutter.net.proto.GetGachaInfoRspOuterClass.GetGachaInfoRsp; import emu.grasscutter.net.proto.ItemParamOuterClass.ItemParam; import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode; +import emu.grasscutter.server.game.BaseGameSystem; import emu.grasscutter.server.game.GameServer; import emu.grasscutter.server.game.GameServerTickEvent; import emu.grasscutter.server.packet.send.PacketDoGachaRsp; @@ -46,8 +47,7 @@ import org.greenrobot.eventbus.Subscribe; import static emu.grasscutter.Configuration.*; -public class GachaManager { - private final GameServer server; +public class GachaSystem extends BaseGameSystem { private final Int2ObjectMap gachaBanners; private WatchService watchService; @@ -56,17 +56,13 @@ public class GachaManager { private int[] fallbackItems4Pool2Default = {11401, 11402, 11403, 11405, 12401, 12402, 12403, 12405, 13401, 13407, 14401, 14402, 14403, 14409, 15401, 15402, 15403, 15405}; private int[] fallbackItems5Pool2Default = {11501, 11502, 12501, 12502, 13502, 13505, 14501, 14502, 15501, 15502}; - public GachaManager(GameServer server) { - this.server = server; + public GachaSystem(GameServer server) { + super(server); this.gachaBanners = new Int2ObjectOpenHashMap<>(); this.load(); this.startWatcher(server); } - public GameServer getServer() { - return server; - } - public Int2ObjectMap getGachaBanners() { return gachaBanners; } diff --git a/src/main/java/emu/grasscutter/game/inventory/Inventory.java b/src/main/java/emu/grasscutter/game/inventory/Inventory.java index f5660a955..15eb9710d 100644 --- a/src/main/java/emu/grasscutter/game/inventory/Inventory.java +++ b/src/main/java/emu/grasscutter/game/inventory/Inventory.java @@ -260,11 +260,11 @@ public class Inventory extends BasePlayerManager implements Iterable { private void addVirtualItem(int itemId, int count) { switch (itemId) { case 101 -> // Character exp - this.player.getServer().getInventoryManager().upgradeAvatar(this.player, this.player.getTeamManager().getCurrentAvatarEntity().getAvatar(), count); + this.player.getServer().getInventorySystem().upgradeAvatar(this.player, this.player.getTeamManager().getCurrentAvatarEntity().getAvatar(), count); case 102 -> // Adventure exp this.player.addExpDirectly(count); case 105 -> // Companionship exp - this.player.getServer().getInventoryManager().upgradeAvatarFetterLevel(this.player, this.player.getTeamManager().getCurrentAvatarEntity().getAvatar(), count); + this.player.getServer().getInventorySystem().upgradeAvatarFetterLevel(this.player, this.player.getTeamManager().getCurrentAvatarEntity().getAvatar(), count); case 106 -> // Resin this.player.getResinManager().addResin(count); case 107 -> // Legendary Key diff --git a/src/main/java/emu/grasscutter/game/managers/AnnouncementManager.java b/src/main/java/emu/grasscutter/game/managers/AnnouncementSystem.java similarity index 90% rename from src/main/java/emu/grasscutter/game/managers/AnnouncementManager.java rename to src/main/java/emu/grasscutter/game/managers/AnnouncementSystem.java index 163d0f5d7..201079fa3 100644 --- a/src/main/java/emu/grasscutter/game/managers/AnnouncementManager.java +++ b/src/main/java/emu/grasscutter/game/managers/AnnouncementSystem.java @@ -6,6 +6,7 @@ import emu.grasscutter.data.DataLoader; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.world.World; import emu.grasscutter.net.proto.AnnounceDataOuterClass; +import emu.grasscutter.server.game.BaseGameSystem; import emu.grasscutter.server.game.GameServer; import emu.grasscutter.server.packet.send.PacketServerAnnounceNotify; import emu.grasscutter.server.packet.send.PacketServerAnnounceRevokeNotify; @@ -19,24 +20,22 @@ import java.io.InputStreamReader; import java.util.*; @Getter -public class AnnouncementManager { - - public final GameServer server; - public AnnouncementManager(GameServer server){ - this.server = server; +public class AnnouncementSystem extends BaseGameSystem { + private final Map announceConfigItemMap; + + public AnnouncementSystem(GameServer server){ + super(server); + this.announceConfigItemMap = new HashMap<>(); loadConfig(); } - Map announceConfigItemMap = new HashMap<>(); private int loadConfig() { try (var fileReader = new InputStreamReader(DataLoader.load("Announcement.json"))) { List announceConfigItems = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(List.class, AnnounceConfigItem.class).getType()); - announceConfigItemMap = new HashMap<>(); + announceConfigItemMap.clear(); announceConfigItems.forEach(i -> announceConfigItemMap.put(i.getTemplateId(), i)); - - } catch (Exception e) { Grasscutter.getLogger().error("Unable to load server announce config.", e); } diff --git a/src/main/java/emu/grasscutter/game/managers/InventoryManager.java b/src/main/java/emu/grasscutter/game/managers/InventorySystem.java similarity index 98% rename from src/main/java/emu/grasscutter/game/managers/InventoryManager.java rename to src/main/java/emu/grasscutter/game/managers/InventorySystem.java index 01224ea37..bf38f64cb 100644 --- a/src/main/java/emu/grasscutter/game/managers/InventoryManager.java +++ b/src/main/java/emu/grasscutter/game/managers/InventorySystem.java @@ -27,15 +27,14 @@ import emu.grasscutter.game.shop.ShopChestBatchUseTable; import emu.grasscutter.game.shop.ShopChestTable; import emu.grasscutter.net.proto.ItemParamOuterClass.ItemParam; import emu.grasscutter.net.proto.MaterialInfoOuterClass.MaterialInfo; +import emu.grasscutter.server.game.BaseGameSystem; import emu.grasscutter.server.game.GameServer; import emu.grasscutter.server.packet.send.*; import emu.grasscutter.utils.Utils; import it.unimi.dsi.fastutil.ints.Int2IntMap; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; -public class InventoryManager { - private final GameServer server; - +public class InventorySystem extends BaseGameSystem { private final static int RELIC_MATERIAL_1 = 105002; // Sanctifying Unction private final static int RELIC_MATERIAL_2 = 105003; // Sanctifying Essence private final static int RELIC_MATERIAL_EXP_1 = 2500; // Sanctifying Unction @@ -55,12 +54,8 @@ public class InventoryManager { private final static int AVATAR_BOOK_EXP_2 = 5000; // Adventurer's Experience private final static int AVATAR_BOOK_EXP_3 = 20000; // Hero's Wit - public InventoryManager(GameServer server) { - this.server = server; - } - - public GameServer getServer() { - return server; + public InventorySystem(GameServer server) { + super(server); } public void lockEquip(Player player, long targetEquipGuid, boolean isLocked) { @@ -850,7 +845,7 @@ public class InventoryManager { // Handle combine diagrams. if (useItem.getItemData().getItemUse().get(0).getUseOp().equals("ITEM_USE_UNLOCK_COMBINE")) { // Unlock. - useSuccess = player.getServer().getCombineManger().unlockCombineDiagram(player, useItem); + useSuccess = player.getServer().getCombineSystem().unlockCombineDiagram(player, useItem); } // Handle cooking recipies. if (useItem.getItemData().getItemUse().get(0).getUseOp().equals("ITEM_USE_UNLOCK_COOK_RECIPE")) { @@ -883,7 +878,7 @@ public class InventoryManager { } break; case MATERIAL_CHEST: - List shopChestTableList = player.getServer().getShopManager().getShopChestData(); + List shopChestTableList = player.getServer().getShopSystem().getShopChestData(); List rewardItemList = new ArrayList<>(); for (ShopChestTable shopChestTable : shopChestTableList) { if (shopChestTable.getItemId() != useItem.getItemId()) { @@ -914,7 +909,7 @@ public class InventoryManager { if (optionId < 1) { break; } - List shopChestBatchUseTableList = player.getServer().getShopManager().getShopChestBatchUseData(); + List shopChestBatchUseTableList = player.getServer().getShopSystem().getShopChestBatchUseData(); for (ShopChestBatchUseTable shopChestBatchUseTable : shopChestBatchUseTableList) { if (shopChestBatchUseTable.getItemId() != useItem.getItemId()) { continue; diff --git a/src/main/java/emu/grasscutter/game/managers/MultiplayerManager.java b/src/main/java/emu/grasscutter/game/managers/MultiplayerSystem.java similarity index 96% rename from src/main/java/emu/grasscutter/game/managers/MultiplayerManager.java rename to src/main/java/emu/grasscutter/game/managers/MultiplayerSystem.java index 91566ef20..053121f66 100644 --- a/src/main/java/emu/grasscutter/game/managers/MultiplayerManager.java +++ b/src/main/java/emu/grasscutter/game/managers/MultiplayerSystem.java @@ -8,20 +8,16 @@ import emu.grasscutter.net.proto.PlayerApplyEnterMpReasonOuterClass.PlayerApplyE import emu.grasscutter.game.player.Player; import emu.grasscutter.game.player.Player.SceneLoadState; import emu.grasscutter.net.proto.PlayerApplyEnterMpResultNotifyOuterClass; +import emu.grasscutter.server.game.BaseGameSystem; import emu.grasscutter.server.game.GameServer; import emu.grasscutter.server.packet.send.PacketPlayerApplyEnterMpNotify; import emu.grasscutter.server.packet.send.PacketPlayerApplyEnterMpResultNotify; import emu.grasscutter.server.packet.send.PacketPlayerEnterSceneNotify; -public class MultiplayerManager { - private final GameServer server; - - public MultiplayerManager(GameServer server) { - this.server = server; - } +public class MultiplayerSystem extends BaseGameSystem { - public GameServer getServer() { - return server; + public MultiplayerSystem(GameServer server) { + super(server); } public void applyEnterMp(Player player, int targetUid) { diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index e287fcb1e..bfc090b93 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -1436,7 +1436,7 @@ public class Player { getStaminaManager().stopSustainedStaminaHandler(); // force to leave the dungeon (inside has a "if") - this.getServer().getDungeonManager().exitDungeon(this); + this.getServer().getDungeonSystem().exitDungeon(this); // Leave world if (this.getWorld() != null) { diff --git a/src/main/java/emu/grasscutter/game/quest/GameQuest.java b/src/main/java/emu/grasscutter/game/quest/GameQuest.java index 7d1fe5ade..87e31a6fb 100644 --- a/src/main/java/emu/grasscutter/game/quest/GameQuest.java +++ b/src/main/java/emu/grasscutter/game/quest/GameQuest.java @@ -58,7 +58,7 @@ public class GameQuest { this.mainQuest.getChildQuests().put(this.questId, this); - this.getData().getBeginExec().forEach(e -> getOwner().getServer().getQuestHandler().triggerExec(this, e, e.getParam())); + this.getData().getBeginExec().forEach(e -> getOwner().getServer().getQuestSystem().triggerExec(this, e, e.getParam())); this.getOwner().getQuestManager().triggerEvent(QuestTrigger.QUEST_CONTENT_QUEST_STATE_EQUAL, this.questId, this.state.getValue()); @@ -171,7 +171,7 @@ public class GameQuest { this.save(); } - this.getData().getFinishExec().forEach(e -> getOwner().getServer().getQuestHandler().triggerExec(this, e, e.getParam())); + this.getData().getFinishExec().forEach(e -> getOwner().getServer().getQuestSystem().triggerExec(this, e, e.getParam())); this.getOwner().getQuestManager().triggerEvent(QuestTrigger.QUEST_CONTENT_QUEST_STATE_EQUAL, this.questId, this.state.getValue()); @@ -205,7 +205,7 @@ public class GameQuest { // TODO for (int i = 0; i < questData.getAcceptCond().size(); i++) { QuestCondition condition = questData.getAcceptCond().get(i); - boolean result = getOwner().getServer().getQuestHandler().triggerCondition(this, condition, + boolean result = getOwner().getServer().getQuestSystem().triggerCondition(this, condition, condition.getParamStr(), condition.getParam()); diff --git a/src/main/java/emu/grasscutter/game/quest/QuestManager.java b/src/main/java/emu/grasscutter/game/quest/QuestManager.java index 69ae3819d..28a17973f 100644 --- a/src/main/java/emu/grasscutter/game/quest/QuestManager.java +++ b/src/main/java/emu/grasscutter/game/quest/QuestManager.java @@ -153,7 +153,7 @@ public class QuestManager extends BasePlayerManager { continue; } - boolean result = getPlayer().getServer().getQuestHandler().triggerContent(quest, condition, paramStr, params); + boolean result = getPlayer().getServer().getQuestSystem().triggerContent(quest, condition, paramStr, params); if (result) { quest.getFinishProgressList()[i] = 1; diff --git a/src/main/java/emu/grasscutter/game/quest/ServerQuestHandler.java b/src/main/java/emu/grasscutter/game/quest/QuestSystem.java similarity index 93% rename from src/main/java/emu/grasscutter/game/quest/ServerQuestHandler.java rename to src/main/java/emu/grasscutter/game/quest/QuestSystem.java index 19c779470..24f78b9d4 100644 --- a/src/main/java/emu/grasscutter/game/quest/ServerQuestHandler.java +++ b/src/main/java/emu/grasscutter/game/quest/QuestSystem.java @@ -4,6 +4,9 @@ import java.util.Set; import emu.grasscutter.data.excels.QuestData; import emu.grasscutter.game.quest.handlers.QuestExecHandler; +import emu.grasscutter.server.game.BaseGameSystem; +import emu.grasscutter.server.game.GameServer; + import org.reflections.Reflections; import emu.grasscutter.Grasscutter; @@ -13,12 +16,14 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; @SuppressWarnings("unchecked") -public class ServerQuestHandler { +public class QuestSystem extends BaseGameSystem { private final Int2ObjectMap condHandlers; private final Int2ObjectMap contHandlers; private final Int2ObjectMap execHandlers; - public ServerQuestHandler() { + public QuestSystem(GameServer server) { + super(server); + this.condHandlers = new Int2ObjectOpenHashMap<>(); this.contHandlers = new Int2ObjectOpenHashMap<>(); this.execHandlers = new Int2ObjectOpenHashMap<>(); diff --git a/src/main/java/emu/grasscutter/game/shop/ShopManager.java b/src/main/java/emu/grasscutter/game/shop/ShopSystem.java similarity index 90% rename from src/main/java/emu/grasscutter/game/shop/ShopManager.java rename to src/main/java/emu/grasscutter/game/shop/ShopSystem.java index 6fb138be8..d6afb07ab 100644 --- a/src/main/java/emu/grasscutter/game/shop/ShopManager.java +++ b/src/main/java/emu/grasscutter/game/shop/ShopSystem.java @@ -6,6 +6,7 @@ import emu.grasscutter.data.DataLoader; import emu.grasscutter.data.GameData; import emu.grasscutter.data.common.ItemParamData; import emu.grasscutter.data.excels.ShopGoodsData; +import emu.grasscutter.server.game.BaseGameSystem; import emu.grasscutter.server.game.GameServer; import emu.grasscutter.utils.Utils; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; @@ -21,35 +22,33 @@ import java.util.List; import static emu.grasscutter.Configuration.*; -public class ShopManager { - private final GameServer server; - - public Int2ObjectMap> getShopData() { - return shopData; - } - - public List getShopChestData() { - return shopChestData; - } - - public List getShopChestBatchUseData() { - return shopChestBatchUseData; - } - +public class ShopSystem extends BaseGameSystem { private final Int2ObjectMap> shopData; private final List shopChestData; private final List shopChestBatchUseData; + + private static final int REFRESH_HOUR = 4; // In GMT+8 server + private static final String TIME_ZONE = "Asia/Shanghai"; // GMT+8 Timezone - public ShopManager(GameServer server) { - this.server = server; + public ShopSystem(GameServer server) { + super(server); this.shopData = new Int2ObjectOpenHashMap<>(); this.shopChestData = new ArrayList<>(); this.shopChestBatchUseData = new ArrayList<>(); this.load(); } + + public Int2ObjectMap> getShopData() { + return shopData; + } - private static final int REFRESH_HOUR = 4; // In GMT+8 server - private static final String TIME_ZONE = "Asia/Shanghai"; // GMT+8 Timezone + public List getShopChestData() { + return shopChestData; + } + + public List getShopChestBatchUseData() { + return shopChestBatchUseData; + } public static int getShopNextRefreshTime(ShopInfo shopInfo) { return switch (shopInfo.getShopRefreshType()) { diff --git a/src/main/java/emu/grasscutter/game/tower/TowerManager.java b/src/main/java/emu/grasscutter/game/tower/TowerManager.java index a862b1587..19a6d860c 100644 --- a/src/main/java/emu/grasscutter/game/tower/TowerManager.java +++ b/src/main/java/emu/grasscutter/game/tower/TowerManager.java @@ -74,7 +74,7 @@ public class TowerManager extends BasePlayerManager { notifyCurLevelRecordChange(); // use team user choose player.getTeamManager().useTemporaryTeam(0); - player.getServer().getDungeonManager().handoffDungeon(player, dungeonId, + player.getServer().getDungeonSystem().handoffDungeon(player, dungeonId, towerDungeonSettleListener); // make sure user can exit dungeon correctly @@ -116,10 +116,10 @@ public class TowerManager extends BasePlayerManager { return getTowerData().currentLevel < 3; } public int getNextFloorId() { - return player.getServer().getTowerScheduleManager().getNextFloorId(getTowerData().currentFloorId); + return player.getServer().getTowerSystem().getNextFloorId(getTowerData().currentFloorId); } public boolean hasNextFloor(){ - return player.getServer().getTowerScheduleManager().getNextFloorId(getTowerData().currentFloorId) > 0; + return player.getServer().getTowerSystem().getNextFloorId(getTowerData().currentFloorId) > 0; } public void clearEntry() { @@ -128,10 +128,10 @@ public class TowerManager extends BasePlayerManager { public boolean canEnterScheduleFloor(){ Map recordMap = getRecordMap(); - if(!recordMap.containsKey(player.getServer().getTowerScheduleManager().getLastEntranceFloor())){ + if(!recordMap.containsKey(player.getServer().getTowerSystem().getLastEntranceFloor())){ return false; } - return recordMap.get(player.getServer().getTowerScheduleManager().getLastEntranceFloor()) + return recordMap.get(player.getServer().getTowerSystem().getLastEntranceFloor()) .getStarCount() >= 6; } diff --git a/src/main/java/emu/grasscutter/game/tower/TowerScheduleManager.java b/src/main/java/emu/grasscutter/game/tower/TowerSystem.java similarity index 92% rename from src/main/java/emu/grasscutter/game/tower/TowerScheduleManager.java rename to src/main/java/emu/grasscutter/game/tower/TowerSystem.java index 0455a9769..206bab462 100644 --- a/src/main/java/emu/grasscutter/game/tower/TowerScheduleManager.java +++ b/src/main/java/emu/grasscutter/game/tower/TowerSystem.java @@ -4,6 +4,7 @@ import emu.grasscutter.Grasscutter; import emu.grasscutter.data.DataLoader; import emu.grasscutter.data.GameData; import emu.grasscutter.data.excels.TowerScheduleData; +import emu.grasscutter.server.game.BaseGameSystem; import emu.grasscutter.server.game.GameServer; import java.io.FileReader; @@ -14,15 +15,10 @@ import java.util.List; import static emu.grasscutter.Configuration.*; -public class TowerScheduleManager { - private final GameServer gameServer; - - public GameServer getGameServer() { - return gameServer; - } - - public TowerScheduleManager(GameServer gameServer) { - this.gameServer = gameServer; +public class TowerSystem extends BaseGameSystem { + + public TowerSystem(GameServer server) { + super(server); this.load(); } diff --git a/src/main/java/emu/grasscutter/game/world/Scene.java b/src/main/java/emu/grasscutter/game/world/Scene.java index d3af36c9f..105e22ff6 100644 --- a/src/main/java/emu/grasscutter/game/world/Scene.java +++ b/src/main/java/emu/grasscutter/game/world/Scene.java @@ -399,7 +399,7 @@ public class Scene { // Reward drop if (target instanceof EntityMonster && this.getSceneType() != SceneType.SCENE_DUNGEON) { - getWorld().getServer().getDropManager().callDrop((EntityMonster) target); + getWorld().getServer().getDropSystem().callDrop((EntityMonster) target); } this.removeEntity(target); diff --git a/src/main/java/emu/grasscutter/game/world/WorldDataManager.java b/src/main/java/emu/grasscutter/game/world/WorldDataSystem.java similarity index 97% rename from src/main/java/emu/grasscutter/game/world/WorldDataManager.java rename to src/main/java/emu/grasscutter/game/world/WorldDataSystem.java index dcffe5417..a4be78686 100644 --- a/src/main/java/emu/grasscutter/game/world/WorldDataManager.java +++ b/src/main/java/emu/grasscutter/game/world/WorldDataSystem.java @@ -14,6 +14,7 @@ import emu.grasscutter.game.player.Player; import emu.grasscutter.net.proto.InvestigationMonsterOuterClass; import emu.grasscutter.scripts.data.SceneGroup; import emu.grasscutter.scripts.data.SceneMonster; +import emu.grasscutter.server.game.BaseGameSystem; import emu.grasscutter.server.game.GameServer; import java.io.InputStream; @@ -24,13 +25,12 @@ import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; -public class WorldDataManager { - private final GameServer gameServer; +public class WorldDataSystem extends BaseGameSystem { private final Map chestInteractHandlerMap; // chestType-Handler private final Map sceneInvestigationGroupMap; // - public WorldDataManager(GameServer gameServer){ - this.gameServer = gameServer; + public WorldDataSystem(GameServer server){ + super(server); this.chestInteractHandlerMap = new HashMap<>(); this.sceneInvestigationGroupMap = new ConcurrentHashMap<>(); diff --git a/src/main/java/emu/grasscutter/server/game/BaseGameSystem.java b/src/main/java/emu/grasscutter/server/game/BaseGameSystem.java new file mode 100644 index 000000000..536e90575 --- /dev/null +++ b/src/main/java/emu/grasscutter/server/game/BaseGameSystem.java @@ -0,0 +1,13 @@ +package emu.grasscutter.server.game; + +public abstract class BaseGameSystem { + protected final GameServer server; + + public BaseGameSystem(GameServer server) { + this.server = server; + } + + public GameServer getServer() { + return this.server; + } +} diff --git a/src/main/java/emu/grasscutter/server/game/GameServer.java b/src/main/java/emu/grasscutter/server/game/GameServer.java index 7db3ae0da..5b53e31dc 100644 --- a/src/main/java/emu/grasscutter/server/game/GameServer.java +++ b/src/main/java/emu/grasscutter/server/game/GameServer.java @@ -5,27 +5,27 @@ import emu.grasscutter.Grasscutter; import emu.grasscutter.command.CommandMap; import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.game.Account; -import emu.grasscutter.game.battlepass.BattlePassMissionManager; +import emu.grasscutter.game.battlepass.BattlePassSystem; import emu.grasscutter.game.combine.CombineManger; -import emu.grasscutter.game.drop.DropManager; -import emu.grasscutter.game.dungeons.DungeonManager; +import emu.grasscutter.game.drop.DropSystem; +import emu.grasscutter.game.dungeons.DungeonSystem; import emu.grasscutter.game.dungeons.challenge.DungeonChallenge; -import emu.grasscutter.game.expedition.ExpeditionManager; -import emu.grasscutter.game.gacha.GachaManager; -import emu.grasscutter.game.managers.AnnouncementManager; +import emu.grasscutter.game.expedition.ExpeditionSystem; +import emu.grasscutter.game.gacha.GachaSystem; +import emu.grasscutter.game.managers.AnnouncementSystem; import emu.grasscutter.game.managers.CookingManager; -import emu.grasscutter.game.managers.InventoryManager; -import emu.grasscutter.game.managers.MultiplayerManager; +import emu.grasscutter.game.managers.InventorySystem; +import emu.grasscutter.game.managers.MultiplayerSystem; import emu.grasscutter.game.managers.chat.ChatManager; import emu.grasscutter.game.managers.chat.ChatManagerHandler; import emu.grasscutter.game.managers.energy.EnergyManager; import emu.grasscutter.game.managers.stamina.StaminaManager; import emu.grasscutter.game.player.Player; -import emu.grasscutter.game.quest.ServerQuestHandler; -import emu.grasscutter.game.shop.ShopManager; -import emu.grasscutter.game.tower.TowerScheduleManager; +import emu.grasscutter.game.quest.QuestSystem; +import emu.grasscutter.game.shop.ShopSystem; +import emu.grasscutter.game.tower.TowerSystem; import emu.grasscutter.game.world.World; -import emu.grasscutter.game.world.WorldDataManager; +import emu.grasscutter.game.world.WorldDataSystem; import emu.grasscutter.net.packet.PacketHandler; import emu.grasscutter.net.proto.SocialDetailOuterClass.SocialDetail; import emu.grasscutter.server.event.types.ServerEvent; @@ -47,30 +47,35 @@ import java.util.concurrent.ConcurrentHashMap; import static emu.grasscutter.utils.Language.translate; import static emu.grasscutter.Configuration.*; +@Getter public final class GameServer extends KcpServer { - private final InetSocketAddress address; + // Game server base + private final InetSocketAddress address; private final GameServerPacketHandler packetHandler; - private final ServerQuestHandler questHandler; - @Getter private final ServerTaskScheduler scheduler; - - private final Map players; - private final Set worlds; + private final Map players; + private final Set worlds; + // Server systems + private final InventorySystem inventorySystem; + private final GachaSystem gachaSystem; + private final ShopSystem shopSystem; + private final MultiplayerSystem multiplayerSystem; + private final DungeonSystem dungeonSystem; + private final ExpeditionSystem expeditionSystem; + private final DropSystem dropSystem; + private final WorldDataSystem worldDataSystem; + private final BattlePassSystem battlePassSystem; + private final CombineManger combineSystem; + private final TowerSystem towerSystem; + private final AnnouncementSystem announcementSystem; + private final QuestSystem questSystem; + + // Extra + private final ServerTaskScheduler scheduler; + private final CommandMap commandMap; + private final TaskMap taskMap; + private ChatManagerHandler chatManager; - @Getter private final InventoryManager inventoryManager; - @Getter private final GachaManager gachaManager; - @Getter private final ShopManager shopManager; - @Getter private final MultiplayerManager multiplayerManager; - @Getter private final DungeonManager dungeonManager; - @Getter private final ExpeditionManager expeditionManager; - @Getter private final CommandMap commandMap; - @Getter private final TaskMap taskMap; - @Getter private final DropManager dropManager; - @Getter private final WorldDataManager worldDataManager; - @Getter private final BattlePassMissionManager battlePassMissionManager; - @Getter private final CombineManger combineManger; - @Getter private final TowerScheduleManager towerScheduleManager; - @Getter private final AnnouncementManager announcementManager; public GameServer() { this(getAdapterInetSocketAddress()); @@ -78,11 +83,11 @@ public final class GameServer extends KcpServer { public GameServer(InetSocketAddress address) { ChannelConfig channelConfig = new ChannelConfig(); - channelConfig.nodelay(true,40,2,true); + channelConfig.nodelay(true, 40, 2, true); channelConfig.setMtu(1400); channelConfig.setSndwnd(256); channelConfig.setRcvwnd(256); - channelConfig.setTimeoutMillis(30*1000);//30s + channelConfig.setTimeoutMillis(30 * 1000);//30s channelConfig.setUseConvChannel(true); channelConfig.setAckNoDelay(false); @@ -94,56 +99,56 @@ public final class GameServer extends KcpServer { CookingManager.initialize(); CombineManger.initialize(); + // Game Server base this.address = address; this.packetHandler = new GameServerPacketHandler(PacketHandler.class); - this.questHandler = new ServerQuestHandler(); - this.scheduler = new ServerTaskScheduler(); this.players = new ConcurrentHashMap<>(); this.worlds = Collections.synchronizedSet(new HashSet<>()); - - this.chatManager = new ChatManager(this); - this.inventoryManager = new InventoryManager(this); - this.gachaManager = new GachaManager(this); - this.shopManager = new ShopManager(this); - this.multiplayerManager = new MultiplayerManager(this); - this.dungeonManager = new DungeonManager(this); + + // Extra + this.scheduler = new ServerTaskScheduler(); this.commandMap = new CommandMap(true); - this.taskMap = new TaskMap(true); - this.dropManager = new DropManager(this); - this.expeditionManager = new ExpeditionManager(this); - this.combineManger = new CombineManger(this); - this.towerScheduleManager = new TowerScheduleManager(this); - this.worldDataManager = new WorldDataManager(this); - this.battlePassMissionManager = new BattlePassMissionManager(this); - this.announcementManager = new AnnouncementManager(this); + this.taskMap = new TaskMap(true); + + // Create game systems + this.inventorySystem = new InventorySystem(this); + this.gachaSystem = new GachaSystem(this); + this.shopSystem = new ShopSystem(this); + this.multiplayerSystem = new MultiplayerSystem(this); + this.dungeonSystem = new DungeonSystem(this); + this.dropSystem = new DropSystem(this); + this.expeditionSystem = new ExpeditionSystem(this); + this.combineSystem = new CombineManger(this); + this.towerSystem = new TowerSystem(this); + this.worldDataSystem = new WorldDataSystem(this); + this.battlePassSystem = new BattlePassSystem(this); + this.announcementSystem = new AnnouncementSystem(this); + this.questSystem = new QuestSystem(this); + + // Chata manager + this.chatManager = new ChatManager(this); + // Hook into shutdown event. Runtime.getRuntime().addShutdownHook(new Thread(this::onServerShutdown)); } + + @Deprecated + public ChatManagerHandler getChatManager() { + return chatManager; + } + + @Deprecated + public void setChatManager(ChatManagerHandler chatManager) { + this.chatManager = chatManager; + } + + public ChatManagerHandler getChatSystem() { + return chatManager; + } - public GameServerPacketHandler getPacketHandler() { - return packetHandler; - } - - public ServerQuestHandler getQuestHandler() { - return questHandler; - } - - public Map getPlayers() { - return players; - } - - public Set getWorlds() { - return worlds; - } - - public ChatManagerHandler getChatManager() { - return chatManager; - } - - public void setChatManager(ChatManagerHandler chatManager) { - this.chatManager = chatManager; - } - + public void setChatSystem(ChatManagerHandler chatManager) { + this.chatManager = chatManager; + } private static InetSocketAddress getAdapterInetSocketAddress(){ InetSocketAddress inetSocketAddress; diff --git a/src/main/java/emu/grasscutter/server/http/handlers/GachaHandler.java b/src/main/java/emu/grasscutter/server/http/handlers/GachaHandler.java index 69a0c67ce..6032e774f 100644 --- a/src/main/java/emu/grasscutter/server/http/handlers/GachaHandler.java +++ b/src/main/java/emu/grasscutter/server/http/handlers/GachaHandler.java @@ -4,7 +4,7 @@ import emu.grasscutter.Grasscutter; import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.game.Account; import emu.grasscutter.game.gacha.GachaBanner; -import emu.grasscutter.game.gacha.GachaManager; +import emu.grasscutter.game.gacha.GachaSystem; import emu.grasscutter.game.player.Player; import emu.grasscutter.server.http.Router; import emu.grasscutter.tools.Tools; @@ -108,7 +108,7 @@ public final class GachaHandler implements Router { // Get the banner info for the banner we want. int scheduleId = Integer.parseInt(request.query("scheduleId")); - GachaManager manager = Grasscutter.getGameServer().getGachaManager(); + GachaSystem manager = Grasscutter.getGameServer().getGachaSystem(); GachaBanner banner = manager.getGachaBanners().get(scheduleId); // Add 5-star items. diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarExpeditionGetRewardReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarExpeditionGetRewardReq.java index 3e3bed9f1..aaacd7954 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarExpeditionGetRewardReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarExpeditionGetRewardReq.java @@ -34,8 +34,8 @@ public class HandlerAvatarExpeditionGetRewardReq extends PacketHandler { List items = new LinkedList<>(); - if (session.getServer().getExpeditionManager().getExpeditionRewardDataList().containsKey(expInfo.getExpId())) { - for (ExpeditionRewardDataList RewardDataList : session.getServer().getExpeditionManager().getExpeditionRewardDataList().get(expInfo.getExpId())) { + if (session.getServer().getExpeditionSystem().getExpeditionRewardDataList().containsKey(expInfo.getExpId())) { + for (ExpeditionRewardDataList RewardDataList : session.getServer().getExpeditionSystem().getExpeditionRewardDataList().get(expInfo.getExpId())) { if(RewardDataList.getHourTime() == expInfo.getHourTime()){ if(!RewardDataList.getExpeditionRewardData().isEmpty()){ for (ExpeditionRewardData RewardData :RewardDataList.getExpeditionRewardData()) { diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarPromoteReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarPromoteReq.java index cd863f5bf..5914f98c9 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarPromoteReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarPromoteReq.java @@ -14,7 +14,7 @@ public class HandlerAvatarPromoteReq extends PacketHandler { AvatarPromoteReq req = AvatarPromoteReq.parseFrom(payload); // Ascend avatar - session.getServer().getInventoryManager().promoteAvatar(session.getPlayer(), req.getGuid()); + session.getServer().getInventorySystem().promoteAvatar(session.getPlayer(), req.getGuid()); } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarSkillUpgradeReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarSkillUpgradeReq.java index e179bcd8e..188e754fe 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarSkillUpgradeReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarSkillUpgradeReq.java @@ -14,7 +14,7 @@ public class HandlerAvatarSkillUpgradeReq extends PacketHandler { AvatarSkillUpgradeReq req = AvatarSkillUpgradeReq.parseFrom(payload); // Level up avatar talent - session.getServer().getInventoryManager().upgradeAvatarSkill(session.getPlayer(), req.getAvatarGuid(), req.getAvatarSkillId()); + session.getServer().getInventorySystem().upgradeAvatarSkill(session.getPlayer(), req.getAvatarGuid(), req.getAvatarSkillId()); } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarUpgradeReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarUpgradeReq.java index 3254b2327..93fa0a7a3 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarUpgradeReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarUpgradeReq.java @@ -14,7 +14,7 @@ public class HandlerAvatarUpgradeReq extends PacketHandler { AvatarUpgradeReq req = AvatarUpgradeReq.parseFrom(payload); // Level up avatar - session.getServer().getInventoryManager().upgradeAvatar( + session.getServer().getInventorySystem().upgradeAvatar( session.getPlayer(), req.getAvatarGuid(), req.getItemId(), diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerBuyGoodsReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerBuyGoodsReq.java index 7e8a9d8a0..2b645cc11 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerBuyGoodsReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerBuyGoodsReq.java @@ -6,7 +6,7 @@ import emu.grasscutter.game.inventory.GameItem; import emu.grasscutter.game.props.ActionReason; import emu.grasscutter.game.shop.ShopInfo; import emu.grasscutter.game.shop.ShopLimit; -import emu.grasscutter.game.shop.ShopManager; +import emu.grasscutter.game.shop.ShopSystem; import emu.grasscutter.net.packet.Opcodes; import emu.grasscutter.net.packet.PacketHandler; import emu.grasscutter.net.packet.PacketOpcodes; @@ -29,7 +29,7 @@ public class HandlerBuyGoodsReq extends PacketHandler { @Override public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { BuyGoodsReqOuterClass.BuyGoodsReq buyGoodsReq = BuyGoodsReqOuterClass.BuyGoodsReq.parseFrom(payload); - List configShop = session.getServer().getShopManager().getShopData().get(buyGoodsReq.getShopType()); + List configShop = session.getServer().getShopSystem().getShopData().get(buyGoodsReq.getShopType()); if (configShop == null) return; @@ -46,7 +46,7 @@ public class HandlerBuyGoodsReq extends PacketHandler { int bought = 0; if (shopLimit != null) { if (currentTs > shopLimit.getNextRefreshTime()) { - shopLimit.setNextRefreshTime(ShopManager.getShopNextRefreshTime(sg)); + shopLimit.setNextRefreshTime(ShopSystem.getShopNextRefreshTime(sg)); } else { bought = shopLimit.getHasBoughtInPeriod(); } @@ -65,7 +65,7 @@ public class HandlerBuyGoodsReq extends PacketHandler { return; } - session.getPlayer().addShopLimit(sg.getGoodsId(), buyGoodsReq.getBuyCount(), ShopManager.getShopNextRefreshTime(sg)); + session.getPlayer().addShopLimit(sg.getGoodsId(), buyGoodsReq.getBuyCount(), ShopSystem.getShopNextRefreshTime(sg)); GameItem item = new GameItem(GameData.getItemDataMap().get(sg.getGoodsItem().getId())); item.setCount(buyGoodsReq.getBuyCount() * sg.getGoodsItem().getCount()); session.getPlayer().getInventory().addItem(item, ActionReason.Shop, true); // fix: not notify when got virtual item from shop diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerCalcWeaponUpgradeReturnItemsReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerCalcWeaponUpgradeReturnItemsReq.java index 79f199ee9..cc7a06e7b 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerCalcWeaponUpgradeReturnItemsReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerCalcWeaponUpgradeReturnItemsReq.java @@ -17,7 +17,7 @@ public class HandlerCalcWeaponUpgradeReturnItemsReq extends PacketHandler { public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { CalcWeaponUpgradeReturnItemsReq req = CalcWeaponUpgradeReturnItemsReq.parseFrom(payload); - List returnOres = session.getServer().getInventoryManager().calcWeaponUpgradeReturnItems( + List returnOres = session.getServer().getInventorySystem().calcWeaponUpgradeReturnItems( session.getPlayer(), req.getTargetWeaponGuid(), req.getFoodWeaponGuidListList(), diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerCombineReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerCombineReq.java index c5b52fab0..b8d80eb3d 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerCombineReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerCombineReq.java @@ -21,7 +21,7 @@ public class HandlerCombineReq extends PacketHandler { CombineReqOuterClass.CombineReq req = CombineReqOuterClass.CombineReq.parseFrom(payload); - var result = session.getServer().getCombineManger() + var result = session.getServer().getCombineSystem() .combineItem(session.getPlayer(), req.getCombineId(), req.getCombineCount()); if(result == null){ diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerDestroyMaterialReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerDestroyMaterialReq.java index e39239f68..35626e97a 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerDestroyMaterialReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerDestroyMaterialReq.java @@ -13,6 +13,6 @@ public class HandlerDestroyMaterialReq extends PacketHandler { DestroyMaterialReq req = DestroyMaterialReq.parseFrom(payload); // Delete items - session.getServer().getInventoryManager().destroyMaterial(session.getPlayer(), req.getMaterialListList()); + session.getServer().getInventorySystem().destroyMaterial(session.getPlayer(), req.getMaterialListList()); } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerDoGachaReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerDoGachaReq.java index 1c06dbbfa..8a69f3edc 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerDoGachaReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerDoGachaReq.java @@ -12,6 +12,6 @@ public class HandlerDoGachaReq extends PacketHandler { public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { DoGachaReq req = DoGachaReq.parseFrom(payload); - session.getServer().getGachaManager().doPulls(session.getPlayer(), req.getGachaScheduleId(), req.getGachaTimes()); + session.getServer().getGachaSystem().doPulls(session.getPlayer(), req.getGachaScheduleId(), req.getGachaTimes()); } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerDungeonEntryInfoReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerDungeonEntryInfoReq.java index 286fbdc67..006f3c73c 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerDungeonEntryInfoReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerDungeonEntryInfoReq.java @@ -13,7 +13,7 @@ public class HandlerDungeonEntryInfoReq extends PacketHandler { public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { DungeonEntryInfoReq req = DungeonEntryInfoReq.parseFrom(payload); - session.getServer().getDungeonManager().getEntryInfo(session.getPlayer(), req.getPointId()); + session.getServer().getDungeonSystem().getEntryInfo(session.getPlayer(), req.getPointId()); } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGachaWishReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGachaWishReq.java index ce3159dc5..ff0e68944 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGachaWishReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGachaWishReq.java @@ -16,7 +16,7 @@ public class HandlerGachaWishReq extends PacketHandler { public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { GachaWishReq req = GachaWishReq.parseFrom(payload); - GachaBanner banner = session.getServer().getGachaManager().getGachaBanners().get(req.getGachaScheduleId()); + GachaBanner banner = session.getServer().getGachaSystem().getGachaBanners().get(req.getGachaScheduleId()); PlayerGachaBannerInfo gachaInfo = session.getPlayer().getGachaInfo().getBannerInfo(banner); gachaInfo.setFailedChosenItemPulls(0); diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetGachaInfoReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetGachaInfoReq.java index b4a9f9fe7..afa4c9612 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetGachaInfoReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetGachaInfoReq.java @@ -14,7 +14,7 @@ public class HandlerGetGachaInfoReq extends PacketHandler { @Override public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - session.send(new PacketGetGachaInfoRsp(session.getServer().getGachaManager(), session.getPlayer())); + session.send(new PacketGetGachaInfoRsp(session.getServer().getGachaSystem(), session.getPlayer())); } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetInvestigationMonsterReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetInvestigationMonsterReq.java index f326731c8..f3ca23ce0 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetInvestigationMonsterReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetInvestigationMonsterReq.java @@ -16,7 +16,7 @@ public class HandlerGetInvestigationMonsterReq extends PacketHandler { session.send(new PacketGetInvestigationMonsterRsp( session.getPlayer(), - session.getServer().getWorldDataManager(), + session.getServer().getWorldDataSystem(), req.getCityIdListList())); } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerApplyEnterMpReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerApplyEnterMpReq.java index ed5591a1b..e2e1309ad 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerApplyEnterMpReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerApplyEnterMpReq.java @@ -14,7 +14,7 @@ public class HandlerPlayerApplyEnterMpReq extends PacketHandler { public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { PlayerApplyEnterMpReq req = PlayerApplyEnterMpReq.parseFrom(payload); - session.getServer().getMultiplayerManager().applyEnterMp(session.getPlayer(), req.getTargetUid()); + session.getServer().getMultiplayerSystem().applyEnterMp(session.getPlayer(), req.getTargetUid()); session.send(new PacketPlayerApplyEnterMpRsp(req.getTargetUid())); } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerApplyEnterMpResultReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerApplyEnterMpResultReq.java index 7a9c41db2..7589190aa 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerApplyEnterMpResultReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerApplyEnterMpResultReq.java @@ -14,7 +14,7 @@ public class HandlerPlayerApplyEnterMpResultReq extends PacketHandler { public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { PlayerApplyEnterMpResultReq req = PlayerApplyEnterMpResultReq.parseFrom(payload); - session.getServer().getMultiplayerManager().applyEnterMpReply(session.getPlayer(), req.getApplyUid(), req.getIsAgreed()); + session.getServer().getMultiplayerSystem().applyEnterMpReply(session.getPlayer(), req.getApplyUid(), req.getIsAgreed()); session.send(new PacketPlayerApplyEnterMpResultRsp(req.getApplyUid(), req.getIsAgreed())); } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerEnterDungeonReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerEnterDungeonReq.java index ce05c8ccf..162eec998 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerEnterDungeonReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerEnterDungeonReq.java @@ -14,7 +14,7 @@ public class HandlerPlayerEnterDungeonReq extends PacketHandler { // Auto template PlayerEnterDungeonReq req = PlayerEnterDungeonReq.parseFrom(payload); - session.getServer().getDungeonManager().enterDungeon(session.getPlayer(), req.getPointId(), req.getDungeonId()); + session.getServer().getDungeonSystem().enterDungeon(session.getPlayer(), req.getPointId(), req.getDungeonId()); } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerGetForceQuitBanInfoReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerGetForceQuitBanInfoReq.java index 65740c7fd..f0b5311a9 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerGetForceQuitBanInfoReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerGetForceQuitBanInfoReq.java @@ -13,7 +13,7 @@ public class HandlerPlayerGetForceQuitBanInfoReq extends PacketHandler { @Override public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - if (session.getServer().getMultiplayerManager().leaveCoop(session.getPlayer())) { + if (session.getServer().getMultiplayerSystem().leaveCoop(session.getPlayer())) { // Success session.send(new PacketPlayerGetForceQuitBanInfoRsp(RetcodeOuterClass.Retcode.RET_SUCC_VALUE)); } else { diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerQuitDungeonReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerQuitDungeonReq.java index e33190847..9bc450149 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerQuitDungeonReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerQuitDungeonReq.java @@ -10,7 +10,7 @@ public class HandlerPlayerQuitDungeonReq extends PacketHandler { @Override public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - session.getPlayer().getServer().getDungeonManager().exitDungeon(session.getPlayer()); + session.getPlayer().getServer().getDungeonSystem().exitDungeon(session.getPlayer()); } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerReliquaryDecomposeReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerReliquaryDecomposeReq.java index d34833596..a098ef0d6 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerReliquaryDecomposeReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerReliquaryDecomposeReq.java @@ -11,6 +11,6 @@ public class HandlerReliquaryDecomposeReq extends PacketHandler { @Override public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { ReliquaryDecomposeReq req = ReliquaryDecomposeReq.parseFrom(payload); - session.getServer().getCombineManger().decomposeReliquaries(session.getPlayer(), req.getConfigId(), req.getTargetCount(), req.getGuidListList()); + session.getServer().getCombineSystem().decomposeReliquaries(session.getPlayer(), req.getConfigId(), req.getTargetCount(), req.getGuidListList()); } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerReliquaryUpgradeReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerReliquaryUpgradeReq.java index bd8ec9e58..6eb19b7ed 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerReliquaryUpgradeReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerReliquaryUpgradeReq.java @@ -13,7 +13,7 @@ public class HandlerReliquaryUpgradeReq extends PacketHandler { public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { ReliquaryUpgradeReq req = ReliquaryUpgradeReq.parseFrom(payload); - session.getServer().getInventoryManager().upgradeRelic(session.getPlayer(), req.getTargetReliquaryGuid(), req.getFoodReliquaryGuidListList(), req.getItemParamListList()); + session.getServer().getInventorySystem().upgradeRelic(session.getPlayer(), req.getTargetReliquaryGuid(), req.getFoodReliquaryGuidListList(), req.getItemParamListList()); } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSceneKickPlayerReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSceneKickPlayerReq.java index 732664481..fec303b4b 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSceneKickPlayerReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSceneKickPlayerReq.java @@ -14,7 +14,7 @@ public class HandlerSceneKickPlayerReq extends PacketHandler { public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { SceneKickPlayerReq req = SceneKickPlayerReq.parseFrom(payload); - if (session.getServer().getMultiplayerManager().kickPlayer(session.getPlayer(), req.getTargetUid())) { + if (session.getServer().getMultiplayerSystem().kickPlayer(session.getPlayer(), req.getTargetUid())) { // Success session.send(new PacketSceneKickPlayerRsp(req.getTargetUid())); } else { diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetEquipLockStateReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetEquipLockStateReq.java index 27bd8b1cb..2467650f9 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetEquipLockStateReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetEquipLockStateReq.java @@ -13,7 +13,7 @@ public class HandlerSetEquipLockStateReq extends PacketHandler { public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { SetEquipLockStateReq req = SetEquipLockStateReq.parseFrom(payload); - session.getServer().getInventoryManager().lockEquip(session.getPlayer(), req.getTargetEquipGuid(), req.getIsLocked()); + session.getServer().getInventorySystem().lockEquip(session.getPlayer(), req.getTargetEquipGuid(), req.getIsLocked()); } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerTowerAllDataReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerTowerAllDataReq.java index 38462882f..c9fa5b112 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerTowerAllDataReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerTowerAllDataReq.java @@ -12,7 +12,7 @@ public class HandlerTowerAllDataReq extends PacketHandler { @Override public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { session.send(new PacketTowerAllDataRsp( - session.getServer().getTowerScheduleManager(), + session.getServer().getTowerSystem(), session.getPlayer().getTowerManager() )); } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerUnlockAvatarTalentReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerUnlockAvatarTalentReq.java index 93cf1cad7..d37df8618 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerUnlockAvatarTalentReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerUnlockAvatarTalentReq.java @@ -14,7 +14,7 @@ public class HandlerUnlockAvatarTalentReq extends PacketHandler { UnlockAvatarTalentReq req = UnlockAvatarTalentReq.parseFrom(payload); // Unlock avatar const - session.getServer().getInventoryManager().unlockAvatarConstellation(session.getPlayer(), req.getAvatarGuid()); + session.getServer().getInventorySystem().unlockAvatarConstellation(session.getPlayer(), req.getAvatarGuid()); } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerUseItemReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerUseItemReq.java index daf4e4c04..0941dafed 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerUseItemReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerUseItemReq.java @@ -15,7 +15,7 @@ public class HandlerUseItemReq extends PacketHandler { public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { UseItemReq req = UseItemReq.parseFrom(payload); - GameItem useItem = session.getServer().getInventoryManager().useItem(session.getPlayer(), req.getTargetGuid(), req.getGuid(), req.getCount(), req.getOptionIdx()); + GameItem useItem = session.getServer().getInventorySystem().useItem(session.getPlayer(), req.getTargetGuid(), req.getGuid(), req.getCount(), req.getOptionIdx()); if (useItem != null) { session.send(new PacketUseItemRsp(req.getTargetGuid(), useItem)); } else { diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerWeaponAwakenReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerWeaponAwakenReq.java index b33510ad0..0c9fcd68c 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerWeaponAwakenReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerWeaponAwakenReq.java @@ -14,7 +14,7 @@ public class HandlerWeaponAwakenReq extends PacketHandler { WeaponAwakenReq req = WeaponAwakenReq.parseFrom(payload); // Weapon refinement - session.getServer().getInventoryManager().refineWeapon(session.getPlayer(), req.getTargetWeaponGuid(), req.getItemGuid()); + session.getServer().getInventorySystem().refineWeapon(session.getPlayer(), req.getTargetWeaponGuid(), req.getItemGuid()); } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerWeaponPromoteReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerWeaponPromoteReq.java index 0b3c23b49..bbb50bd5d 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerWeaponPromoteReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerWeaponPromoteReq.java @@ -14,7 +14,7 @@ public class HandlerWeaponPromoteReq extends PacketHandler { WeaponPromoteReq req = WeaponPromoteReq.parseFrom(payload); // Ascend weapon - session.getServer().getInventoryManager().promoteWeapon(session.getPlayer(), req.getTargetWeaponGuid()); + session.getServer().getInventorySystem().promoteWeapon(session.getPlayer(), req.getTargetWeaponGuid()); } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerWeaponUpgradeReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerWeaponUpgradeReq.java index f099c976a..3e531afa6 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerWeaponUpgradeReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerWeaponUpgradeReq.java @@ -14,7 +14,7 @@ public class HandlerWeaponUpgradeReq extends PacketHandler { WeaponUpgradeReq req = WeaponUpgradeReq.parseFrom(payload); // Level up weapon - session.getServer().getInventoryManager().upgradeWeapon( + session.getServer().getInventorySystem().upgradeWeapon( session.getPlayer(), req.getTargetWeaponGuid(), req.getFoodWeaponGuidListList(), diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketGetGachaInfoRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketGetGachaInfoRsp.java index 1bd3ea876..bc1e3f1e3 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketGetGachaInfoRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketGetGachaInfoRsp.java @@ -1,13 +1,13 @@ package emu.grasscutter.server.packet.send; -import emu.grasscutter.game.gacha.GachaManager; +import emu.grasscutter.game.gacha.GachaSystem; import emu.grasscutter.game.player.Player; import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.PacketOpcodes; public class PacketGetGachaInfoRsp extends BasePacket { - public PacketGetGachaInfoRsp(GachaManager manager, Player player) { + public PacketGetGachaInfoRsp(GachaSystem manager, Player player) { super(PacketOpcodes.GetGachaInfoRsp); this.setData(manager.toProto(player)); diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketGetInvestigationMonsterRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketGetInvestigationMonsterRsp.java index 51e88a71e..306cbca57 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketGetInvestigationMonsterRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketGetInvestigationMonsterRsp.java @@ -1,7 +1,7 @@ package emu.grasscutter.server.packet.send; import emu.grasscutter.game.player.Player; -import emu.grasscutter.game.world.WorldDataManager; +import emu.grasscutter.game.world.WorldDataSystem; import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.proto.GetActivityInfoRspOuterClass; @@ -11,7 +11,7 @@ import java.util.List; public class PacketGetInvestigationMonsterRsp extends BasePacket { - public PacketGetInvestigationMonsterRsp(Player player, WorldDataManager worldDataManager, List cityIdListList) { + public PacketGetInvestigationMonsterRsp(Player player, WorldDataSystem worldDataManager, List cityIdListList) { super(PacketOpcodes.GetInvestigationMonsterRsp); diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketGetShopRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketGetShopRsp.java index f76f3d198..0bee63451 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketGetShopRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketGetShopRsp.java @@ -4,7 +4,7 @@ import emu.grasscutter.Grasscutter; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.shop.ShopInfo; import emu.grasscutter.game.shop.ShopLimit; -import emu.grasscutter.game.shop.ShopManager; +import emu.grasscutter.game.shop.ShopSystem; import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.proto.GetShopRspOuterClass; @@ -27,7 +27,7 @@ public class PacketGetShopRsp extends BasePacket { .setCityId(1) //mock .setCityReputationLevel(10); //mock - ShopManager manager = Grasscutter.getGameServer().getShopManager(); + ShopSystem manager = Grasscutter.getGameServer().getShopSystem(); if (manager.getShopData().get(shopType) != null) { List list = manager.getShopData().get(shopType); List goodsList = new ArrayList<>(); @@ -54,7 +54,7 @@ public class PacketGetShopRsp extends BasePacket { int currentTs = Utils.getCurrentSeconds(); ShopLimit currentShopLimit = inv.getGoodsLimit(info.getGoodsId()); - int nextRefreshTime = ShopManager.getShopNextRefreshTime(info); + int nextRefreshTime = ShopSystem.getShopNextRefreshTime(info); if (currentShopLimit != null) { if (currentShopLimit.getNextRefreshTime() < currentTs) { // second game day currentShopLimit.setHasBoughtInPeriod(0); diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketTowerAllDataRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketTowerAllDataRsp.java index 654aa4a07..e7adf1833 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketTowerAllDataRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketTowerAllDataRsp.java @@ -1,7 +1,7 @@ package emu.grasscutter.server.packet.send; import emu.grasscutter.game.tower.TowerManager; -import emu.grasscutter.game.tower.TowerScheduleManager; +import emu.grasscutter.game.tower.TowerSystem; import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.proto.TowerAllDataRspOuterClass.TowerAllDataRsp; @@ -17,7 +17,7 @@ import java.util.stream.IntStream; public class PacketTowerAllDataRsp extends BasePacket { - public PacketTowerAllDataRsp(TowerScheduleManager towerScheduleManager, TowerManager towerManager) { + public PacketTowerAllDataRsp(TowerSystem towerScheduleManager, TowerManager towerManager) { super(PacketOpcodes.TowerAllDataRsp); var recordList = towerManager.getRecordMap().values().stream() diff --git a/src/main/java/emu/grasscutter/task/tasks/AnnouncementTask.java b/src/main/java/emu/grasscutter/task/tasks/AnnouncementTask.java index bb717221f..c6ec1619b 100644 --- a/src/main/java/emu/grasscutter/task/tasks/AnnouncementTask.java +++ b/src/main/java/emu/grasscutter/task/tasks/AnnouncementTask.java @@ -1,7 +1,7 @@ package emu.grasscutter.task.tasks; import emu.grasscutter.Grasscutter; -import emu.grasscutter.game.managers.AnnouncementManager; +import emu.grasscutter.game.managers.AnnouncementSystem; import emu.grasscutter.task.Task; import emu.grasscutter.task.TaskHandler; import org.quartz.JobExecutionContext; @@ -29,11 +29,11 @@ public final class AnnouncementTask extends TaskHandler { @Override public synchronized void execute(JobExecutionContext context) throws JobExecutionException { var current = new Date(); - var announceConfigItems = Grasscutter.getGameServer().getAnnouncementManager().getAnnounceConfigItemMap().values().stream() - .filter(AnnouncementManager.AnnounceConfigItem::isTick) + var announceConfigItems = Grasscutter.getGameServer().getAnnouncementSystem().getAnnounceConfigItemMap().values().stream() + .filter(AnnouncementSystem.AnnounceConfigItem::isTick) .filter(i -> current.after(i.getBeginTime())) .filter(i -> current.before(i.getEndTime())) - .collect(Collectors.toMap(AnnouncementManager.AnnounceConfigItem::getTemplateId, y -> y)); + .collect(Collectors.toMap(AnnouncementSystem.AnnounceConfigItem::getTemplateId, y -> y)); announceConfigItems.values().forEach(i -> intervalMap.compute(i.getTemplateId(), (k,v) -> v == null ? 1 : v + 1)); @@ -43,7 +43,7 @@ public final class AnnouncementTask extends TaskHandler { .map(i -> announceConfigItems.get(i.getKey())) .toList(); - Grasscutter.getGameServer().getAnnouncementManager().broadcast(toSend); + Grasscutter.getGameServer().getAnnouncementSystem().broadcast(toSend); Grasscutter.getLogger().debug("Broadcast {} announcement(s) to all online players", toSend.size()); // clear the interval count From cc5b292bc374edfe11eb7cc54ab06bff30d9da2e Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Tue, 19 Jul 2022 00:35:54 -0700 Subject: [PATCH 26/61] Refactor `Player::GetPos()` -> `Player::GetPosition()` --- .../command/commands/PositionCommand.java | 2 +- .../grasscutter/command/commands/SpawnCommand.java | 2 +- .../command/commands/TeleportAllCommand.java | 2 +- .../command/commands/TeleportCommand.java | 2 +- .../emu/grasscutter/game/entity/EntityAvatar.java | 2 +- .../grasscutter/game/managers/MultiplayerSystem.java | 10 +++++----- .../game/managers/mapmark/MapMarksManager.java | 4 ++-- .../java/emu/grasscutter/game/player/Player.java | 12 ++++++------ .../emu/grasscutter/game/player/TeamManager.java | 2 +- src/main/java/emu/grasscutter/game/world/Scene.java | 12 ++++++------ src/main/java/emu/grasscutter/game/world/World.java | 6 +++--- .../java/emu/grasscutter/plugin/api/PlayerHook.java | 4 ++-- .../packet/send/PacketPlayerEnterSceneNotify.java | 4 ++-- 13 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/main/java/emu/grasscutter/command/commands/PositionCommand.java b/src/main/java/emu/grasscutter/command/commands/PositionCommand.java index 221afe801..0d59fdc54 100644 --- a/src/main/java/emu/grasscutter/command/commands/PositionCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/PositionCommand.java @@ -14,7 +14,7 @@ public final class PositionCommand implements CommandHandler { @Override public void execute(Player sender, Player targetPlayer, List args) { - Position pos = targetPlayer.getPos(); + Position pos = targetPlayer.getPosition(); CommandHandler.sendMessage(sender, translate(sender, "commands.position.success", Float.toString(pos.getX()), Float.toString(pos.getY()), Float.toString(pos.getZ()), Integer.toString(targetPlayer.getSceneId()))); diff --git a/src/main/java/emu/grasscutter/command/commands/SpawnCommand.java b/src/main/java/emu/grasscutter/command/commands/SpawnCommand.java index 311df8b56..3a962cf28 100644 --- a/src/main/java/emu/grasscutter/command/commands/SpawnCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/SpawnCommand.java @@ -85,7 +85,7 @@ public final class SpawnCommand implements CommandHandler { double maxRadius = Math.sqrt(amount * 0.2 / Math.PI); for (int i = 0; i < amount; i++) { - Position pos = GetRandomPositionInCircle(targetPlayer.getPos(), maxRadius).addY(3); + Position pos = GetRandomPositionInCircle(targetPlayer.getPosition(), maxRadius).addY(3); if(x != 0 && y != 0 && z != 0) { pos = GetRandomPositionInCircle(new Position(x, y, z), maxRadius).addY(3); } diff --git a/src/main/java/emu/grasscutter/command/commands/TeleportAllCommand.java b/src/main/java/emu/grasscutter/command/commands/TeleportAllCommand.java index 5a28383a3..5e046a207 100644 --- a/src/main/java/emu/grasscutter/command/commands/TeleportAllCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/TeleportAllCommand.java @@ -23,7 +23,7 @@ public final class TeleportAllCommand implements CommandHandler { for (Player player : targetPlayer.getWorld().getPlayers()) { if (player.equals(targetPlayer)) continue; - Position pos = targetPlayer.getPos(); + Position pos = targetPlayer.getPosition(); player.getWorld().transferPlayerToScene(player, targetPlayer.getSceneId(), pos); } diff --git a/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java b/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java index 0bc920ac7..21d898af9 100644 --- a/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java @@ -26,7 +26,7 @@ public final class TeleportCommand implements CommandHandler { @Override public void execute(Player sender, Player targetPlayer, List args) { - Position pos = targetPlayer.getPos(); + Position pos = targetPlayer.getPosition(); float x = pos.getX(); float y = pos.getY(); float z = pos.getZ(); diff --git a/src/main/java/emu/grasscutter/game/entity/EntityAvatar.java b/src/main/java/emu/grasscutter/game/entity/EntityAvatar.java index f200a6559..63d94b866 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityAvatar.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityAvatar.java @@ -69,7 +69,7 @@ public class EntityAvatar extends GameEntity { @Override public Position getPosition() { - return getPlayer().getPos(); + return getPlayer().getPosition(); } @Override diff --git a/src/main/java/emu/grasscutter/game/managers/MultiplayerSystem.java b/src/main/java/emu/grasscutter/game/managers/MultiplayerSystem.java index 053121f66..d64a34572 100644 --- a/src/main/java/emu/grasscutter/game/managers/MultiplayerSystem.java +++ b/src/main/java/emu/grasscutter/game/managers/MultiplayerSystem.java @@ -89,11 +89,11 @@ public class MultiplayerSystem extends BaseGameSystem { world.addPlayer(hostPlayer); // Rejoin packet - hostPlayer.sendPacket(new PacketPlayerEnterSceneNotify(hostPlayer, hostPlayer, EnterType.ENTER_TYPE_SELF, EnterReason.HostFromSingleToMp, hostPlayer.getScene().getId(), hostPlayer.getPos())); + hostPlayer.sendPacket(new PacketPlayerEnterSceneNotify(hostPlayer, hostPlayer, EnterType.ENTER_TYPE_SELF, EnterReason.HostFromSingleToMp, hostPlayer.getScene().getId(), hostPlayer.getPosition())); } // Set scene pos and id of requester to the host player's - requester.getPos().set(hostPlayer.getPos()); + requester.getPosition().set(hostPlayer.getPosition()); requester.getRotation().set(hostPlayer.getRotation()); requester.setSceneId(hostPlayer.getSceneId()); @@ -101,7 +101,7 @@ public class MultiplayerSystem extends BaseGameSystem { hostPlayer.getWorld().addPlayer(requester); // Packet - requester.sendPacket(new PacketPlayerEnterSceneNotify(requester, hostPlayer, EnterType.ENTER_TYPE_OTHER, EnterReason.TeamJoin, hostPlayer.getScene().getId(), hostPlayer.getPos())); + requester.sendPacket(new PacketPlayerEnterSceneNotify(requester, hostPlayer, EnterType.ENTER_TYPE_OTHER, EnterReason.TeamJoin, hostPlayer.getScene().getId(), hostPlayer.getPosition())); } public boolean leaveCoop(Player player) { @@ -122,7 +122,7 @@ public class MultiplayerSystem extends BaseGameSystem { world.addPlayer(player); // Packet - player.sendPacket(new PacketPlayerEnterSceneNotify(player, EnterType.ENTER_TYPE_SELF, EnterReason.TeamBack, player.getScene().getId(), player.getPos())); + player.sendPacket(new PacketPlayerEnterSceneNotify(player, EnterType.ENTER_TYPE_SELF, EnterReason.TeamBack, player.getScene().getId(), player.getPosition())); return true; } @@ -149,7 +149,7 @@ public class MultiplayerSystem extends BaseGameSystem { World world = new World(victim); world.addPlayer(victim); - victim.sendPacket(new PacketPlayerEnterSceneNotify(victim, EnterType.ENTER_TYPE_SELF, EnterReason.TeamKick, victim.getScene().getId(), victim.getPos())); + victim.sendPacket(new PacketPlayerEnterSceneNotify(victim, EnterType.ENTER_TYPE_SELF, EnterReason.TeamKick, victim.getScene().getId(), victim.getPosition())); return true; } } diff --git a/src/main/java/emu/grasscutter/game/managers/mapmark/MapMarksManager.java b/src/main/java/emu/grasscutter/game/managers/mapmark/MapMarksManager.java index dfde7a0e3..225aa834a 100644 --- a/src/main/java/emu/grasscutter/game/managers/mapmark/MapMarksManager.java +++ b/src/main/java/emu/grasscutter/game/managers/mapmark/MapMarksManager.java @@ -78,9 +78,9 @@ public class MapMarksManager extends BasePlayerManager { y = 300; } Position pos = mapMark.getPosition(); - player.getPos().set(pos.getX(), y, pos.getZ()); + player.getPosition().set(pos.getX(), y, pos.getZ()); if (mapMark.getSceneId() != player.getSceneId()) { - player.getWorld().transferPlayerToScene(player, mapMark.getSceneId(), player.getPos()); + player.getWorld().transferPlayerToScene(player, mapMark.getSceneId(), player.getPosition()); } player.getScene().broadcastPacket(new PacketSceneEntityAppearNotify(player)); } diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index bfc090b93..60a156465 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -97,7 +97,7 @@ public class Player { private String signature; private int headImage; private int nameCardId = 210001; - private Position pos; + private Position position; private Position rotation; private PlayerBirthday birthday; private PlayerCodex codex; @@ -200,7 +200,7 @@ public class Player { this.insectCaptureManager = new InsectCaptureManager(this); this.questManager = new QuestManager(this); - this.pos = new Position(); + this.position = new Position(); this.rotation = new Position(); this.properties = new HashMap<>(); for (PlayerProperty prop : PlayerProperty.values()) { @@ -272,7 +272,7 @@ public class Player { this.setProperty(PlayerProperty.PROP_PLAYER_RESIN, 160, false); this.getFlyCloakList().add(140001); this.getNameCardList().add(210001); - this.getPos().set(GameConstants.START_POSITION); + this.getPosition().set(GameConstants.START_POSITION); this.getRotation().set(0, 307, 0); this.messageHandler = null; this.mapMarksManager = new MapMarksManager(this); @@ -419,8 +419,8 @@ public class Player { this.currentRealmId = currentRealmId; } - public Position getPos() { - return pos; + public Position getPosition() { + return position; } public Position getRotation() { @@ -1182,7 +1182,7 @@ public class Player { public PlayerLocationInfo getPlayerLocationInfo() { return PlayerLocationInfo.newBuilder() .setUid(this.getUid()) - .setPos(this.getPos().toProto()) + .setPos(this.getPosition().toProto()) .setRot(this.getRotation().toProto()) .build(); } diff --git a/src/main/java/emu/grasscutter/game/player/TeamManager.java b/src/main/java/emu/grasscutter/game/player/TeamManager.java index cfb1abece..7fe31ab5a 100644 --- a/src/main/java/emu/grasscutter/game/player/TeamManager.java +++ b/src/main/java/emu/grasscutter/game/player/TeamManager.java @@ -662,7 +662,7 @@ public class TeamManager extends BasePlayerDataManager { // Set player position player.setSceneId(3); - player.getPos().set(GameConstants.START_POSITION); + player.getPosition().set(GameConstants.START_POSITION); // Packets getPlayer().sendPacket(new BasePacket(PacketOpcodes.WorldPlayerReviveRsp)); diff --git a/src/main/java/emu/grasscutter/game/world/Scene.java b/src/main/java/emu/grasscutter/game/world/Scene.java index 105e22ff6..85a571293 100644 --- a/src/main/java/emu/grasscutter/game/world/Scene.java +++ b/src/main/java/emu/grasscutter/game/world/Scene.java @@ -459,7 +459,7 @@ public class Scene { public synchronized void checkSpawns() { Set loadedGridBlocks = new HashSet<>(); for (Player player : this.getPlayers()) { - for (SpawnDataEntry.GridBlockId block : SpawnDataEntry.GridBlockId.getAdjacentGridBlockIds(player.getSceneId(), player.getPos())) + for (SpawnDataEntry.GridBlockId block : SpawnDataEntry.GridBlockId.getAdjacentGridBlockIds(player.getSceneId(), player.getPosition())) loadedGridBlocks.add(block); } if (this.loadedGridBlocks.containsAll(loadedGridBlocks)) { // Don't recalculate static spawns if nothing has changed @@ -555,7 +555,7 @@ public class Scene { public List getPlayerActiveBlocks(Player player){ // consider the borders' entities of blocks, so we check if contains by index return SceneIndexManager.queryNeighbors(getScriptManager().getBlocksIndex(), - player.getPos().toXZDoubleArray(), Grasscutter.getConfig().server.game.loadEntitiesForPlayerRange); + player.getPosition().toXZDoubleArray(), Grasscutter.getConfig().server.game.loadEntitiesForPlayerRange); } public void checkBlocks() { Set visible = new HashSet<>(); @@ -582,7 +582,7 @@ public class Scene { }else{ // dynamic load the groups for players in a loaded block var toLoad = this.getPlayers().stream() - .filter(p -> block.contains(p.getPos())) + .filter(p -> block.contains(p.getPosition())) .map(p -> playerMeetGroups(p, block)) .flatMap(Collection::stream) .toList(); @@ -592,7 +592,7 @@ public class Scene { } public List playerMeetGroups(Player player, SceneBlock block){ - List sceneGroups = SceneIndexManager.queryNeighbors(block.sceneGroupIndex, player.getPos().toDoubleArray(), + List sceneGroups = SceneIndexManager.queryNeighbors(block.sceneGroupIndex, player.getPosition().toDoubleArray(), Grasscutter.getConfig().server.game.loadEntitiesForPlayerRange); List groups = sceneGroups.stream() @@ -612,7 +612,7 @@ public class Scene { // the groups form here is not added in current scene var groups = players.stream() - .filter(player -> block.contains(player.getPos())) + .filter(player -> block.contains(player.getPosition())) .map(p -> playerMeetGroups(p, block)) .flatMap(Collection::stream) .toList(); @@ -774,7 +774,7 @@ public class Scene { this.npcBornEntrySet.addAll(loadNpcForPlayer(player)); } private List loadNpcForPlayer(Player player){ - var pos = player.getPos(); + var pos = player.getPosition(); var data = GameData.getSceneNpcBornData().get(getId()); if(data == null){ return List.of(); diff --git a/src/main/java/emu/grasscutter/game/world/World.java b/src/main/java/emu/grasscutter/game/world/World.java index 463523191..d4bdbfc83 100644 --- a/src/main/java/emu/grasscutter/game/world/World.java +++ b/src/main/java/emu/grasscutter/game/world/World.java @@ -193,7 +193,7 @@ public class World implements Iterable { World world = new World(victim); world.addPlayer(victim); - victim.sendPacket(new PacketPlayerEnterSceneNotify(victim, EnterType.ENTER_TYPE_SELF, EnterReason.TeamKick, victim.getSceneId(), victim.getPos())); + victim.sendPacket(new PacketPlayerEnterSceneNotify(victim, EnterType.ENTER_TYPE_SELF, EnterReason.TeamKick, victim.getSceneId(), victim.getPosition())); } } } @@ -249,10 +249,10 @@ public class World implements Iterable { // Set player position if (pos == null) { - pos = player.getPos(); + pos = player.getPosition(); } - player.getPos().set(pos); + player.getPosition().set(pos); if (oldScene != null) { newScene.setPrevScene(oldScene.getId()); diff --git a/src/main/java/emu/grasscutter/plugin/api/PlayerHook.java b/src/main/java/emu/grasscutter/plugin/api/PlayerHook.java index 0252b860d..5410241a3 100644 --- a/src/main/java/emu/grasscutter/plugin/api/PlayerHook.java +++ b/src/main/java/emu/grasscutter/plugin/api/PlayerHook.java @@ -39,7 +39,7 @@ public final class PlayerHook { * @param sceneId The scene to send the player to. */ public void changeScenes(int sceneId) { - this.player.getWorld().transferPlayerToScene(this.player, sceneId, this.player.getPos()); + this.player.getWorld().transferPlayerToScene(this.player, sceneId, this.player.getPosition()); } /** @@ -81,7 +81,7 @@ public final class PlayerHook { * @param position The position to teleport the player to. */ public void teleport(Position position) { - this.player.getPos().set(position); + this.player.getPosition().set(position); this.player.sendPacket(new PacketPlayerEnterSceneNotify(this.player, EnterType.ENTER_TYPE_JUMP, EnterReason.TransPoint, this.player.getSceneId(), position diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerEnterSceneNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerEnterSceneNotify.java index 44a4ca006..180fd2e7a 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerEnterSceneNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerEnterSceneNotify.java @@ -21,7 +21,7 @@ public class PacketPlayerEnterSceneNotify extends BasePacket { PlayerEnterSceneNotify proto = PlayerEnterSceneNotify.newBuilder() .setSceneId(player.getSceneId()) - .setPos(player.getPos().toProto()) + .setPos(player.getPosition().toProto()) .setSceneBeginTime(System.currentTimeMillis()) .setType(EnterType.ENTER_TYPE_SELF) .setTargetUid(player.getUid()) @@ -48,7 +48,7 @@ public class PacketPlayerEnterSceneNotify extends BasePacket { PlayerEnterSceneNotify.Builder proto = PlayerEnterSceneNotify.newBuilder() .setPrevSceneId(player.getSceneId()) - .setPrevPos(player.getPos().toProto()) + .setPrevPos(player.getPosition().toProto()) .setSceneId(newScene) .setPos(newPos.toProto()) .setSceneBeginTime(System.currentTimeMillis()) From 1a2f7fb5a798156b283ec57cc4723791ca4a2970 Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Tue, 19 Jul 2022 02:36:19 -0700 Subject: [PATCH 27/61] Forgot to remove extra player variable from `AbilityManager` --- .../game/ability/AbilityManager.java | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/src/main/java/emu/grasscutter/game/ability/AbilityManager.java b/src/main/java/emu/grasscutter/game/ability/AbilityManager.java index 1464e5717..d59b8b0f1 100644 --- a/src/main/java/emu/grasscutter/game/ability/AbilityManager.java +++ b/src/main/java/emu/grasscutter/game/ability/AbilityManager.java @@ -1,30 +1,15 @@ package emu.grasscutter.game.ability; -import java.util.*; -import java.util.Optional; -import java.util.Map.Entry; - import com.google.protobuf.InvalidProtocolBufferException; -import emu.grasscutter.Grasscutter; - import emu.grasscutter.data.GameData; import emu.grasscutter.data.binout.AbilityModifierEntry; import emu.grasscutter.data.binout.AbilityModifier.AbilityModifierAction; -import emu.grasscutter.data.excels.AvatarSkillDepotData; -import emu.grasscutter.data.excels.ItemData; -import emu.grasscutter.game.avatar.Avatar; -import emu.grasscutter.game.entity.EntityAvatar; -import emu.grasscutter.game.entity.EntityClientGadget; import emu.grasscutter.game.entity.EntityGadget; -import emu.grasscutter.game.entity.EntityItem; import emu.grasscutter.game.entity.GameEntity; import emu.grasscutter.game.entity.gadget.GadgetGatherObject; -import emu.grasscutter.game.entity.gadget.GadgetGatherPoint; import emu.grasscutter.game.player.BasePlayerManager; import emu.grasscutter.game.player.Player; -import emu.grasscutter.game.props.ElementType; -import emu.grasscutter.net.proto.AbilityActionGenerateElemBallOuterClass.AbilityActionGenerateElemBall; import emu.grasscutter.net.proto.AbilityInvokeEntryHeadOuterClass.AbilityInvokeEntryHead; import emu.grasscutter.net.proto.AbilityInvokeEntryOuterClass.AbilityInvokeEntry; import emu.grasscutter.net.proto.AbilityMetaModifierChangeOuterClass.AbilityMetaModifierChange; @@ -32,12 +17,8 @@ import emu.grasscutter.net.proto.AbilityMetaReInitOverrideMapOuterClass.AbilityM import emu.grasscutter.net.proto.AbilityMixinCostStaminaOuterClass.AbilityMixinCostStamina; import emu.grasscutter.net.proto.AbilityScalarValueEntryOuterClass.AbilityScalarValueEntry; import emu.grasscutter.net.proto.ModifierActionOuterClass.ModifierAction; -import emu.grasscutter.utils.Position; -import emu.grasscutter.utils.Utils; -import emu.grasscutter.game.props.FightProperty; public class AbilityManager extends BasePlayerManager { - private Player player; HealAbilityManager healAbilityManager; public AbilityManager(Player player) { From 5feabc8f9a7c341d1d7f66a6a6b1b6e084a53f87 Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Tue, 19 Jul 2022 02:51:26 -0700 Subject: [PATCH 28/61] Add `Entity::OnInteract` --- .../grasscutter/game/entity/EntityGadget.java | 20 ++++++-- .../grasscutter/game/entity/EntityItem.java | 28 +++++++++++ .../game/entity/EntityMonster.java | 6 +++ .../game/entity/EntityVehicle.java | 6 +++ .../grasscutter/game/entity/GameEntity.java | 11 ++++ .../game/entity/gadget/GadgetChest.java | 7 +-- .../emu/grasscutter/game/player/Player.java | 50 +++---------------- .../emu/grasscutter/game/world/Scene.java | 30 +++++++---- 8 files changed, 97 insertions(+), 61 deletions(-) diff --git a/src/main/java/emu/grasscutter/game/entity/EntityGadget.java b/src/main/java/emu/grasscutter/game/entity/EntityGadget.java index fe2b60f75..2d84cafa4 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityGadget.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityGadget.java @@ -3,6 +3,7 @@ package emu.grasscutter.game.entity; import emu.grasscutter.data.GameData; import emu.grasscutter.data.excels.GadgetData; import emu.grasscutter.game.entity.gadget.*; +import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.EntityIdType; import emu.grasscutter.game.props.EntityType; import emu.grasscutter.game.props.LifeState; @@ -15,6 +16,7 @@ import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityIn import emu.grasscutter.net.proto.EntityClientDataOuterClass.EntityClientData; import emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo; import emu.grasscutter.net.proto.FightPropPairOuterClass.FightPropPair; +import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq; import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo; import emu.grasscutter.net.proto.PropPairOuterClass.PropPair; import emu.grasscutter.net.proto.ProtEntityTypeOuterClass.ProtEntityType; @@ -22,6 +24,7 @@ import emu.grasscutter.net.proto.SceneEntityAiInfoOuterClass.SceneEntityAiInfo; import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo; import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo; import emu.grasscutter.net.proto.VectorOuterClass.Vector; +import emu.grasscutter.net.proto.VisionTypeOuterClass.VisionType; import emu.grasscutter.scripts.constants.EventType; import emu.grasscutter.scripts.data.SceneGadget; import emu.grasscutter.scripts.data.ScriptArgs; @@ -150,6 +153,19 @@ public class EntityGadget extends EntityBaseGadget { if (this.fightProp == null) this.fightProp = new Int2FloatOpenHashMap(); return this.fightProp; } + + @Override + public void onInteract(Player player, GadgetInteractReq interactReq) { + if (this.getContent() == null) { + return; + } + + boolean shouldDelete = this.getContent().onInteract(player, interactReq); + + if (shouldDelete) { + this.getScene().killEntity(this); + } + } @Override public void onCreate() { @@ -213,8 +229,4 @@ public class EntityGadget extends EntityBaseGadget { return entityInfo.build(); } - public void die() { - getScene().broadcastPacket(new PacketLifeStateChangeNotify(this, LifeState.LIFE_DEAD)); - this.onDeath(0); - } } diff --git a/src/main/java/emu/grasscutter/game/entity/EntityItem.java b/src/main/java/emu/grasscutter/game/entity/EntityItem.java index 791b230a1..63817f7c1 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityItem.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityItem.java @@ -3,6 +3,7 @@ package emu.grasscutter.game.entity; import emu.grasscutter.data.excels.ItemData; import emu.grasscutter.game.inventory.GameItem; import emu.grasscutter.game.player.Player; +import emu.grasscutter.game.props.ActionReason; import emu.grasscutter.game.props.EntityIdType; import emu.grasscutter.game.props.PlayerProperty; import emu.grasscutter.game.world.Scene; @@ -12,6 +13,8 @@ import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityIn import emu.grasscutter.net.proto.EntityClientDataOuterClass.EntityClientData; import emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo; import emu.grasscutter.net.proto.GadgetBornTypeOuterClass.GadgetBornType; +import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq; +import emu.grasscutter.net.proto.InteractTypeOuterClass.InteractType; import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo; import emu.grasscutter.net.proto.PropPairOuterClass.PropPair; import emu.grasscutter.net.proto.ProtEntityTypeOuterClass.ProtEntityType; @@ -19,6 +22,7 @@ import emu.grasscutter.net.proto.SceneEntityAiInfoOuterClass.SceneEntityAiInfo; import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo; import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo; import emu.grasscutter.net.proto.VectorOuterClass.Vector; +import emu.grasscutter.server.packet.send.PacketGadgetInteractRsp; import emu.grasscutter.utils.Position; import emu.grasscutter.utils.ProtoHelper; import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap; @@ -99,6 +103,30 @@ public class EntityItem extends EntityBaseGadget { public boolean isShare() { return share; } + + @Override + public void onInteract(Player player, GadgetInteractReq interactReq) { + // check drop owner to avoid someone picked up item in others' world + if (!this.isShare()) { + int dropOwner = (int) (this.getGuid() >> 32); + if (dropOwner != player.getUid()) { + return; + } + } + + this.getScene().removeEntity(this); + GameItem item = new GameItem(this.getItemData(), this.getCount()); + + // Add to inventory + boolean success = player.getInventory().addItem(item, ActionReason.SubfieldDrop); + if (success) { + if (!this.isShare()) { // not shared drop + player.sendPacket(new PacketGadgetInteractRsp(this, InteractType.INTERACT_TYPE_PICK_ITEM)); + } else { + this.getScene().broadcastPacket(new PacketGadgetInteractRsp(this, InteractType.INTERACT_TYPE_PICK_ITEM)); + } + } + } @Override public SceneEntityInfo toProto() { diff --git a/src/main/java/emu/grasscutter/game/entity/EntityMonster.java b/src/main/java/emu/grasscutter/game/entity/EntityMonster.java index b8c47e3db..eacc0ca60 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityMonster.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityMonster.java @@ -16,6 +16,7 @@ import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityIn import emu.grasscutter.net.proto.EntityClientDataOuterClass.EntityClientData; import emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo; import emu.grasscutter.net.proto.FightPropPairOuterClass.FightPropPair; +import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq; import emu.grasscutter.net.proto.MonsterBornTypeOuterClass.MonsterBornType; import emu.grasscutter.net.proto.PropPairOuterClass.PropPair; import emu.grasscutter.net.proto.ProtEntityTypeOuterClass.ProtEntityType; @@ -112,6 +113,11 @@ public class EntityMonster extends GameEntity { this.poseId = poseId; } + @Override + public void onInteract(Player player, GadgetInteractReq interactReq) { + player.getInsectCaptureManager().arrestSmallCreature(this); + } + @Override public void onCreate() { // Lua event diff --git a/src/main/java/emu/grasscutter/game/entity/EntityVehicle.java b/src/main/java/emu/grasscutter/game/entity/EntityVehicle.java index ceab84bc3..a8381b8d8 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityVehicle.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityVehicle.java @@ -10,6 +10,7 @@ import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.Animat import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo; import emu.grasscutter.net.proto.EntityRendererChangedInfoOuterClass.EntityRendererChangedInfo; import emu.grasscutter.net.proto.FightPropPairOuterClass.*; +import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq; import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo; import emu.grasscutter.net.proto.PropPairOuterClass.PropPair; import emu.grasscutter.net.proto.ProtEntityTypeOuterClass.ProtEntityType; @@ -82,6 +83,11 @@ public class EntityVehicle extends EntityBaseGadget { public Position getRotation() { return this.rot; } + + @Override + public void onInteract(Player player, GadgetInteractReq interactReq) { + player.getInsectCaptureManager().arrestSmallCreature(this); + } @Override public SceneEntityInfo toProto() { diff --git a/src/main/java/emu/grasscutter/game/entity/GameEntity.java b/src/main/java/emu/grasscutter/game/entity/GameEntity.java index 21d8f8173..c571f54f0 100644 --- a/src/main/java/emu/grasscutter/game/entity/GameEntity.java +++ b/src/main/java/emu/grasscutter/game/entity/GameEntity.java @@ -3,12 +3,14 @@ package emu.grasscutter.game.entity; import java.util.HashMap; import java.util.Map; +import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.props.LifeState; import emu.grasscutter.game.world.Scene; import emu.grasscutter.game.world.SpawnDataEntry; import emu.grasscutter.game.world.World; import emu.grasscutter.net.proto.FightPropPairOuterClass.FightPropPair; +import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq; import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo; import emu.grasscutter.net.proto.MotionStateOuterClass.MotionState; import emu.grasscutter.net.proto.SceneEntityInfoOuterClass.SceneEntityInfo; @@ -228,6 +230,15 @@ public abstract class GameEntity { } } + /** + * Called when a player interacts with this entity + * @param player Player that is interacting with this entity + * @param interactReq Interact request protobuf data + */ + public void onInteract(Player player, GadgetInteractReq interactReq) { + + } + /** * Called when this entity is added to the world */ diff --git a/src/main/java/emu/grasscutter/game/entity/gadget/GadgetChest.java b/src/main/java/emu/grasscutter/game/entity/gadget/GadgetChest.java index 02da258fc..1fb146240 100644 --- a/src/main/java/emu/grasscutter/game/entity/gadget/GadgetChest.java +++ b/src/main/java/emu/grasscutter/game/entity/gadget/GadgetChest.java @@ -3,6 +3,7 @@ package emu.grasscutter.game.entity.gadget; import emu.grasscutter.Grasscutter; import emu.grasscutter.game.entity.EntityGadget; import emu.grasscutter.game.player.Player; +import emu.grasscutter.game.props.LifeState; import emu.grasscutter.net.proto.BossChestInfoOuterClass.BossChestInfo; import emu.grasscutter.net.proto.GadgetInteractReqOuterClass.GadgetInteractReq; import emu.grasscutter.net.proto.InterOpTypeOuterClass.InterOpType; @@ -11,6 +12,7 @@ import emu.grasscutter.net.proto.InteractTypeOuterClass.InteractType; import emu.grasscutter.net.proto.SceneGadgetInfoOuterClass.SceneGadgetInfo; import emu.grasscutter.scripts.constants.ScriptGadgetState; import emu.grasscutter.server.packet.send.PacketGadgetInteractRsp; +import emu.grasscutter.server.packet.send.PacketLifeStateChangeNotify; public class GadgetChest extends GadgetContent { @@ -31,14 +33,13 @@ public class GadgetChest extends GadgetContent { return false; }else{ var success = handler.onInteract(this, player); - if (!success){ + if (!success) { return false; } getGadget().updateState(ScriptGadgetState.ChestOpened); player.sendPacket(new PacketGadgetInteractRsp(this.getGadget(), InteractTypeOuterClass.InteractType.INTERACT_TYPE_OPEN_CHEST)); - // let the chest disappear - getGadget().die(); + return true; } } diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index 60a156465..013f96c9d 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -995,52 +995,14 @@ public class Player { return this.getMailHandler().replaceMailByIndex(index, message); } - - public void interactWith(int gadgetEntityId, GadgetInteractReq opType) { - GameEntity entity = getScene().getEntityById(gadgetEntityId); - if (entity == null) { + public void interactWith(int gadgetEntityId, GadgetInteractReq interactReq) { + GameEntity target = getScene().getEntityById(gadgetEntityId); + + if (target == null) { return; } - - // Handle - if (entity instanceof EntityItem drop) { - // Pick item - if (!drop.isShare()) // check drop owner to avoid someone picked up item in others' world - { - int dropOwner = (int)(drop.getGuid() >> 32); - if (dropOwner != getUid()) { - return; - } - } - entity.getScene().removeEntity(entity); - GameItem item = new GameItem(drop.getItemData(), drop.getCount()); - // Add to inventory - boolean success = getInventory().addItem(item, ActionReason.SubfieldDrop); - if (success) { - if (!drop.isShare()) { // not shared drop - this.sendPacket(new PacketGadgetInteractRsp(drop, InteractType.INTERACT_TYPE_PICK_ITEM)); - }else{ - this.getScene().broadcastPacket(new PacketGadgetInteractRsp(drop, InteractType.INTERACT_TYPE_PICK_ITEM)); - } - } - } else if (entity instanceof EntityGadget gadget) { - if (gadget.getContent() == null) { - return; - } - - boolean shouldDelete = gadget.getContent().onInteract(this, opType); - - if (shouldDelete) { - entity.getScene().removeEntity(entity, VisionType.VISION_TYPE_REMOVE); - } - } else if (entity instanceof EntityMonster monster) { - insectCaptureManager.arrestSmallCreature(monster); - } else if (entity instanceof EntityVehicle vehicle) {// try to arrest it, example: glowworm - insectCaptureManager.arrestSmallCreature(vehicle); - } else { - // Delete directly - entity.getScene().removeEntity(entity); - } + + target.onInteract(this, interactReq); } public void onPause() { diff --git a/src/main/java/emu/grasscutter/game/world/Scene.java b/src/main/java/emu/grasscutter/game/world/Scene.java index 85a571293..d13bc3ef9 100644 --- a/src/main/java/emu/grasscutter/game/world/Scene.java +++ b/src/main/java/emu/grasscutter/game/world/Scene.java @@ -379,19 +379,28 @@ public class Scene { // Sanity check target.damage(result.getDamage(), result.getAttackerId()); } + + public void killEntity(GameEntity target) { + killEntity(target, 0); + } public void killEntity(GameEntity target, int attackerId) { - GameEntity attacker = getEntityById(attackerId); - - //Check codex - if (attacker instanceof EntityClientGadget) { - var clientGadgetOwner = getEntityById(((EntityClientGadget) attacker).getOwnerEntityId()); - if(clientGadgetOwner instanceof EntityAvatar) { - ((EntityClientGadget) attacker).getOwner().getCodex().checkAnimal(target, CodexAnimalData.CodexAnimalUnlockCondition.CODEX_COUNT_TYPE_KILL); - } + GameEntity attacker = null; + + if (attackerId > 0) { + attacker = getEntityById(attackerId); } - else if (attacker instanceof EntityAvatar) { - ((EntityAvatar) attacker).getPlayer().getCodex().checkAnimal(target, CodexAnimalData.CodexAnimalUnlockCondition.CODEX_COUNT_TYPE_KILL); + + if (attacker != null) { + // Check codex + if (attacker instanceof EntityClientGadget gadgetAttacker) { + var clientGadgetOwner = getEntityById(gadgetAttacker.getOwnerEntityId()); + if (clientGadgetOwner instanceof EntityAvatar) { + ((EntityClientGadget) attacker).getOwner().getCodex().checkAnimal(target, CodexAnimalData.CodexAnimalUnlockCondition.CODEX_COUNT_TYPE_KILL); + } + } else if (attacker instanceof EntityAvatar avatarAttacker) { + avatarAttacker.getPlayer().getCodex().checkAnimal(target, CodexAnimalData.CodexAnimalUnlockCondition.CODEX_COUNT_TYPE_KILL); + } } // Packet @@ -402,6 +411,7 @@ public class Scene { getWorld().getServer().getDropSystem().callDrop((EntityMonster) target); } + // Remove entity from world this.removeEntity(target); // Death event From f020cefd8041e80d21005c66f7dd0e9abf6b1394 Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Tue, 19 Jul 2022 02:53:03 -0700 Subject: [PATCH 29/61] Set default player position to be the starting position --- .../java/emu/grasscutter/game/player/Player.java | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index 013f96c9d..c415cf7c7 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -199,9 +199,10 @@ public class Player { this.deforestationManager = new DeforestationManager(this); this.insectCaptureManager = new InsectCaptureManager(this); this.questManager = new QuestManager(this); - - this.position = new Position(); - this.rotation = new Position(); + this.position = new Position(GameConstants.START_POSITION); + this.rotation = new Position(0, 307, 0); + this.sceneId = 3; + this.regionId = 1; this.properties = new HashMap<>(); for (PlayerProperty prop : PlayerProperty.values()) { if (prop.getId() < 10000) { @@ -222,9 +223,6 @@ public class Player { this.unlockedFurnitureSuite = new HashSet<>(); this.activeForges = new ArrayList<>(); this.unlockedRecipies = new HashMap<>(); - - this.setSceneId(3); - this.setRegionId(1); this.sceneState = SceneLoadState.NONE; this.attackResults = new LinkedBlockingQueue<>(); @@ -272,8 +270,6 @@ public class Player { this.setProperty(PlayerProperty.PROP_PLAYER_RESIN, 160, false); this.getFlyCloakList().add(140001); this.getNameCardList().add(210001); - this.getPosition().set(GameConstants.START_POSITION); - this.getRotation().set(0, 307, 0); this.messageHandler = null; this.mapMarksManager = new MapMarksManager(this); this.staminaManager = new StaminaManager(this); From fc16f9d69484b91dd7702612012d2ef1bf9a4bb4 Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Tue, 19 Jul 2022 03:05:36 -0700 Subject: [PATCH 30/61] Refactor out `InsectCaptureManager` --- .../data/common/ItemParamData.java | 2 + .../excels/EnvAnimalGatherConfigData.java | 21 +++----- .../game/entity/EntityMonster.java | 17 ++++++- .../game/entity/EntityVehicle.java | 5 -- .../grasscutter/game/inventory/Inventory.java | 17 ++++++- .../game/managers/InsectCaptureManager.java | 50 ------------------- .../emu/grasscutter/game/player/Player.java | 3 -- 7 files changed, 41 insertions(+), 74 deletions(-) delete mode 100644 src/main/java/emu/grasscutter/game/managers/InsectCaptureManager.java diff --git a/src/main/java/emu/grasscutter/data/common/ItemParamData.java b/src/main/java/emu/grasscutter/data/common/ItemParamData.java index cc96240bb..229cbf7b9 100644 --- a/src/main/java/emu/grasscutter/data/common/ItemParamData.java +++ b/src/main/java/emu/grasscutter/data/common/ItemParamData.java @@ -2,6 +2,7 @@ package emu.grasscutter.data.common; import com.google.gson.annotations.SerializedName; +// Used in excels public class ItemParamData { @SerializedName(value="id", alternate={"itemId"}) private int id; @@ -10,6 +11,7 @@ public class ItemParamData { private int count; public ItemParamData() {} + public ItemParamData(int id, int count) { this.id = id; this.count = count; diff --git a/src/main/java/emu/grasscutter/data/excels/EnvAnimalGatherConfigData.java b/src/main/java/emu/grasscutter/data/excels/EnvAnimalGatherConfigData.java index e99d681e0..d169b3ef7 100644 --- a/src/main/java/emu/grasscutter/data/excels/EnvAnimalGatherConfigData.java +++ b/src/main/java/emu/grasscutter/data/excels/EnvAnimalGatherConfigData.java @@ -4,37 +4,32 @@ import java.util.List; import emu.grasscutter.data.GameResource; import emu.grasscutter.data.ResourceType; +import emu.grasscutter.data.common.ItemParamData; @ResourceType(name = "EnvAnimalGatherExcelConfigData.json", loadPriority = ResourceType.LoadPriority.LOW) public class EnvAnimalGatherConfigData extends GameResource { private int animalId; private String entityType; - private List gatherItemId; + private List gatherItemId; private String excludeWeathers; private int aliveTime; private int escapeTime; private int escapeRadius; + @Override public int getId() { return animalId; } + public int getAnimalId(){ return animalId; } + public String getEntityType(){ return entityType; } - public GatherItem gatherItem(){ - return gatherItemId.get(0); - } - public static class GatherItem{ - private int id; - private int count; - public int getId(){ - return id; - } - public int getCount(){ - return count; - } + + public ItemParamData getGatherItem() { + return gatherItemId.size() > 0 ? gatherItemId.get(0) : null; } } diff --git a/src/main/java/emu/grasscutter/game/entity/EntityMonster.java b/src/main/java/emu/grasscutter/game/entity/EntityMonster.java index eacc0ca60..2ff99bef4 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityMonster.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityMonster.java @@ -1,15 +1,22 @@ package emu.grasscutter.game.entity; +import emu.grasscutter.Grasscutter; import emu.grasscutter.data.GameData; +import emu.grasscutter.data.common.ItemParamData; import emu.grasscutter.data.common.PropGrowCurve; +import emu.grasscutter.data.excels.EnvAnimalGatherConfigData; +import emu.grasscutter.data.excels.ItemData; import emu.grasscutter.data.excels.MonsterCurveData; import emu.grasscutter.data.excels.MonsterData; +import emu.grasscutter.game.inventory.GameItem; import emu.grasscutter.game.player.Player; +import emu.grasscutter.game.props.ActionReason; import emu.grasscutter.game.props.EntityIdType; import emu.grasscutter.game.props.FightProperty; import emu.grasscutter.game.props.PlayerProperty; import emu.grasscutter.game.props.WatcherTriggerType; import emu.grasscutter.game.world.Scene; +import emu.grasscutter.net.proto.VisionTypeOuterClass; import emu.grasscutter.net.proto.AbilitySyncStateInfoOuterClass.AbilitySyncStateInfo; import emu.grasscutter.net.proto.AnimatorParameterValueInfoPairOuterClass.AnimatorParameterValueInfoPair; import emu.grasscutter.net.proto.EntityAuthorityInfoOuterClass.EntityAuthorityInfo; @@ -115,7 +122,15 @@ public class EntityMonster extends GameEntity { @Override public void onInteract(Player player, GadgetInteractReq interactReq) { - player.getInsectCaptureManager().arrestSmallCreature(this); + EnvAnimalGatherConfigData gatherData = GameData.getEnvAnimalGatherConfigDataMap().get(this.getMonsterData().getId()); + + if (gatherData == null) { + return; + } + + player.getInventory().addItem(gatherData.getGatherItem(), ActionReason.SubfieldDrop); + + this.getScene().killEntity(this); } @Override diff --git a/src/main/java/emu/grasscutter/game/entity/EntityVehicle.java b/src/main/java/emu/grasscutter/game/entity/EntityVehicle.java index a8381b8d8..16d8b1f6f 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityVehicle.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityVehicle.java @@ -84,11 +84,6 @@ public class EntityVehicle extends EntityBaseGadget { return this.rot; } - @Override - public void onInteract(Player player, GadgetInteractReq interactReq) { - player.getInsectCaptureManager().arrestSmallCreature(this); - } - @Override public SceneEntityInfo toProto() { diff --git a/src/main/java/emu/grasscutter/game/inventory/Inventory.java b/src/main/java/emu/grasscutter/game/inventory/Inventory.java index 15eb9710d..bdda8ac9f 100644 --- a/src/main/java/emu/grasscutter/game/inventory/Inventory.java +++ b/src/main/java/emu/grasscutter/game/inventory/Inventory.java @@ -77,6 +77,10 @@ public class Inventory extends BasePlayerManager implements Iterable { } public boolean addItem(int itemId, int count) { + return addItem(itemId, count, null); + } + + public boolean addItem(int itemId, int count, ActionReason reason) { ItemData itemData = GameData.getItemDataMap().get(itemId); if (itemData == null) { @@ -85,9 +89,9 @@ public class Inventory extends BasePlayerManager implements Iterable { GameItem item = new GameItem(itemData, count); - return addItem(item); + return addItem(item, reason); } - + public boolean addItem(GameItem item) { GameItem result = putItem(item); @@ -120,6 +124,15 @@ public class Inventory extends BasePlayerManager implements Iterable { return result; } + public boolean addItem(ItemParamData itemParam) { + return addItem(itemParam, null); + } + + public boolean addItem(ItemParamData itemParam, ActionReason reason) { + if (itemParam == null) return false; + return addItem(itemParam.getId(), itemParam.getCount(), reason); + } + public void addItems(Collection items) { this.addItems(items, null); } diff --git a/src/main/java/emu/grasscutter/game/managers/InsectCaptureManager.java b/src/main/java/emu/grasscutter/game/managers/InsectCaptureManager.java deleted file mode 100644 index 42a21bbb3..000000000 --- a/src/main/java/emu/grasscutter/game/managers/InsectCaptureManager.java +++ /dev/null @@ -1,50 +0,0 @@ -package emu.grasscutter.game.managers; - -import emu.grasscutter.Grasscutter; -import emu.grasscutter.data.GameData; -import emu.grasscutter.data.excels.EnvAnimalGatherConfigData; -import emu.grasscutter.data.excels.ItemData; -import emu.grasscutter.game.entity.EntityMonster; -import emu.grasscutter.game.entity.EntityVehicle; -import emu.grasscutter.game.entity.GameEntity; -import emu.grasscutter.game.inventory.GameItem; -import emu.grasscutter.game.player.BasePlayerManager; -import emu.grasscutter.game.player.Player; -import emu.grasscutter.game.props.ActionReason; -import emu.grasscutter.net.proto.VisionTypeOuterClass; - -public class InsectCaptureManager extends BasePlayerManager { - - public InsectCaptureManager(Player player) { - super(player); - } - - public void arrestSmallCreature(GameEntity entity) { - //System.out.println("arrestSmallCreature!"); - EnvAnimalGatherConfigData gather; - int thingId; - if (entity instanceof EntityMonster monster) { - thingId = monster.getMonsterData().getId(); - gather = GameData.getEnvAnimalGatherConfigDataMap().get(thingId); - } else if (entity instanceof EntityVehicle gadget) { - thingId = gadget.getGadgetId(); - gather = GameData.getEnvAnimalGatherConfigDataMap().get(thingId); - } else { - return; - } - if (gather == null) { - Grasscutter.getLogger().warn("monster/gather(id={}) couldn't be caught.", thingId); - return; - } - String type = gather.getEntityType(); - if ((type.equals("Monster") && entity instanceof EntityMonster) || (type.equals("Gadget") && entity instanceof EntityVehicle)) { - EnvAnimalGatherConfigData.GatherItem gatherItem = gather.gatherItem(); - ItemData data = GameData.getItemDataMap().get(gatherItem.getId()); - GameItem item = new GameItem(data, gatherItem.getCount()); - player.getInventory().addItem(item, ActionReason.SubfieldDrop); - entity.getScene().removeEntity(entity, VisionTypeOuterClass.VisionType.VISION_TYPE_REMOVE); - } else { - Grasscutter.getLogger().warn("monster/gather(id={}) has a wrong type.", thingId); - } - } -} diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index c415cf7c7..c718b0460 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -30,7 +30,6 @@ import emu.grasscutter.game.mail.Mail; import emu.grasscutter.game.mail.MailHandler; import emu.grasscutter.game.managers.CookingManager; import emu.grasscutter.game.managers.FurnitureManager; -import emu.grasscutter.game.managers.InsectCaptureManager; import emu.grasscutter.game.managers.ResinManager; import emu.grasscutter.game.managers.collection.CollectionRecordStore; import emu.grasscutter.game.managers.deforestation.DeforestationManager; @@ -142,7 +141,6 @@ public class Player { @Getter private transient QuestManager questManager; @Getter private transient TowerManager towerManager; @Getter private transient SotSManager sotsManager; - @Getter private transient InsectCaptureManager insectCaptureManager; @Getter private transient MapMarksManager mapMarksManager; @Getter private transient StaminaManager staminaManager; @Getter private transient EnergyManager energyManager; @@ -197,7 +195,6 @@ public class Player { this.towerManager = new TowerManager(this); this.abilityManager = new AbilityManager(this); this.deforestationManager = new DeforestationManager(this); - this.insectCaptureManager = new InsectCaptureManager(this); this.questManager = new QuestManager(this); this.position = new Position(GameConstants.START_POSITION); this.rotation = new Position(0, 307, 0); From abccec785bda2b6c5c891fd33e3ae27e50005ae5 Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Wed, 20 Jul 2022 02:01:19 -0700 Subject: [PATCH 31/61] Delete AccountManager.java This file was never used by anyone. RIP. --- .../grasscutter/game/managers/AccountManager.java | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 src/main/java/emu/grasscutter/game/managers/AccountManager.java diff --git a/src/main/java/emu/grasscutter/game/managers/AccountManager.java b/src/main/java/emu/grasscutter/game/managers/AccountManager.java deleted file mode 100644 index 68173dc1e..000000000 --- a/src/main/java/emu/grasscutter/game/managers/AccountManager.java +++ /dev/null @@ -1,15 +0,0 @@ -package emu.grasscutter.game.managers; - -import emu.grasscutter.server.game.GameServer; - -public class AccountManager { - private final GameServer server; - - public AccountManager(GameServer server) { - this.server = server; - } - - public GameServer getServer() { - return server; - } -} From f22b92b08fbc79436c10aa55c4ad40cfafe47dfd Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Wed, 20 Jul 2022 02:01:56 -0700 Subject: [PATCH 32/61] Add a `save()` function to player managers --- .../grasscutter/game/managers/mapmark/MapMarksManager.java | 4 ---- .../emu/grasscutter/game/player/BasePlayerManager.java | 7 +++++++ 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/main/java/emu/grasscutter/game/managers/mapmark/MapMarksManager.java b/src/main/java/emu/grasscutter/game/managers/mapmark/MapMarksManager.java index 225aa834a..703385bc6 100644 --- a/src/main/java/emu/grasscutter/game/managers/mapmark/MapMarksManager.java +++ b/src/main/java/emu/grasscutter/game/managers/mapmark/MapMarksManager.java @@ -66,10 +66,6 @@ public class MapMarksManager extends BasePlayerManager { } } - private void save() { - player.save(); - } - private void teleport(Player player, MapMark mapMark) { float y; try { diff --git a/src/main/java/emu/grasscutter/game/player/BasePlayerManager.java b/src/main/java/emu/grasscutter/game/player/BasePlayerManager.java index 24023f726..7508995c0 100644 --- a/src/main/java/emu/grasscutter/game/player/BasePlayerManager.java +++ b/src/main/java/emu/grasscutter/game/player/BasePlayerManager.java @@ -12,4 +12,11 @@ public abstract class BasePlayerManager { public Player getPlayer() { return this.player; } + + /** + * Saves the player to the database + */ + public void save() { + getPlayer().save(); + } } From 55541fa1da064b3be773e040c963e4d5f40c8d46 Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Wed, 20 Jul 2022 02:26:02 -0700 Subject: [PATCH 33/61] Add a `loadReader` helper function to DataLoader Also minor name changing on a few DataLoader methods --- .../java/emu/grasscutter/data/DataLoader.java | 30 +++++++++++++++---- .../emu/grasscutter/data/ResourceLoader.java | 4 +-- .../game/activity/ActivityManager.java | 5 ++-- .../game/combine/CombineManger.java | 2 +- .../emu/grasscutter/game/drop/DropSystem.java | 2 +- .../dungeons/challenge/DungeonChallenge.java | 2 +- .../game/expedition/ExpeditionSystem.java | 2 +- .../grasscutter/game/gacha/GachaSystem.java | 2 +- .../game/managers/AnnouncementSystem.java | 2 +- .../game/managers/energy/EnergyManager.java | 2 +- .../emu/grasscutter/game/shop/ShopSystem.java | 6 ++-- .../grasscutter/game/tower/TowerSystem.java | 2 +- .../game/world/WorldDataSystem.java | 5 ++-- .../java/emu/grasscutter/utils/Utils.java | 2 +- 14 files changed, 45 insertions(+), 23 deletions(-) diff --git a/src/main/java/emu/grasscutter/data/DataLoader.java b/src/main/java/emu/grasscutter/data/DataLoader.java index d03d3a612..5dee449ef 100644 --- a/src/main/java/emu/grasscutter/data/DataLoader.java +++ b/src/main/java/emu/grasscutter/data/DataLoader.java @@ -8,7 +8,9 @@ import emu.grasscutter.utils.Utils; import java.io.FileInputStream; import java.io.FileNotFoundException; +import java.io.IOException; import java.io.InputStream; +import java.io.InputStreamReader; import java.nio.file.Path; import java.util.List; @@ -27,6 +29,24 @@ public class DataLoader { public static InputStream load(String resourcePath) throws FileNotFoundException { return load(resourcePath, true); } + + /** + * Creates an input stream reader for a data file. If the file isn't found within the /data directory then it will fallback to the default within the jar resources + * + * @param resourcePath The path to the data file to be loaded. + * @return InputStreamReader of the data file. + * @throws IOException + * @throws FileNotFoundException + * @see #load(String, boolean) + */ + public static InputStreamReader loadReader(String resourcePath) throws IOException, FileNotFoundException { + try { + InputStream is = load(resourcePath, true); + return new InputStreamReader(is); + } catch (FileNotFoundException exception) { + throw exception; + } + } /** * Load a data file by its name. @@ -49,7 +69,7 @@ public class DataLoader { return null; } - public static void CheckAllFiles() { + public static void checkAllFiles() { try { List filenames = FileUtils.getPathsFromResource("/defaults/data/"); @@ -58,16 +78,16 @@ public class DataLoader { } else for (Path file : filenames) { String relativePath = String.valueOf(file).split("defaults[\\\\\\/]data[\\\\\\/]")[1]; - CheckAndCopyData(relativePath); + checkAndCopyData(relativePath); } } catch (Exception e) { Grasscutter.getLogger().error("An error occurred while trying to check the data folder.", e); } - GenerateGachaMappings(); + generateGachaMappings(); } - private static void CheckAndCopyData(String name) { + private static void checkAndCopyData(String name) { String filePath = Utils.toFilePath(DATA(name)); if (!Utils.fileExists(filePath)) { @@ -93,7 +113,7 @@ public class DataLoader { } } - private static void GenerateGachaMappings() { + private static void generateGachaMappings() { if (!Utils.fileExists(GachaHandler.gachaMappings)) { try { Grasscutter.getLogger().info("Creating default '" + GachaHandler.gachaMappings + "' data"); diff --git a/src/main/java/emu/grasscutter/data/ResourceLoader.java b/src/main/java/emu/grasscutter/data/ResourceLoader.java index 5d93b7245..763fb7281 100644 --- a/src/main/java/emu/grasscutter/data/ResourceLoader.java +++ b/src/main/java/emu/grasscutter/data/ResourceLoader.java @@ -312,9 +312,9 @@ public class ResourceLoader { for (String name : spawnDataNames) { // Load spawn entries from file - try (InputStream spawnDataEntries = DataLoader.load(name)) { + try (InputStreamReader reader = DataLoader.loadReader(name)) { Type type = TypeToken.getParameterized(Collection.class, SpawnGroupEntry.class).getType(); - List list = Grasscutter.getGsonFactory().fromJson(new InputStreamReader(spawnDataEntries), type); + List list = Grasscutter.getGsonFactory().fromJson(reader, type); // Add spawns to group if it already exists in our spawn group map spawnEntryMap.addAll(list); diff --git a/src/main/java/emu/grasscutter/game/activity/ActivityManager.java b/src/main/java/emu/grasscutter/game/activity/ActivityManager.java index b3cdb024a..f1c86b812 100644 --- a/src/main/java/emu/grasscutter/game/activity/ActivityManager.java +++ b/src/main/java/emu/grasscutter/game/activity/ActivityManager.java @@ -16,6 +16,7 @@ import org.reflections.Reflections; import java.io.InputStream; import java.io.InputStreamReader; +import java.io.Reader; import java.util.*; import java.util.concurrent.ConcurrentHashMap; @@ -44,9 +45,9 @@ public class ActivityManager extends BasePlayerManager { activityWatcherTypeMap.put(typeName.value(), ConstructorAccess.get(item)); }); - try(InputStream is = DataLoader.load("ActivityConfig.json"); InputStreamReader isr = new InputStreamReader(is)) { + try(Reader reader = DataLoader.loadReader("ActivityConfig.json")) { List activities = Grasscutter.getGsonFactory().fromJson( - isr, + reader, TypeToken.getParameterized(List.class, ActivityConfigItem.class).getType()); diff --git a/src/main/java/emu/grasscutter/game/combine/CombineManger.java b/src/main/java/emu/grasscutter/game/combine/CombineManger.java index 555440a85..0ec9750dc 100644 --- a/src/main/java/emu/grasscutter/game/combine/CombineManger.java +++ b/src/main/java/emu/grasscutter/game/combine/CombineManger.java @@ -39,7 +39,7 @@ public class CombineManger extends BaseGameSystem { public static void initialize() { // Read the data we need for strongbox. - try (Reader fileReader = new InputStreamReader(DataLoader.load("ReliquaryDecompose.json"))) { + try (Reader fileReader = DataLoader.loadReader("ReliquaryDecompose.json")) { List decomposeEntries = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, ReliquaryDecomposeEntry.class).getType()); for (ReliquaryDecomposeEntry entry : decomposeEntries) { diff --git a/src/main/java/emu/grasscutter/game/drop/DropSystem.java b/src/main/java/emu/grasscutter/game/drop/DropSystem.java index 4e94bfe98..2917df436 100644 --- a/src/main/java/emu/grasscutter/game/drop/DropSystem.java +++ b/src/main/java/emu/grasscutter/game/drop/DropSystem.java @@ -38,7 +38,7 @@ public class DropSystem extends BaseGameSystem { } public synchronized void load() { - try (Reader fileReader = new InputStreamReader(DataLoader.load("Drop.json"))) { + try (Reader fileReader = DataLoader.loadReader("Drop.json")) { getDropData().clear(); List banners = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, DropInfo.class).getType()); if(banners.size() > 0) { diff --git a/src/main/java/emu/grasscutter/game/dungeons/challenge/DungeonChallenge.java b/src/main/java/emu/grasscutter/game/dungeons/challenge/DungeonChallenge.java index 392d40455..5093b8665 100644 --- a/src/main/java/emu/grasscutter/game/dungeons/challenge/DungeonChallenge.java +++ b/src/main/java/emu/grasscutter/game/dungeons/challenge/DungeonChallenge.java @@ -46,7 +46,7 @@ public class DungeonChallenge extends WorldChallenge { public static void initialize() { // Read the data we need for dungeon rewards drops. - try (Reader fileReader = new InputStreamReader(DataLoader.load("DungeonDrop.json"))) { + try (Reader fileReader = DataLoader.loadReader("DungeonDrop.json")) { List dungeonDropList = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, DungeonDrop.class).getType()); for (DungeonDrop entry : dungeonDropList) { diff --git a/src/main/java/emu/grasscutter/game/expedition/ExpeditionSystem.java b/src/main/java/emu/grasscutter/game/expedition/ExpeditionSystem.java index 9dba624a6..01c18cca0 100644 --- a/src/main/java/emu/grasscutter/game/expedition/ExpeditionSystem.java +++ b/src/main/java/emu/grasscutter/game/expedition/ExpeditionSystem.java @@ -30,7 +30,7 @@ public class ExpeditionSystem extends BaseGameSystem { } public synchronized void load() { - try (Reader fileReader = new InputStreamReader(DataLoader.load("ExpeditionReward.json"))) { + try (Reader fileReader = DataLoader.loadReader("ExpeditionReward.json")) { getExpeditionRewardDataList().clear(); List banners = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, ExpeditionRewardInfo.class).getType()); if(banners.size() > 0) { diff --git a/src/main/java/emu/grasscutter/game/gacha/GachaSystem.java b/src/main/java/emu/grasscutter/game/gacha/GachaSystem.java index 6365561eb..ac513a1e7 100644 --- a/src/main/java/emu/grasscutter/game/gacha/GachaSystem.java +++ b/src/main/java/emu/grasscutter/game/gacha/GachaSystem.java @@ -76,7 +76,7 @@ public class GachaSystem extends BaseGameSystem { } public synchronized void load() { - try (Reader fileReader = new InputStreamReader(DataLoader.load("Banners.json"))) { + try (Reader fileReader = DataLoader.loadReader("Banners.json")) { getGachaBanners().clear(); List banners = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, GachaBanner.class).getType()); if(banners.size() > 0) { diff --git a/src/main/java/emu/grasscutter/game/managers/AnnouncementSystem.java b/src/main/java/emu/grasscutter/game/managers/AnnouncementSystem.java index 201079fa3..22f23ffcf 100644 --- a/src/main/java/emu/grasscutter/game/managers/AnnouncementSystem.java +++ b/src/main/java/emu/grasscutter/game/managers/AnnouncementSystem.java @@ -30,7 +30,7 @@ public class AnnouncementSystem extends BaseGameSystem { } private int loadConfig() { - try (var fileReader = new InputStreamReader(DataLoader.load("Announcement.json"))) { + try (var fileReader = DataLoader.loadReader("Announcement.json")) { List announceConfigItems = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(List.class, AnnounceConfigItem.class).getType()); diff --git a/src/main/java/emu/grasscutter/game/managers/energy/EnergyManager.java b/src/main/java/emu/grasscutter/game/managers/energy/EnergyManager.java index e688267d9..c509d85d1 100644 --- a/src/main/java/emu/grasscutter/game/managers/energy/EnergyManager.java +++ b/src/main/java/emu/grasscutter/game/managers/energy/EnergyManager.java @@ -62,7 +62,7 @@ public class EnergyManager extends BasePlayerManager { public static void initialize() { // Read the data we need for monster energy drops. - try (Reader fileReader = new InputStreamReader(DataLoader.load("EnergyDrop.json"))) { + try (Reader fileReader = DataLoader.loadReader("EnergyDrop.json")) { List energyDropList = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, EnergyDropEntry.class).getType()); for (EnergyDropEntry entry : energyDropList) { diff --git a/src/main/java/emu/grasscutter/game/shop/ShopSystem.java b/src/main/java/emu/grasscutter/game/shop/ShopSystem.java index d6afb07ab..2169a06eb 100644 --- a/src/main/java/emu/grasscutter/game/shop/ShopSystem.java +++ b/src/main/java/emu/grasscutter/game/shop/ShopSystem.java @@ -60,7 +60,7 @@ public class ShopSystem extends BaseGameSystem { } private void loadShop() { - try (Reader fileReader = new InputStreamReader(DataLoader.load("Shop.json"))) { + try (Reader fileReader = DataLoader.loadReader("Shop.json")) { getShopData().clear(); List banners = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, ShopTable.class).getType()); if(banners.size() > 0) { @@ -104,7 +104,7 @@ public class ShopSystem extends BaseGameSystem { } private void loadShopChest() { - try (Reader fileReader = new InputStreamReader(DataLoader.load("ShopChest.json"))) { + try (Reader fileReader = DataLoader.loadReader("ShopChest.json")) { getShopChestData().clear(); List shopChestTableList = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, ShopChestTable.class).getType()); if (shopChestTableList.size() > 0) { @@ -119,7 +119,7 @@ public class ShopSystem extends BaseGameSystem { } private void loadShopChestBatchUse() { - try (Reader fileReader = new InputStreamReader(DataLoader.load("ShopChestBatchUse.json"))) { + try (Reader fileReader = DataLoader.loadReader("ShopChestBatchUse.json")) { getShopChestBatchUseData().clear(); List shopChestBatchUseTableList = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, ShopChestBatchUseTable.class).getType()); if (shopChestBatchUseTableList.size() > 0) { diff --git a/src/main/java/emu/grasscutter/game/tower/TowerSystem.java b/src/main/java/emu/grasscutter/game/tower/TowerSystem.java index 206bab462..2b9b9e5af 100644 --- a/src/main/java/emu/grasscutter/game/tower/TowerSystem.java +++ b/src/main/java/emu/grasscutter/game/tower/TowerSystem.java @@ -25,7 +25,7 @@ public class TowerSystem extends BaseGameSystem { private TowerScheduleConfig towerScheduleConfig; public synchronized void load(){ - try (Reader fileReader = new InputStreamReader(DataLoader.load("TowerSchedule.json"))) { + try (Reader fileReader = DataLoader.loadReader("TowerSchedule.json")) { towerScheduleConfig = Grasscutter.getGsonFactory().fromJson(fileReader, TowerScheduleConfig.class); } catch (Exception e) { Grasscutter.getLogger().error("Unable to load tower schedule config.", e); diff --git a/src/main/java/emu/grasscutter/game/world/WorldDataSystem.java b/src/main/java/emu/grasscutter/game/world/WorldDataSystem.java index a4be78686..5ec06de79 100644 --- a/src/main/java/emu/grasscutter/game/world/WorldDataSystem.java +++ b/src/main/java/emu/grasscutter/game/world/WorldDataSystem.java @@ -19,6 +19,7 @@ import emu.grasscutter.server.game.GameServer; import java.io.InputStream; import java.io.InputStreamReader; +import java.io.Reader; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -41,9 +42,9 @@ public class WorldDataSystem extends BaseGameSystem { // set the special chest first chestInteractHandlerMap.put("SceneObj_Chest_Flora", new BossChestInteractHandler()); - try(InputStream is = DataLoader.load("ChestReward.json"); InputStreamReader isr = new InputStreamReader(is)) { + try(Reader reader = DataLoader.loadReader("ChestReward.json")) { List chestReward = Grasscutter.getGsonFactory().fromJson( - isr, + reader, TypeToken.getParameterized(List.class, ChestReward.class).getType()); chestReward.forEach(reward -> diff --git a/src/main/java/emu/grasscutter/utils/Utils.java b/src/main/java/emu/grasscutter/utils/Utils.java index 1c86b3d12..f379def58 100644 --- a/src/main/java/emu/grasscutter/utils/Utils.java +++ b/src/main/java/emu/grasscutter/utils/Utils.java @@ -191,7 +191,7 @@ public final class Utils { createFolder(dataFolder); // Make sure the data folder is populated, if there are any missing files copy them from resources - DataLoader.CheckAllFiles(); + DataLoader.checkAllFiles(); if(exit) System.exit(1); } From 408fa907285970224116b1a0332f272d47862ab3 Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Wed, 20 Jul 2022 02:29:51 -0700 Subject: [PATCH 34/61] Move config java files to their own package --- src/main/java/emu/grasscutter/Grasscutter.java | 6 +++--- .../java/emu/grasscutter/auth/DefaultAuthentication.java | 2 +- .../java/emu/grasscutter/auth/DefaultAuthenticators.java | 2 +- .../emu/grasscutter/command/commands/AccountCommand.java | 2 +- .../emu/grasscutter/command/commands/SpawnCommand.java | 2 +- .../java/emu/grasscutter/command/commands/TeamCommand.java | 5 +++-- .../emu/grasscutter/{utils => config}/ConfigContainer.java | 2 +- .../java/emu/grasscutter/{ => config}/Configuration.java | 6 ++---- src/main/java/emu/grasscutter/data/DataLoader.java | 4 ++-- src/main/java/emu/grasscutter/data/ResourceLoader.java | 2 +- .../java/emu/grasscutter/database/DatabaseManager.java | 4 ++-- src/main/java/emu/grasscutter/game/Account.java | 4 ++-- src/main/java/emu/grasscutter/game/avatar/Avatar.java | 4 ++-- .../emu/grasscutter/game/expedition/ExpeditionSystem.java | 4 ++-- src/main/java/emu/grasscutter/game/gacha/GachaBanner.java | 4 ++-- src/main/java/emu/grasscutter/game/gacha/GachaSystem.java | 4 ++-- .../java/emu/grasscutter/game/inventory/Inventory.java | 4 ++-- .../java/emu/grasscutter/game/managers/ResinManager.java | 4 ++-- .../emu/grasscutter/game/managers/chat/ChatManager.java | 5 +++-- .../grasscutter/game/managers/energy/EnergyManager.java | 4 ++-- .../grasscutter/game/managers/stamina/StaminaManager.java | 4 ++-- src/main/java/emu/grasscutter/game/player/Player.java | 4 ++-- src/main/java/emu/grasscutter/game/player/TeamInfo.java | 4 ++-- src/main/java/emu/grasscutter/game/player/TeamManager.java | 4 ++-- src/main/java/emu/grasscutter/game/shop/ShopSystem.java | 4 ++-- src/main/java/emu/grasscutter/game/tower/TowerSystem.java | 4 ++-- src/main/java/emu/grasscutter/plugin/Plugin.java | 4 ++-- src/main/java/emu/grasscutter/plugin/PluginManager.java | 5 +++-- src/main/java/emu/grasscutter/scripts/data/SceneBlock.java | 5 +++-- src/main/java/emu/grasscutter/scripts/data/SceneGroup.java | 5 +++-- src/main/java/emu/grasscutter/scripts/data/SceneMeta.java | 5 +++-- src/main/java/emu/grasscutter/server/game/GameServer.java | 2 +- .../grasscutter/server/game/GameServerPacketHandler.java | 4 ++-- src/main/java/emu/grasscutter/server/game/GameSession.java | 2 +- src/main/java/emu/grasscutter/server/http/HttpServer.java | 2 +- .../grasscutter/server/http/dispatch/RegionHandler.java | 3 +-- .../http/documentation/GachaMappingRequestHandler.java | 7 ++++--- .../server/http/documentation/HandbookRequestHandler.java | 2 +- .../server/http/documentation/RootRequestHandler.java | 2 +- .../server/http/handlers/AnnouncementsHandler.java | 4 ++-- .../emu/grasscutter/server/http/handlers/GachaHandler.java | 2 +- .../grasscutter/server/http/handlers/GenericHandler.java | 4 ++-- .../grasscutter/server/http/objects/HttpJsonResponse.java | 2 +- .../server/http/objects/WebStaticVersionResponse.java | 4 ++-- .../server/packet/recv/HandlerGetPlayerTokenReq.java | 6 +++--- .../server/packet/recv/HandlerPlayerLoginReq.java | 4 ++-- .../server/packet/recv/HandlerSetPlayerBornDataReq.java | 4 ++-- .../server/packet/recv/HandlerUnionCmdNotify.java | 4 ++-- .../server/packet/send/PacketGetPlayerFriendListRsp.java | 4 ++-- .../server/packet/send/PacketPlayerLoginRsp.java | 4 ++-- .../server/packet/send/PacketPlayerStoreNotify.java | 4 ++-- .../server/packet/send/PacketPullRecentChatRsp.java | 2 +- .../server/packet/send/PacketStoreWeightLimitNotify.java | 4 ++-- src/main/java/emu/grasscutter/tools/Tools.java | 2 +- src/main/java/emu/grasscutter/utils/Language.java | 5 +++-- src/main/java/emu/grasscutter/utils/Utils.java | 1 + 56 files changed, 106 insertions(+), 100 deletions(-) rename src/main/java/emu/grasscutter/{utils => config}/ConfigContainer.java (99%) rename src/main/java/emu/grasscutter/{ => config}/Configuration.java (96%) diff --git a/src/main/java/emu/grasscutter/Grasscutter.java b/src/main/java/emu/grasscutter/Grasscutter.java index 881a1d2ac..34bf4a582 100644 --- a/src/main/java/emu/grasscutter/Grasscutter.java +++ b/src/main/java/emu/grasscutter/Grasscutter.java @@ -11,6 +11,7 @@ import emu.grasscutter.auth.DefaultAuthentication; import emu.grasscutter.command.CommandMap; import emu.grasscutter.command.DefaultPermissionHandler; import emu.grasscutter.command.PermissionHandler; +import emu.grasscutter.config.ConfigContainer; import emu.grasscutter.data.ResourceLoader; import emu.grasscutter.database.DatabaseManager; import emu.grasscutter.plugin.PluginManager; @@ -26,7 +27,6 @@ import emu.grasscutter.server.http.handlers.GachaHandler; import emu.grasscutter.server.http.handlers.GenericHandler; import emu.grasscutter.server.http.handlers.LogHandler; import emu.grasscutter.tools.Tools; -import emu.grasscutter.utils.ConfigContainer; import emu.grasscutter.utils.Crypto; import emu.grasscutter.utils.Language; import emu.grasscutter.utils.Utils; @@ -43,8 +43,8 @@ import javax.annotation.Nullable; import java.io.*; import java.util.Calendar; -import static emu.grasscutter.Configuration.DATA; -import static emu.grasscutter.Configuration.SERVER; +import static emu.grasscutter.config.Configuration.DATA; +import static emu.grasscutter.config.Configuration.SERVER; import static emu.grasscutter.utils.Language.translate; public final class Grasscutter { diff --git a/src/main/java/emu/grasscutter/auth/DefaultAuthentication.java b/src/main/java/emu/grasscutter/auth/DefaultAuthentication.java index 51f0684ba..62d512ebd 100644 --- a/src/main/java/emu/grasscutter/auth/DefaultAuthentication.java +++ b/src/main/java/emu/grasscutter/auth/DefaultAuthentication.java @@ -6,7 +6,7 @@ import emu.grasscutter.game.Account; import emu.grasscutter.server.http.objects.ComboTokenResJson; import emu.grasscutter.server.http.objects.LoginResultJson; -import static emu.grasscutter.Configuration.ACCOUNT; +import static emu.grasscutter.config.Configuration.ACCOUNT; import static emu.grasscutter.utils.Language.translate; /** diff --git a/src/main/java/emu/grasscutter/auth/DefaultAuthenticators.java b/src/main/java/emu/grasscutter/auth/DefaultAuthenticators.java index 81b463046..6ac5f9fbb 100644 --- a/src/main/java/emu/grasscutter/auth/DefaultAuthenticators.java +++ b/src/main/java/emu/grasscutter/auth/DefaultAuthenticators.java @@ -15,7 +15,7 @@ import java.security.KeyFactory; import java.security.interfaces.RSAPrivateKey; import java.security.spec.PKCS8EncodedKeySpec; -import static emu.grasscutter.Configuration.*; +import static emu.grasscutter.config.Configuration.*; import static emu.grasscutter.utils.Language.translate; /** diff --git a/src/main/java/emu/grasscutter/command/commands/AccountCommand.java b/src/main/java/emu/grasscutter/command/commands/AccountCommand.java index 4f96b986f..3d622a505 100644 --- a/src/main/java/emu/grasscutter/command/commands/AccountCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/AccountCommand.java @@ -1,10 +1,10 @@ package emu.grasscutter.command.commands; import at.favre.lib.crypto.bcrypt.BCrypt; -import emu.grasscutter.Configuration; import emu.grasscutter.Grasscutter; import emu.grasscutter.command.Command; import emu.grasscutter.command.CommandHandler; +import emu.grasscutter.config.Configuration; import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.game.Account; import emu.grasscutter.game.player.Player; diff --git a/src/main/java/emu/grasscutter/command/commands/SpawnCommand.java b/src/main/java/emu/grasscutter/command/commands/SpawnCommand.java index 3a962cf28..1306991ef 100644 --- a/src/main/java/emu/grasscutter/command/commands/SpawnCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/SpawnCommand.java @@ -20,7 +20,7 @@ import javax.swing.text.html.parser.Entity; import java.util.List; import java.util.Random; -import static emu.grasscutter.Configuration.*; +import static emu.grasscutter.config.Configuration.*; import static emu.grasscutter.utils.Language.translate; @Command(label = "spawn", usage = "spawn [amount] [level(monster only)] [ (monster only, optional)]", aliases = {"drop"}, permission = "server.spawn", permissionTargeted = "server.spawn.others", description = "commands.spawn.description") diff --git a/src/main/java/emu/grasscutter/command/commands/TeamCommand.java b/src/main/java/emu/grasscutter/command/commands/TeamCommand.java index c425059f7..afcaa4a74 100644 --- a/src/main/java/emu/grasscutter/command/commands/TeamCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/TeamCommand.java @@ -6,11 +6,12 @@ import emu.grasscutter.game.player.Player; import emu.grasscutter.server.packet.send.PacketChangeMpTeamAvatarRsp; import java.util.List; + +import static emu.grasscutter.config.Configuration.*; + import java.util.ArrayList; import java.util.HashSet; -import static emu.grasscutter.Configuration.*; - @Command(label = "team", usage = "team [avatarId,...] [index|first|last|index-index,...]", permission = "player.team", permissionTargeted = "player.team.others", description = "commands.team.description") public final class TeamCommand implements CommandHandler { diff --git a/src/main/java/emu/grasscutter/utils/ConfigContainer.java b/src/main/java/emu/grasscutter/config/ConfigContainer.java similarity index 99% rename from src/main/java/emu/grasscutter/utils/ConfigContainer.java rename to src/main/java/emu/grasscutter/config/ConfigContainer.java index dd7002482..5049e3b20 100644 --- a/src/main/java/emu/grasscutter/utils/ConfigContainer.java +++ b/src/main/java/emu/grasscutter/config/ConfigContainer.java @@ -1,4 +1,4 @@ -package emu.grasscutter.utils; +package emu.grasscutter.config; import com.google.gson.JsonObject; import emu.grasscutter.Grasscutter; diff --git a/src/main/java/emu/grasscutter/Configuration.java b/src/main/java/emu/grasscutter/config/Configuration.java similarity index 96% rename from src/main/java/emu/grasscutter/Configuration.java rename to src/main/java/emu/grasscutter/config/Configuration.java index 486c5d33c..82c7b3f71 100644 --- a/src/main/java/emu/grasscutter/Configuration.java +++ b/src/main/java/emu/grasscutter/config/Configuration.java @@ -1,9 +1,7 @@ -package emu.grasscutter; - -import emu.grasscutter.utils.ConfigContainer; -import emu.grasscutter.utils.ConfigContainer.*; +package emu.grasscutter.config; import java.util.Locale; + import java.nio.file.Paths; import static emu.grasscutter.Grasscutter.config; diff --git a/src/main/java/emu/grasscutter/data/DataLoader.java b/src/main/java/emu/grasscutter/data/DataLoader.java index 5dee449ef..a006448f3 100644 --- a/src/main/java/emu/grasscutter/data/DataLoader.java +++ b/src/main/java/emu/grasscutter/data/DataLoader.java @@ -6,6 +6,8 @@ import emu.grasscutter.tools.Tools; import emu.grasscutter.utils.FileUtils; import emu.grasscutter.utils.Utils; +import static emu.grasscutter.config.Configuration.DATA; + import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; @@ -14,8 +16,6 @@ import java.io.InputStreamReader; import java.nio.file.Path; import java.util.List; -import static emu.grasscutter.Configuration.DATA; - public class DataLoader { /** diff --git a/src/main/java/emu/grasscutter/data/ResourceLoader.java b/src/main/java/emu/grasscutter/data/ResourceLoader.java index 763fb7281..70b006567 100644 --- a/src/main/java/emu/grasscutter/data/ResourceLoader.java +++ b/src/main/java/emu/grasscutter/data/ResourceLoader.java @@ -29,7 +29,7 @@ import emu.grasscutter.data.common.ScenePointConfig; import emu.grasscutter.game.world.SpawnDataEntry.*; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import static emu.grasscutter.Configuration.*; +import static emu.grasscutter.config.Configuration.*; import static emu.grasscutter.utils.Language.translate; public class ResourceLoader { diff --git a/src/main/java/emu/grasscutter/database/DatabaseManager.java b/src/main/java/emu/grasscutter/database/DatabaseManager.java index d0c322864..15d78eb51 100644 --- a/src/main/java/emu/grasscutter/database/DatabaseManager.java +++ b/src/main/java/emu/grasscutter/database/DatabaseManager.java @@ -1,5 +1,7 @@ package emu.grasscutter.database; +import static emu.grasscutter.config.Configuration.*; + import com.mongodb.MongoCommandException; import com.mongodb.client.MongoClient; import com.mongodb.client.MongoClients; @@ -26,8 +28,6 @@ import emu.grasscutter.game.player.Player; import emu.grasscutter.game.quest.GameMainQuest; import emu.grasscutter.game.quest.GameQuest; -import static emu.grasscutter.Configuration.*; - public final class DatabaseManager { private static Datastore gameDatastore; private static Datastore dispatchDatastore; diff --git a/src/main/java/emu/grasscutter/game/Account.java b/src/main/java/emu/grasscutter/game/Account.java index 8685a16e3..43f4efe5c 100644 --- a/src/main/java/emu/grasscutter/game/Account.java +++ b/src/main/java/emu/grasscutter/game/Account.java @@ -5,13 +5,13 @@ import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.utils.Crypto; import emu.grasscutter.utils.Utils; +import static emu.grasscutter.config.Configuration.*; + import java.util.*; import java.util.stream.Stream; import org.bson.Document; -import static emu.grasscutter.Configuration.*; - @Entity(value = "accounts", useDiscriminator = false) public class Account { @Id private String id; diff --git a/src/main/java/emu/grasscutter/game/avatar/Avatar.java b/src/main/java/emu/grasscutter/game/avatar/Avatar.java index 92dd421ba..3ab2e1dc8 100644 --- a/src/main/java/emu/grasscutter/game/avatar/Avatar.java +++ b/src/main/java/emu/grasscutter/game/avatar/Avatar.java @@ -1,5 +1,7 @@ package emu.grasscutter.game.avatar; +import static emu.grasscutter.config.Configuration.GAME_OPTIONS; + import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -62,8 +64,6 @@ import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import static emu.grasscutter.Configuration.GAME_OPTIONS; - @Entity(value = "avatars", useDiscriminator = false) public class Avatar { @Id private ObjectId id; diff --git a/src/main/java/emu/grasscutter/game/expedition/ExpeditionSystem.java b/src/main/java/emu/grasscutter/game/expedition/ExpeditionSystem.java index 01c18cca0..0faca23b7 100644 --- a/src/main/java/emu/grasscutter/game/expedition/ExpeditionSystem.java +++ b/src/main/java/emu/grasscutter/game/expedition/ExpeditionSystem.java @@ -8,14 +8,14 @@ import emu.grasscutter.server.game.GameServer; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import static emu.grasscutter.config.Configuration.*; + import java.io.FileReader; import java.io.InputStreamReader; import java.io.Reader; import java.util.Collection; import java.util.List; -import static emu.grasscutter.Configuration.*; - public class ExpeditionSystem extends BaseGameSystem { private final Int2ObjectMap> expeditionRewardData; diff --git a/src/main/java/emu/grasscutter/game/gacha/GachaBanner.java b/src/main/java/emu/grasscutter/game/gacha/GachaBanner.java index dd68ad4af..4b8bd95c2 100644 --- a/src/main/java/emu/grasscutter/game/gacha/GachaBanner.java +++ b/src/main/java/emu/grasscutter/game/gacha/GachaBanner.java @@ -1,5 +1,7 @@ package emu.grasscutter.game.gacha; +import static emu.grasscutter.config.Configuration.*; + import emu.grasscutter.data.common.ItemParamData; import emu.grasscutter.game.player.Player; import emu.grasscutter.net.proto.GachaInfoOuterClass.GachaInfo; @@ -7,8 +9,6 @@ import emu.grasscutter.net.proto.GachaUpInfoOuterClass.GachaUpInfo; import emu.grasscutter.utils.Utils; import lombok.Getter; -import static emu.grasscutter.Configuration.*; - public class GachaBanner { @Getter private int gachaType; @Getter private int scheduleId; diff --git a/src/main/java/emu/grasscutter/game/gacha/GachaSystem.java b/src/main/java/emu/grasscutter/game/gacha/GachaSystem.java index ac513a1e7..c1c591584 100644 --- a/src/main/java/emu/grasscutter/game/gacha/GachaSystem.java +++ b/src/main/java/emu/grasscutter/game/gacha/GachaSystem.java @@ -1,5 +1,7 @@ package emu.grasscutter.game.gacha; +import static emu.grasscutter.config.Configuration.*; + import java.io.File; import java.io.FileReader; import java.io.InputStreamReader; @@ -45,8 +47,6 @@ import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; import org.greenrobot.eventbus.Subscribe; -import static emu.grasscutter.Configuration.*; - public class GachaSystem extends BaseGameSystem { private final Int2ObjectMap gachaBanners; private WatchService watchService; diff --git a/src/main/java/emu/grasscutter/game/inventory/Inventory.java b/src/main/java/emu/grasscutter/game/inventory/Inventory.java index bdda8ac9f..b2ee9aebf 100644 --- a/src/main/java/emu/grasscutter/game/inventory/Inventory.java +++ b/src/main/java/emu/grasscutter/game/inventory/Inventory.java @@ -1,5 +1,7 @@ package emu.grasscutter.game.inventory; +import static emu.grasscutter.config.Configuration.*; + import java.util.Collection; import java.util.Iterator; import java.util.LinkedList; @@ -30,8 +32,6 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; -import static emu.grasscutter.Configuration.*; - public class Inventory extends BasePlayerManager implements Iterable { private final Long2ObjectMap store; private final Int2ObjectMap inventoryTypes; diff --git a/src/main/java/emu/grasscutter/game/managers/ResinManager.java b/src/main/java/emu/grasscutter/game/managers/ResinManager.java index 2fefe88e1..78f4b09fd 100644 --- a/src/main/java/emu/grasscutter/game/managers/ResinManager.java +++ b/src/main/java/emu/grasscutter/game/managers/ResinManager.java @@ -1,5 +1,7 @@ package emu.grasscutter.game.managers; +import static emu.grasscutter.config.Configuration.GAME_OPTIONS; + import emu.grasscutter.game.player.BasePlayerManager; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.PlayerProperty; @@ -8,8 +10,6 @@ import emu.grasscutter.server.packet.send.PacketPlayerPropNotify; import emu.grasscutter.server.packet.send.PacketResinChangeNotify; import emu.grasscutter.utils.Utils; -import static emu.grasscutter.Configuration.GAME_OPTIONS; - public class ResinManager extends BasePlayerManager { public ResinManager(Player player) { diff --git a/src/main/java/emu/grasscutter/game/managers/chat/ChatManager.java b/src/main/java/emu/grasscutter/game/managers/chat/ChatManager.java index d9d243dcd..66acd2e9a 100644 --- a/src/main/java/emu/grasscutter/game/managers/chat/ChatManager.java +++ b/src/main/java/emu/grasscutter/game/managers/chat/ChatManager.java @@ -12,13 +12,14 @@ import emu.grasscutter.server.packet.send.PacketPullRecentChatRsp; import emu.grasscutter.utils.Utils; import java.util.regex.Pattern; + +import static emu.grasscutter.config.Configuration.*; + import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; -import static emu.grasscutter.Configuration.*; - public class ChatManager implements ChatManagerHandler { static final String PREFIXES = "[/!]"; static final Pattern RE_PREFIXES = Pattern.compile(PREFIXES); diff --git a/src/main/java/emu/grasscutter/game/managers/energy/EnergyManager.java b/src/main/java/emu/grasscutter/game/managers/energy/EnergyManager.java index c509d85d1..710ec31a4 100644 --- a/src/main/java/emu/grasscutter/game/managers/energy/EnergyManager.java +++ b/src/main/java/emu/grasscutter/game/managers/energy/EnergyManager.java @@ -32,8 +32,6 @@ import it.unimi.dsi.fastutil.ints.Int2IntMap; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import static emu.grasscutter.Configuration.GAME_OPTIONS; - import java.io.InputStreamReader; import java.io.Reader; import java.util.Collection; @@ -42,6 +40,8 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.concurrent.ThreadLocalRandom; + +import static emu.grasscutter.config.Configuration.GAME_OPTIONS; import static java.util.Map.entry; import com.google.gson.reflect.TypeToken; diff --git a/src/main/java/emu/grasscutter/game/managers/stamina/StaminaManager.java b/src/main/java/emu/grasscutter/game/managers/stamina/StaminaManager.java index e72d737ec..b45fdac1f 100644 --- a/src/main/java/emu/grasscutter/game/managers/stamina/StaminaManager.java +++ b/src/main/java/emu/grasscutter/game/managers/stamina/StaminaManager.java @@ -22,9 +22,9 @@ import emu.grasscutter.server.packet.send.*; import emu.grasscutter.utils.Position; import org.jetbrains.annotations.NotNull; -import java.util.*; +import static emu.grasscutter.config.Configuration.GAME_OPTIONS; -import static emu.grasscutter.Configuration.GAME_OPTIONS; +import java.util.*; public class StaminaManager extends BasePlayerManager { diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index c718b0460..4172368e2 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -76,6 +76,8 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import lombok.Getter; +import static emu.grasscutter.config.Configuration.*; + import java.time.DayOfWeek; import java.time.Instant; import java.time.LocalDate; @@ -83,8 +85,6 @@ import java.time.ZoneId; import java.util.*; import java.util.concurrent.LinkedBlockingQueue; -import static emu.grasscutter.Configuration.*; - @Entity(value = "players", useDiscriminator = false) public class Player { @Id private int id; diff --git a/src/main/java/emu/grasscutter/game/player/TeamInfo.java b/src/main/java/emu/grasscutter/game/player/TeamInfo.java index 89383e486..b1f265339 100644 --- a/src/main/java/emu/grasscutter/game/player/TeamInfo.java +++ b/src/main/java/emu/grasscutter/game/player/TeamInfo.java @@ -1,13 +1,13 @@ package emu.grasscutter.game.player; +import static emu.grasscutter.config.Configuration.*; + import java.util.ArrayList; import java.util.List; import dev.morphia.annotations.Entity; import emu.grasscutter.game.avatar.Avatar; -import static emu.grasscutter.Configuration.*; - @Entity public class TeamInfo { private String name; diff --git a/src/main/java/emu/grasscutter/game/player/TeamManager.java b/src/main/java/emu/grasscutter/game/player/TeamManager.java index 7fe31ab5a..5281f85f5 100644 --- a/src/main/java/emu/grasscutter/game/player/TeamManager.java +++ b/src/main/java/emu/grasscutter/game/player/TeamManager.java @@ -1,5 +1,7 @@ package emu.grasscutter.game.player; +import static emu.grasscutter.config.Configuration.*; + import java.util.*; import dev.morphia.annotations.Entity; @@ -38,8 +40,6 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; -import static emu.grasscutter.Configuration.*; - @Entity public class TeamManager extends BasePlayerDataManager { @Transient private Player player; diff --git a/src/main/java/emu/grasscutter/game/shop/ShopSystem.java b/src/main/java/emu/grasscutter/game/shop/ShopSystem.java index 2169a06eb..8ad4fa657 100644 --- a/src/main/java/emu/grasscutter/game/shop/ShopSystem.java +++ b/src/main/java/emu/grasscutter/game/shop/ShopSystem.java @@ -12,6 +12,8 @@ import emu.grasscutter.utils.Utils; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import static emu.grasscutter.config.Configuration.*; + import java.io.FileReader; import java.io.InputStreamReader; import java.io.Reader; @@ -20,8 +22,6 @@ import java.util.Collection; import java.util.Iterator; import java.util.List; -import static emu.grasscutter.Configuration.*; - public class ShopSystem extends BaseGameSystem { private final Int2ObjectMap> shopData; private final List shopChestData; diff --git a/src/main/java/emu/grasscutter/game/tower/TowerSystem.java b/src/main/java/emu/grasscutter/game/tower/TowerSystem.java index 2b9b9e5af..2923dfd0b 100644 --- a/src/main/java/emu/grasscutter/game/tower/TowerSystem.java +++ b/src/main/java/emu/grasscutter/game/tower/TowerSystem.java @@ -7,14 +7,14 @@ import emu.grasscutter.data.excels.TowerScheduleData; import emu.grasscutter.server.game.BaseGameSystem; import emu.grasscutter.server.game.GameServer; +import static emu.grasscutter.config.Configuration.*; + import java.io.FileReader; import java.io.InputStreamReader; import java.io.Reader; import java.util.ArrayList; import java.util.List; -import static emu.grasscutter.Configuration.*; - public class TowerSystem extends BaseGameSystem { public TowerSystem(GameServer server) { diff --git a/src/main/java/emu/grasscutter/plugin/Plugin.java b/src/main/java/emu/grasscutter/plugin/Plugin.java index f322adc93..d14ad5c51 100644 --- a/src/main/java/emu/grasscutter/plugin/Plugin.java +++ b/src/main/java/emu/grasscutter/plugin/Plugin.java @@ -6,12 +6,12 @@ import emu.grasscutter.server.game.GameServer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import static emu.grasscutter.config.Configuration.*; + import java.io.File; import java.io.InputStream; import java.net.URLClassLoader; -import static emu.grasscutter.Configuration.*; - /** * The base class for all plugins to extend. */ diff --git a/src/main/java/emu/grasscutter/plugin/PluginManager.java b/src/main/java/emu/grasscutter/plugin/PluginManager.java index 4c7b0ac68..6de30da38 100644 --- a/src/main/java/emu/grasscutter/plugin/PluginManager.java +++ b/src/main/java/emu/grasscutter/plugin/PluginManager.java @@ -6,14 +6,15 @@ import emu.grasscutter.utils.Utils; import lombok.*; import javax.annotation.Nullable; + +import static emu.grasscutter.config.Configuration.PLUGIN; + import java.io.*; import java.lang.reflect.Method; import java.net.*; import java.util.*; import java.util.jar.*; -import static emu.grasscutter.Configuration.PLUGIN; - /** * Manages the server's plugins and the event system. */ diff --git a/src/main/java/emu/grasscutter/scripts/data/SceneBlock.java b/src/main/java/emu/grasscutter/scripts/data/SceneBlock.java index 5ec0a15db..48903f68b 100644 --- a/src/main/java/emu/grasscutter/scripts/data/SceneBlock.java +++ b/src/main/java/emu/grasscutter/scripts/data/SceneBlock.java @@ -13,11 +13,12 @@ import lombok.ToString; import javax.script.Bindings; import javax.script.CompiledScript; import javax.script.ScriptException; + +import static emu.grasscutter.config.Configuration.SCRIPT; + import java.util.Map; import java.util.stream.Collectors; -import static emu.grasscutter.Configuration.SCRIPT; - @ToString @Setter public class SceneBlock { diff --git a/src/main/java/emu/grasscutter/scripts/data/SceneGroup.java b/src/main/java/emu/grasscutter/scripts/data/SceneGroup.java index 417da4749..507f80c34 100644 --- a/src/main/java/emu/grasscutter/scripts/data/SceneGroup.java +++ b/src/main/java/emu/grasscutter/scripts/data/SceneGroup.java @@ -10,13 +10,14 @@ import org.luaj.vm2.LuaValue; import javax.script.Bindings; import javax.script.CompiledScript; import javax.script.ScriptException; + +import static emu.grasscutter.config.Configuration.SCRIPT; + import java.util.List; import java.util.Map; import java.util.Optional; import java.util.stream.Collectors; -import static emu.grasscutter.Configuration.SCRIPT; - @ToString @Setter public class SceneGroup { diff --git a/src/main/java/emu/grasscutter/scripts/data/SceneMeta.java b/src/main/java/emu/grasscutter/scripts/data/SceneMeta.java index 9d6cf1f1a..efb6744fe 100644 --- a/src/main/java/emu/grasscutter/scripts/data/SceneMeta.java +++ b/src/main/java/emu/grasscutter/scripts/data/SceneMeta.java @@ -11,12 +11,13 @@ import lombok.ToString; import javax.script.Bindings; import javax.script.CompiledScript; import javax.script.ScriptException; + +import static emu.grasscutter.config.Configuration.SCRIPT; + import java.util.List; import java.util.Map; import java.util.stream.Collectors; -import static emu.grasscutter.Configuration.SCRIPT; - @ToString @Setter public class SceneMeta { diff --git a/src/main/java/emu/grasscutter/server/game/GameServer.java b/src/main/java/emu/grasscutter/server/game/GameServer.java index 5b53e31dc..84c4c2605 100644 --- a/src/main/java/emu/grasscutter/server/game/GameServer.java +++ b/src/main/java/emu/grasscutter/server/game/GameServer.java @@ -44,8 +44,8 @@ import java.time.OffsetDateTime; import java.util.*; import java.util.concurrent.ConcurrentHashMap; +import static emu.grasscutter.config.Configuration.*; import static emu.grasscutter.utils.Language.translate; -import static emu.grasscutter.Configuration.*; @Getter public final class GameServer extends KcpServer { diff --git a/src/main/java/emu/grasscutter/server/game/GameServerPacketHandler.java b/src/main/java/emu/grasscutter/server/game/GameServerPacketHandler.java index f0d2aaa40..e9c2be311 100644 --- a/src/main/java/emu/grasscutter/server/game/GameServerPacketHandler.java +++ b/src/main/java/emu/grasscutter/server/game/GameServerPacketHandler.java @@ -1,5 +1,7 @@ package emu.grasscutter.server.game; +import static emu.grasscutter.config.Configuration.*; + import java.util.Set; import emu.grasscutter.server.event.game.ReceivePacketEvent; @@ -14,8 +16,6 @@ import emu.grasscutter.server.game.GameSession.SessionState; import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; -import static emu.grasscutter.Configuration.*; - @SuppressWarnings("unchecked") public class GameServerPacketHandler { private final Int2ObjectMap handlers; diff --git a/src/main/java/emu/grasscutter/server/game/GameSession.java b/src/main/java/emu/grasscutter/server/game/GameSession.java index e2d726941..005fcc4af 100644 --- a/src/main/java/emu/grasscutter/server/game/GameSession.java +++ b/src/main/java/emu/grasscutter/server/game/GameSession.java @@ -17,8 +17,8 @@ import emu.grasscutter.utils.Utils; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; +import static emu.grasscutter.config.Configuration.*; import static emu.grasscutter.utils.Language.translate; -import static emu.grasscutter.Configuration.*; public class GameSession implements GameSessionManager.KcpChannel { private final GameServer server; diff --git a/src/main/java/emu/grasscutter/server/http/HttpServer.java b/src/main/java/emu/grasscutter/server/http/HttpServer.java index 34d2059a1..d35e7de25 100644 --- a/src/main/java/emu/grasscutter/server/http/HttpServer.java +++ b/src/main/java/emu/grasscutter/server/http/HttpServer.java @@ -13,7 +13,7 @@ import org.eclipse.jetty.util.ssl.SslContextFactory; import java.io.File; import java.io.UnsupportedEncodingException; -import static emu.grasscutter.Configuration.*; +import static emu.grasscutter.config.Configuration.*; import static emu.grasscutter.utils.Language.translate; /** diff --git a/src/main/java/emu/grasscutter/server/http/dispatch/RegionHandler.java b/src/main/java/emu/grasscutter/server/http/dispatch/RegionHandler.java index 336bda588..e9af92cb3 100644 --- a/src/main/java/emu/grasscutter/server/http/dispatch/RegionHandler.java +++ b/src/main/java/emu/grasscutter/server/http/dispatch/RegionHandler.java @@ -29,8 +29,7 @@ import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.security.Signature; - -import static emu.grasscutter.Configuration.*; +import static emu.grasscutter.config.Configuration.*; import static emu.grasscutter.net.proto.QueryRegionListHttpRspOuterClass.QueryRegionListHttpRsp; /** diff --git a/src/main/java/emu/grasscutter/server/http/documentation/GachaMappingRequestHandler.java b/src/main/java/emu/grasscutter/server/http/documentation/GachaMappingRequestHandler.java index 4810978ad..8457b7e0e 100644 --- a/src/main/java/emu/grasscutter/server/http/documentation/GachaMappingRequestHandler.java +++ b/src/main/java/emu/grasscutter/server/http/documentation/GachaMappingRequestHandler.java @@ -1,16 +1,17 @@ package emu.grasscutter.server.http.documentation; -import static emu.grasscutter.Configuration.RESOURCE; - import com.google.gson.reflect.TypeToken; import emu.grasscutter.Grasscutter; import emu.grasscutter.data.GameData; import emu.grasscutter.data.excels.AvatarData; import emu.grasscutter.data.excels.ItemData; import emu.grasscutter.utils.Utils; -import static emu.grasscutter.Configuration.DOCUMENT_LANGUAGE; import express.http.Request; import express.http.Response; + +import static emu.grasscutter.config.Configuration.DOCUMENT_LANGUAGE; +import static emu.grasscutter.config.Configuration.RESOURCE; + import java.io.FileInputStream; import java.io.IOException; import java.io.InputStreamReader; diff --git a/src/main/java/emu/grasscutter/server/http/documentation/HandbookRequestHandler.java b/src/main/java/emu/grasscutter/server/http/documentation/HandbookRequestHandler.java index 8153368a0..5968e64c4 100644 --- a/src/main/java/emu/grasscutter/server/http/documentation/HandbookRequestHandler.java +++ b/src/main/java/emu/grasscutter/server/http/documentation/HandbookRequestHandler.java @@ -1,6 +1,6 @@ package emu.grasscutter.server.http.documentation; -import static emu.grasscutter.Configuration.*; +import static emu.grasscutter.config.Configuration.*; import static emu.grasscutter.utils.Language.translate; import com.google.gson.reflect.TypeToken; diff --git a/src/main/java/emu/grasscutter/server/http/documentation/RootRequestHandler.java b/src/main/java/emu/grasscutter/server/http/documentation/RootRequestHandler.java index 12b738bf3..7cf376979 100644 --- a/src/main/java/emu/grasscutter/server/http/documentation/RootRequestHandler.java +++ b/src/main/java/emu/grasscutter/server/http/documentation/RootRequestHandler.java @@ -1,6 +1,6 @@ package emu.grasscutter.server.http.documentation; -import static emu.grasscutter.Configuration.DATA; +import static emu.grasscutter.config.Configuration.DATA; import static emu.grasscutter.utils.Language.translate; import emu.grasscutter.Grasscutter; diff --git a/src/main/java/emu/grasscutter/server/http/handlers/AnnouncementsHandler.java b/src/main/java/emu/grasscutter/server/http/handlers/AnnouncementsHandler.java index 07790a641..f2c04be7e 100644 --- a/src/main/java/emu/grasscutter/server/http/handlers/AnnouncementsHandler.java +++ b/src/main/java/emu/grasscutter/server/http/handlers/AnnouncementsHandler.java @@ -12,6 +12,8 @@ import express.http.Request; import express.http.Response; import io.javalin.Javalin; +import static emu.grasscutter.config.Configuration.*; + import java.io.File; import java.io.FileInputStream; import java.io.IOException; @@ -19,8 +21,6 @@ import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.util.Objects; -import static emu.grasscutter.Configuration.*; - /** * Handles requests related to the announcements page. */ diff --git a/src/main/java/emu/grasscutter/server/http/handlers/GachaHandler.java b/src/main/java/emu/grasscutter/server/http/handlers/GachaHandler.java index 6032e774f..7c42555ae 100644 --- a/src/main/java/emu/grasscutter/server/http/handlers/GachaHandler.java +++ b/src/main/java/emu/grasscutter/server/http/handlers/GachaHandler.java @@ -22,7 +22,7 @@ import java.util.Arrays; import java.util.LinkedHashSet; import java.util.Set; -import static emu.grasscutter.Configuration.DATA; +import static emu.grasscutter.config.Configuration.DATA; import static emu.grasscutter.utils.Language.translate; /** diff --git a/src/main/java/emu/grasscutter/server/http/handlers/GenericHandler.java b/src/main/java/emu/grasscutter/server/http/handlers/GenericHandler.java index 5b3be8d8b..664bbed60 100644 --- a/src/main/java/emu/grasscutter/server/http/handlers/GenericHandler.java +++ b/src/main/java/emu/grasscutter/server/http/handlers/GenericHandler.java @@ -1,5 +1,7 @@ package emu.grasscutter.server.http.handlers; +import static emu.grasscutter.config.Configuration.ACCOUNT; + import emu.grasscutter.GameConstants; import emu.grasscutter.Grasscutter; import emu.grasscutter.server.http.objects.HttpJsonResponse; @@ -10,8 +12,6 @@ import express.http.Request; import express.http.Response; import io.javalin.Javalin; -import static emu.grasscutter.Configuration.ACCOUNT; - /** * Handles all generic, hard-coded responses. */ diff --git a/src/main/java/emu/grasscutter/server/http/objects/HttpJsonResponse.java b/src/main/java/emu/grasscutter/server/http/objects/HttpJsonResponse.java index 35ca9b006..b3603d94c 100644 --- a/src/main/java/emu/grasscutter/server/http/objects/HttpJsonResponse.java +++ b/src/main/java/emu/grasscutter/server/http/objects/HttpJsonResponse.java @@ -10,8 +10,8 @@ import express.http.HttpContextHandler; import express.http.Request; import express.http.Response; +import static emu.grasscutter.config.Configuration.*; import static emu.grasscutter.utils.Language.translate; -import static emu.grasscutter.Configuration.*; public final class HttpJsonResponse implements HttpContextHandler { private final String response; diff --git a/src/main/java/emu/grasscutter/server/http/objects/WebStaticVersionResponse.java b/src/main/java/emu/grasscutter/server/http/objects/WebStaticVersionResponse.java index 40a08ebd8..7577da5ca 100644 --- a/src/main/java/emu/grasscutter/server/http/objects/WebStaticVersionResponse.java +++ b/src/main/java/emu/grasscutter/server/http/objects/WebStaticVersionResponse.java @@ -10,11 +10,11 @@ import express.http.Request; import express.http.Response; import io.javalin.core.util.FileUtil; +import static emu.grasscutter.config.Configuration.DATA; + import java.io.IOException; import java.io.InputStream; -import static emu.grasscutter.Configuration.DATA; - public class WebStaticVersionResponse implements HttpContextHandler { @Override diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetPlayerTokenReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetPlayerTokenReq.java index 8d1615587..c73019a9a 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetPlayerTokenReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetPlayerTokenReq.java @@ -1,8 +1,5 @@ package emu.grasscutter.server.packet.recv; -import static emu.grasscutter.Configuration.ACCOUNT; -import static emu.grasscutter.Configuration.GAME_OPTIONS; - import emu.grasscutter.Grasscutter; import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.game.Account; @@ -21,6 +18,9 @@ import emu.grasscutter.utils.Utils; import javax.crypto.Cipher; +import static emu.grasscutter.config.Configuration.ACCOUNT; +import static emu.grasscutter.config.Configuration.GAME_OPTIONS; + import java.nio.ByteBuffer; import java.security.Signature; diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerLoginReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerLoginReq.java index 45810b16c..714d3161b 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerLoginReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerLoginReq.java @@ -1,5 +1,7 @@ package emu.grasscutter.server.packet.recv; +import static emu.grasscutter.config.Configuration.ACCOUNT; + import emu.grasscutter.Grasscutter; import emu.grasscutter.database.DatabaseHelper; import emu.grasscutter.game.player.Player; @@ -13,8 +15,6 @@ import emu.grasscutter.server.game.GameSession.SessionState; import emu.grasscutter.server.packet.send.PacketPlayerLoginRsp; import emu.grasscutter.server.packet.send.PacketTakeAchievementRewardReq; -import static emu.grasscutter.Configuration.ACCOUNT; - @Opcodes(PacketOpcodes.PlayerLoginReq) // Sends initial data packets public class HandlerPlayerLoginReq extends PacketHandler { diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetPlayerBornDataReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetPlayerBornDataReq.java index ddb2e8948..48ac9151f 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetPlayerBornDataReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetPlayerBornDataReq.java @@ -17,9 +17,9 @@ import emu.grasscutter.server.event.game.PlayerCreationEvent; import emu.grasscutter.server.game.GameSession; import emu.grasscutter.server.game.GameSession.SessionState; -import java.util.Arrays; +import static emu.grasscutter.config.Configuration.*; -import static emu.grasscutter.Configuration.*; +import java.util.Arrays; @Opcodes(PacketOpcodes.SetPlayerBornDataReq) public class HandlerSetPlayerBornDataReq extends PacketHandler { diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerUnionCmdNotify.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerUnionCmdNotify.java index a86ffb084..5c1d6c550 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerUnionCmdNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerUnionCmdNotify.java @@ -1,5 +1,7 @@ package emu.grasscutter.server.packet.recv; +import static emu.grasscutter.config.Configuration.SERVER; + import emu.grasscutter.Grasscutter; import emu.grasscutter.net.packet.Opcodes; import emu.grasscutter.net.packet.PacketOpcodes; @@ -9,8 +11,6 @@ import emu.grasscutter.net.packet.PacketHandler; import emu.grasscutter.server.game.GameSession; import emu.grasscutter.Grasscutter.ServerDebugMode; -import static emu.grasscutter.Configuration.SERVER; - @Opcodes(PacketOpcodes.UnionCmdNotify) public class HandlerUnionCmdNotify extends PacketHandler { @Override diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketGetPlayerFriendListRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketGetPlayerFriendListRsp.java index 7bea1374a..97a7d4a97 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketGetPlayerFriendListRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketGetPlayerFriendListRsp.java @@ -1,5 +1,7 @@ package emu.grasscutter.server.packet.send; +import static emu.grasscutter.config.Configuration.*; + import emu.grasscutter.GameConstants; import emu.grasscutter.game.friends.Friendship; import emu.grasscutter.game.player.Player; @@ -11,8 +13,6 @@ import emu.grasscutter.net.proto.GetPlayerFriendListRspOuterClass.GetPlayerFrien import emu.grasscutter.net.proto.ProfilePictureOuterClass.ProfilePicture; import emu.grasscutter.net.proto.PlatformTypeOuterClass; -import static emu.grasscutter.Configuration.*; - public class PacketGetPlayerFriendListRsp extends BasePacket { public PacketGetPlayerFriendListRsp(Player player) { diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerLoginRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerLoginRsp.java index 52a487d55..a05075460 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerLoginRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerLoginRsp.java @@ -13,12 +13,12 @@ import emu.grasscutter.server.http.dispatch.RegionHandler; import emu.grasscutter.utils.Crypto; import emu.grasscutter.utils.FileUtils; +import static emu.grasscutter.config.Configuration.*; + import java.io.File; import java.util.Base64; import java.util.Objects; -import static emu.grasscutter.Configuration.*; - public class PacketPlayerLoginRsp extends BasePacket { private static QueryCurrRegionHttpRspOuterClass.QueryCurrRegionHttpRsp regionCache; diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerStoreNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerStoreNotify.java index 2a61aeda9..01c89a4ae 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerStoreNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerStoreNotify.java @@ -1,5 +1,7 @@ package emu.grasscutter.server.packet.send; +import static emu.grasscutter.config.Configuration.*; + import emu.grasscutter.game.inventory.GameItem; import emu.grasscutter.game.player.Player; import emu.grasscutter.net.packet.BasePacket; @@ -8,8 +10,6 @@ import emu.grasscutter.net.proto.ItemOuterClass.Item; import emu.grasscutter.net.proto.PlayerStoreNotifyOuterClass.PlayerStoreNotify; import emu.grasscutter.net.proto.StoreTypeOuterClass.StoreType; -import static emu.grasscutter.Configuration.*; - public class PacketPlayerStoreNotify extends BasePacket { public PacketPlayerStoreNotify(Player player) { diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketPullRecentChatRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketPullRecentChatRsp.java index 472075c76..ac846f8a9 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketPullRecentChatRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketPullRecentChatRsp.java @@ -8,7 +8,7 @@ import emu.grasscutter.net.proto.ChatInfoOuterClass.ChatInfo; import emu.grasscutter.net.proto.PullRecentChatRspOuterClass.PullRecentChatRsp; import emu.grasscutter.utils.Utils; -import static emu.grasscutter.Configuration.*; +import static emu.grasscutter.config.Configuration.*; import java.util.List; diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketStoreWeightLimitNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketStoreWeightLimitNotify.java index 17600932b..17ccf8865 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketStoreWeightLimitNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketStoreWeightLimitNotify.java @@ -1,12 +1,12 @@ package emu.grasscutter.server.packet.send; +import static emu.grasscutter.config.Configuration.*; + import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.proto.StoreTypeOuterClass.StoreType; import emu.grasscutter.net.proto.StoreWeightLimitNotifyOuterClass.StoreWeightLimitNotify; -import static emu.grasscutter.Configuration.*; - public class PacketStoreWeightLimitNotify extends BasePacket { public PacketStoreWeightLimitNotify() { diff --git a/src/main/java/emu/grasscutter/tools/Tools.java b/src/main/java/emu/grasscutter/tools/Tools.java index f6d425ee2..c473a145a 100644 --- a/src/main/java/emu/grasscutter/tools/Tools.java +++ b/src/main/java/emu/grasscutter/tools/Tools.java @@ -27,8 +27,8 @@ import emu.grasscutter.data.excels.QuestData; import emu.grasscutter.data.excels.SceneData; import emu.grasscutter.utils.Utils; +import static emu.grasscutter.config.Configuration.*; import static emu.grasscutter.utils.Language.translate; -import static emu.grasscutter.Configuration.*; public final class Tools { public static void createGmHandbook() throws Exception { diff --git a/src/main/java/emu/grasscutter/utils/Language.java b/src/main/java/emu/grasscutter/utils/Language.java index c343e949e..da022a25e 100644 --- a/src/main/java/emu/grasscutter/utils/Language.java +++ b/src/main/java/emu/grasscutter/utils/Language.java @@ -6,12 +6,13 @@ import emu.grasscutter.Grasscutter; import emu.grasscutter.game.player.Player; import javax.annotation.Nullable; + +import static emu.grasscutter.config.Configuration.*; + import java.io.InputStream; import java.util.concurrent.ConcurrentHashMap; import java.util.Map; -import static emu.grasscutter.Configuration.*; - public final class Language { private static final Map cachedLanguages = new ConcurrentHashMap<>(); diff --git a/src/main/java/emu/grasscutter/utils/Utils.java b/src/main/java/emu/grasscutter/utils/Utils.java index f379def58..c7bdad311 100644 --- a/src/main/java/emu/grasscutter/utils/Utils.java +++ b/src/main/java/emu/grasscutter/utils/Utils.java @@ -10,6 +10,7 @@ import java.util.*; import java.util.concurrent.ThreadLocalRandom; import emu.grasscutter.Grasscutter; +import emu.grasscutter.config.ConfigContainer; import emu.grasscutter.data.DataLoader; import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; From 52ee229e96f5785767cb63924c8449fc536e64cc Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Wed, 20 Jul 2022 02:52:35 -0700 Subject: [PATCH 35/61] Split config `debugLevel` into `logPackets` (Game) and `logRequests` (Dispatch) --- .../grasscutter/config/ConfigContainer.java | 16 +++-- .../server/game/GameServerPacketHandler.java | 2 +- .../grasscutter/server/game/GameSession.java | 63 +++++++++++-------- .../grasscutter/server/http/HttpServer.java | 4 +- .../server/http/objects/HttpJsonResponse.java | 4 +- .../objects/WebStaticVersionResponse.java | 3 +- .../packet/recv/HandlerUnionCmdNotify.java | 6 +- 7 files changed, 58 insertions(+), 40 deletions(-) diff --git a/src/main/java/emu/grasscutter/config/ConfigContainer.java b/src/main/java/emu/grasscutter/config/ConfigContainer.java index 5049e3b20..619775dc8 100644 --- a/src/main/java/emu/grasscutter/config/ConfigContainer.java +++ b/src/main/java/emu/grasscutter/config/ConfigContainer.java @@ -93,9 +93,8 @@ public class ConfigContainer { } public static class Server { - public ServerDebugMode debugLevel = ServerDebugMode.NONE; - public Set DebugWhitelist = Set.of(); - public Set DebugBlacklist = Set.of(); + public Set debugWhitelist = Set.of(); + public Set debugBlacklist = Set.of(); public ServerRunMode runMode = ServerRunMode.HYBRID; public HTTP http = new HTTP(); @@ -135,16 +134,21 @@ public class ConfigContainer { public static class Game { public String bindAddress = "0.0.0.0"; + public int bindPort = 22102; + /* This is the address used in the default region. */ public String accessAddress = "127.0.0.1"; - - public int bindPort = 22102; /* This is the port used in the default region. */ public int accessPort = 0; + /* Entities within a certain range will be loaded for the player */ public int loadEntitiesForPlayerRange = 100; public boolean enableScriptInBigWorld = false; public boolean enableConsole = true; + + /* Controls whether packets should be logged in console or not */ + public ServerDebugMode logPackets = ServerDebugMode.NONE; + public GameOptions gameOptions = new GameOptions(); public JoinOptions joinOptions = new JoinOptions(); public ConsoleAccount serverAccount = new ConsoleAccount(); @@ -156,6 +160,8 @@ public class ConfigContainer { public Region[] regions = {}; public String defaultName = "Grasscutter"; + + public ServerDebugMode logRequests = ServerDebugMode.NONE; } public static class Encryption { diff --git a/src/main/java/emu/grasscutter/server/game/GameServerPacketHandler.java b/src/main/java/emu/grasscutter/server/game/GameServerPacketHandler.java index e9c2be311..0f6998274 100644 --- a/src/main/java/emu/grasscutter/server/game/GameServerPacketHandler.java +++ b/src/main/java/emu/grasscutter/server/game/GameServerPacketHandler.java @@ -94,7 +94,7 @@ public class GameServerPacketHandler { } // Log unhandled packets - if (SERVER.debugLevel == ServerDebugMode.MISSING) { + if (GAME_INFO.logPackets == ServerDebugMode.MISSING) { Grasscutter.getLogger().info("Unhandled packet (" + opcode + "): " + emu.grasscutter.net.packet.PacketOpcodesUtil.getOpcodeName(opcode)); } } diff --git a/src/main/java/emu/grasscutter/server/game/GameSession.java b/src/main/java/emu/grasscutter/server/game/GameSession.java index 005fcc4af..096a3a35d 100644 --- a/src/main/java/emu/grasscutter/server/game/GameSession.java +++ b/src/main/java/emu/grasscutter/server/game/GameSession.java @@ -148,18 +148,23 @@ public class GameSession implements GameSessionManager.KcpChannel { } // Log - if (SERVER.debugLevel == ServerDebugMode.ALL) { - if (!loopPacket.contains(packet.getOpcode())) { - logPacket("SEND",packet.getOpcode(), packet.getData()); - } - } - - if (SERVER.debugLevel == ServerDebugMode.WHITELIST && SERVER.DebugWhitelist.contains(packet.getOpcode())) { - logPacket("SEND",packet.getOpcode(), packet.getData()); - } - - if (SERVER.debugLevel == ServerDebugMode.BLACKLIST && !(SERVER.DebugBlacklist.contains(packet.getOpcode()))) { - logPacket("SEND",packet.getOpcode(), packet.getData()); + switch (GAME_INFO.logPackets) { + case ALL -> { + if (!loopPacket.contains(packet.getOpcode())) { + logPacket("SEND", packet.getOpcode(), packet.getData()); + } + } + case WHITELIST-> { + if (SERVER.debugWhitelist.contains(packet.getOpcode())) { + logPacket("SEND", packet.getOpcode(), packet.getData()); + } + } + case BLACKLIST-> { + if (!SERVER.debugBlacklist.contains(packet.getOpcode())) { + logPacket("SEND", packet.getOpcode(), packet.getData()); + } + } + default -> {} } // Invoke event. @@ -194,7 +199,7 @@ public class GameSession implements GameSessionManager.KcpChannel { //logPacket(packet); // Handle try { - boolean allDebug = SERVER.debugLevel == ServerDebugMode.ALL; + boolean allDebug = GAME_INFO.logPackets == ServerDebugMode.ALL; while (packet.readableBytes() > 0) { // Length if (packet.readableBytes() < 12) { @@ -225,20 +230,26 @@ public class GameSession implements GameSessionManager.KcpChannel { } return; // Bad packet } + // Log packet - if (allDebug) { - if (!loopPacket.contains(opcode)) { - logPacket("RECV",opcode, payload); - } - } - - if (SERVER.debugLevel == ServerDebugMode.WHITELIST && SERVER.DebugWhitelist.contains(opcode)) { - logPacket("RECV",opcode, payload); - } - - if (SERVER.debugLevel == ServerDebugMode.BLACKLIST && !(SERVER.DebugBlacklist.contains(opcode))) { - logPacket("RECV",opcode, payload); - } + switch (GAME_INFO.logPackets) { + case ALL -> { + if (!loopPacket.contains(opcode)) { + logPacket("RECV",opcode, payload); + } + } + case WHITELIST-> { + if (SERVER.debugWhitelist.contains(opcode)) { + logPacket("RECV",opcode, payload); + } + } + case BLACKLIST-> { + if (!(SERVER.debugBlacklist.contains(opcode))) { + logPacket("RECV",opcode, payload); + } + } + default -> {} + } // Handle getServer().getPacketHandler().handle(this, opcode, header, payload); diff --git a/src/main/java/emu/grasscutter/server/http/HttpServer.java b/src/main/java/emu/grasscutter/server/http/HttpServer.java index d35e7de25..a4a0e704a 100644 --- a/src/main/java/emu/grasscutter/server/http/HttpServer.java +++ b/src/main/java/emu/grasscutter/server/http/HttpServer.java @@ -43,7 +43,7 @@ public final class HttpServer { } // Configure debug logging. - if(SERVER.debugLevel == ServerDebugMode.ALL) + if(DISPATCH_INFO.logRequests == ServerDebugMode.ALL) config.enableDevLogging(); // Disable compression on static files. @@ -173,7 +173,7 @@ public final class HttpServer { public static class UnhandledRequestRouter implements Router { @Override public void applyRoutes(Express express, Javalin handle) { handle.error(404, context -> { - if(SERVER.debugLevel == ServerDebugMode.MISSING) + if(DISPATCH_INFO.logRequests == ServerDebugMode.MISSING) Grasscutter.getLogger().info(translate("messages.dispatch.unhandled_request_error", context.method(), context.url())); context.contentType("text/html"); diff --git a/src/main/java/emu/grasscutter/server/http/objects/HttpJsonResponse.java b/src/main/java/emu/grasscutter/server/http/objects/HttpJsonResponse.java index b3603d94c..147259161 100644 --- a/src/main/java/emu/grasscutter/server/http/objects/HttpJsonResponse.java +++ b/src/main/java/emu/grasscutter/server/http/objects/HttpJsonResponse.java @@ -35,8 +35,8 @@ public final class HttpJsonResponse implements HttpContextHandler { @Override public void handle(Request req, Response res) throws IOException { // Checking for ALL here isn't required as when ALL is enabled enableDevLogging() gets enabled - if(SERVER.debugLevel == ServerDebugMode.MISSING && Arrays.stream(missingRoutes).anyMatch(x -> Objects.equals(x, req.baseUrl()))) { - Grasscutter.getLogger().info(translate("messages.dispatch.request", req.ip(), req.method(), req.baseUrl()) + (SERVER.debugLevel == ServerDebugMode.MISSING ? "(MISSING)" : "")); + if(DISPATCH_INFO.logRequests == ServerDebugMode.MISSING && Arrays.stream(missingRoutes).anyMatch(x -> Objects.equals(x, req.baseUrl()))) { + Grasscutter.getLogger().info(translate("messages.dispatch.request", req.ip(), req.method(), req.baseUrl()) + (DISPATCH_INFO.logRequests == ServerDebugMode.MISSING ? "(MISSING)" : "")); } res.send(response); } diff --git a/src/main/java/emu/grasscutter/server/http/objects/WebStaticVersionResponse.java b/src/main/java/emu/grasscutter/server/http/objects/WebStaticVersionResponse.java index 7577da5ca..111451bf8 100644 --- a/src/main/java/emu/grasscutter/server/http/objects/WebStaticVersionResponse.java +++ b/src/main/java/emu/grasscutter/server/http/objects/WebStaticVersionResponse.java @@ -11,6 +11,7 @@ import express.http.Response; import io.javalin.core.util.FileUtil; import static emu.grasscutter.config.Configuration.DATA; +import static emu.grasscutter.config.Configuration.DISPATCH_INFO; import java.io.IOException; import java.io.InputStream; @@ -32,7 +33,7 @@ public class WebStaticVersionResponse implements HttpContextHandler { response.type((fromExtension != null) ? fromExtension.getMIME() : "application/octet-stream"); response.send(filestream.readAllBytes()); } catch (Exception e) { - if(Grasscutter.getConfig().server.debugLevel.equals(Grasscutter.ServerDebugMode.MISSING)) { + if(DISPATCH_INFO.logRequests == Grasscutter.ServerDebugMode.MISSING) { Grasscutter.getLogger().warn("Webstatic File Missing: " + path); } response.status(404); diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerUnionCmdNotify.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerUnionCmdNotify.java index 5c1d6c550..9323ec5b6 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerUnionCmdNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerUnionCmdNotify.java @@ -1,8 +1,8 @@ package emu.grasscutter.server.packet.recv; +import static emu.grasscutter.config.Configuration.GAME_INFO; import static emu.grasscutter.config.Configuration.SERVER; -import emu.grasscutter.Grasscutter; import emu.grasscutter.net.packet.Opcodes; import emu.grasscutter.net.packet.PacketOpcodes; import emu.grasscutter.net.proto.UnionCmdNotifyOuterClass.UnionCmdNotify; @@ -19,9 +19,9 @@ public class HandlerUnionCmdNotify extends PacketHandler { for (UnionCmd cmd : req.getCmdListList()) { int cmdOpcode = cmd.getMessageId(); byte[] cmdPayload = cmd.getBody().toByteArray(); - if(Grasscutter.config.server.debugLevel == ServerDebugMode.WHITELIST && SERVER.DebugWhitelist.contains(cmd.getMessageId())) { + if(GAME_INFO.logPackets == ServerDebugMode.WHITELIST && SERVER.debugWhitelist.contains(cmd.getMessageId())) { session.logPacket("RECV in Union", cmdOpcode, cmdPayload); - } else if (Grasscutter.config.server.debugLevel == ServerDebugMode.BLACKLIST && !SERVER.DebugBlacklist.contains(cmd.getMessageId())) { + } else if (GAME_INFO.logPackets == ServerDebugMode.BLACKLIST && !SERVER.debugBlacklist.contains(cmd.getMessageId())) { session.logPacket("RECV in Union", cmdOpcode, cmdPayload); } //debugLevel ALL ignores UnionCmdNotify, so we will also ignore the contained opcodes From 8b4212ffb9c97e49fbc667f35585a01c98e6b19e Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Wed, 20 Jul 2022 03:14:04 -0700 Subject: [PATCH 36/61] Refactor `PacketOpcodesUtil` to be more... useful --- .../java/emu/grasscutter/Grasscutter.java | 6 +- .../grasscutter/net/packet/PacketOpcodes.java | 10 --- .../net/packet/PacketOpcodesUtil.java | 46 ------------- .../net/packet/PacketOpcodesUtils.java | 68 +++++++++++++++++++ .../server/game/GameServerPacketHandler.java | 2 +- .../grasscutter/server/game/GameSession.java | 18 ++--- 6 files changed, 79 insertions(+), 71 deletions(-) delete mode 100644 src/main/java/emu/grasscutter/net/packet/PacketOpcodesUtil.java create mode 100644 src/main/java/emu/grasscutter/net/packet/PacketOpcodesUtils.java diff --git a/src/main/java/emu/grasscutter/Grasscutter.java b/src/main/java/emu/grasscutter/Grasscutter.java index 34bf4a582..2e9523e29 100644 --- a/src/main/java/emu/grasscutter/Grasscutter.java +++ b/src/main/java/emu/grasscutter/Grasscutter.java @@ -5,7 +5,6 @@ import ch.qos.logback.classic.Logger; import com.google.gson.Gson; import com.google.gson.GsonBuilder; -import emu.grasscutter.Grasscutter.ServerDebugMode; import emu.grasscutter.auth.AuthenticationSystem; import emu.grasscutter.auth.DefaultAuthentication; import emu.grasscutter.command.CommandMap; @@ -14,6 +13,7 @@ import emu.grasscutter.command.PermissionHandler; import emu.grasscutter.config.ConfigContainer; import emu.grasscutter.data.ResourceLoader; import emu.grasscutter.database.DatabaseManager; +import emu.grasscutter.net.packet.PacketOpcodesUtils; import emu.grasscutter.plugin.PluginManager; import emu.grasscutter.plugin.api.ServerHook; import emu.grasscutter.scripts.ScriptLoader; @@ -98,6 +98,10 @@ public final class Grasscutter { Tools.createGmHandbook(); exitEarly = true; } + case "-dumppacketids" -> { + PacketOpcodesUtils.dumpPacketIds(); + exitEarly = true; + } case "-gachamap" -> { Tools.createGachaMapping(DATA("gacha_mappings.js")); exitEarly = true; diff --git a/src/main/java/emu/grasscutter/net/packet/PacketOpcodes.java b/src/main/java/emu/grasscutter/net/packet/PacketOpcodes.java index abb006fc9..3d79a196d 100644 --- a/src/main/java/emu/grasscutter/net/packet/PacketOpcodes.java +++ b/src/main/java/emu/grasscutter/net/packet/PacketOpcodes.java @@ -1,7 +1,5 @@ package emu.grasscutter.net.packet; -import java.util.HashSet; - public class PacketOpcodes { // Empty public static final int NONE = 0; @@ -1856,12 +1854,4 @@ public class PacketOpcodes { public static final int WorldRoutineTypeCloseNotify = 3502; public static final int WorldRoutineTypeRefreshNotify = 3525; - // Unknown - - public static final HashSet BANNED_PACKETS = new HashSet<>() { - { - this.add(PacketOpcodes.WindSeedClientNotify); - this.add(PacketOpcodes.PlayerLuaShellNotify); - } - }; } \ No newline at end of file diff --git a/src/main/java/emu/grasscutter/net/packet/PacketOpcodesUtil.java b/src/main/java/emu/grasscutter/net/packet/PacketOpcodesUtil.java deleted file mode 100644 index ff7be1e45..000000000 --- a/src/main/java/emu/grasscutter/net/packet/PacketOpcodesUtil.java +++ /dev/null @@ -1,46 +0,0 @@ -package emu.grasscutter.net.packet; - -import java.io.BufferedWriter; -import java.io.FileWriter; -import java.io.IOException; -import java.lang.reflect.Field; - -import it.unimi.dsi.fastutil.ints.Int2ObjectMap; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; - -public class PacketOpcodesUtil { - private static Int2ObjectMap opcodeMap; - - static { - opcodeMap = new Int2ObjectOpenHashMap(); - - Field[] fields = PacketOpcodes.class.getFields(); - - for (Field f : fields) { - if(f.getType().equals(int.class)) { - try { - opcodeMap.put(f.getInt(null), f.getName()); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - } - - public static String getOpcodeName(int opcode) { - if (opcode <= 0) return "UNKNOWN"; - return opcodeMap.getOrDefault(opcode, "UNKNOWN"); - } - - public static void dumpOpcodes() { - try { - BufferedWriter out = new BufferedWriter(new FileWriter("opcodes.ini")); - for (Int2ObjectMap.Entry entry : opcodeMap.int2ObjectEntrySet()) { - out.write(String.format("%04X=%s%s", entry.getIntKey(), entry.getValue(), System.lineSeparator())); - } - out.close(); - } catch (IOException e) { - e.printStackTrace(); - } - } -} diff --git a/src/main/java/emu/grasscutter/net/packet/PacketOpcodesUtils.java b/src/main/java/emu/grasscutter/net/packet/PacketOpcodesUtils.java new file mode 100644 index 000000000..fc6c5dba0 --- /dev/null +++ b/src/main/java/emu/grasscutter/net/packet/PacketOpcodesUtils.java @@ -0,0 +1,68 @@ +package emu.grasscutter.net.packet; + +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.IOException; +import java.lang.reflect.Field; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import java.util.TreeMap; +import java.util.stream.Collectors; + +import emu.grasscutter.GameConstants; +import emu.grasscutter.Grasscutter; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; + +public class PacketOpcodesUtils { + private static Int2ObjectMap opcodeMap; + + public static final Set BANNED_PACKETS = Set.of( + PacketOpcodes.WindSeedClientNotify, + PacketOpcodes.PlayerLuaShellNotify + ); + + public static final Set LOOP_PACKETS = Set.of( + PacketOpcodes.PingReq, + PacketOpcodes.PingRsp, + PacketOpcodes.WorldPlayerRTTNotify, + PacketOpcodes.UnionCmdNotify, + PacketOpcodes.QueryPathReq + ); + + static { + opcodeMap = new Int2ObjectOpenHashMap(); + + Field[] fields = PacketOpcodes.class.getFields(); + + for (Field f : fields) { + if(f.getType().equals(int.class)) { + try { + opcodeMap.put(f.getInt(null), f.getName()); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } + + public static String getOpcodeName(int opcode) { + if (opcode <= 0) return "UNKNOWN"; + return opcodeMap.getOrDefault(opcode, "UNKNOWN"); + } + + public static void dumpPacketIds() { + try (FileWriter writer = new FileWriter("./PacketIds_" + GameConstants.VERSION + ".json")) { + // Create sorted tree map + Map packetIds = opcodeMap.int2ObjectEntrySet().stream() + .filter(e -> e.getIntKey() > 0) + .collect(Collectors.toMap(Int2ObjectMap.Entry::getIntKey, Int2ObjectMap.Entry::getValue, (k, v) -> v, TreeMap::new)); + // Write to file + writer.write(Grasscutter.getGsonFactory().toJson(packetIds)); + Grasscutter.getLogger().info("Dumped packet ids."); + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/src/main/java/emu/grasscutter/server/game/GameServerPacketHandler.java b/src/main/java/emu/grasscutter/server/game/GameServerPacketHandler.java index 0f6998274..7a8c4b8b1 100644 --- a/src/main/java/emu/grasscutter/server/game/GameServerPacketHandler.java +++ b/src/main/java/emu/grasscutter/server/game/GameServerPacketHandler.java @@ -95,7 +95,7 @@ public class GameServerPacketHandler { // Log unhandled packets if (GAME_INFO.logPackets == ServerDebugMode.MISSING) { - Grasscutter.getLogger().info("Unhandled packet (" + opcode + "): " + emu.grasscutter.net.packet.PacketOpcodesUtil.getOpcodeName(opcode)); + Grasscutter.getLogger().info("Unhandled packet (" + opcode + "): " + emu.grasscutter.net.packet.PacketOpcodesUtils.getOpcodeName(opcode)); } } } diff --git a/src/main/java/emu/grasscutter/server/game/GameSession.java b/src/main/java/emu/grasscutter/server/game/GameSession.java index 096a3a35d..5d184853c 100644 --- a/src/main/java/emu/grasscutter/server/game/GameSession.java +++ b/src/main/java/emu/grasscutter/server/game/GameSession.java @@ -9,7 +9,7 @@ import emu.grasscutter.game.Account; import emu.grasscutter.game.player.Player; import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.PacketOpcodes; -import emu.grasscutter.net.packet.PacketOpcodesUtil; +import emu.grasscutter.net.packet.PacketOpcodesUtils; import emu.grasscutter.server.event.game.SendPacketEvent; import emu.grasscutter.utils.Crypto; import emu.grasscutter.utils.FileUtils; @@ -126,7 +126,7 @@ public class GameSession implements GameSessionManager.KcpChannel { } public void logPacket( String sendOrRecv, int opcode, byte[] payload) { - Grasscutter.getLogger().info(sendOrRecv + ": " + PacketOpcodesUtil.getOpcodeName(opcode) + " (" + opcode + ")"); + Grasscutter.getLogger().info(sendOrRecv + ": " + PacketOpcodesUtils.getOpcodeName(opcode) + " (" + opcode + ")"); System.out.println(Utils.bytesToHex(payload)); } public void send(BasePacket packet) { @@ -138,7 +138,7 @@ public class GameSession implements GameSessionManager.KcpChannel { // DO NOT REMOVE (unless we find a way to validate code before sending to client which I don't think we can) // Stop WindSeedClientNotify from being sent for security purposes. - if(PacketOpcodes.BANNED_PACKETS.contains(packet.getOpcode())) { + if(PacketOpcodesUtils.BANNED_PACKETS.contains(packet.getOpcode())) { return; } @@ -150,7 +150,7 @@ public class GameSession implements GameSessionManager.KcpChannel { // Log switch (GAME_INFO.logPackets) { case ALL -> { - if (!loopPacket.contains(packet.getOpcode())) { + if (!PacketOpcodesUtils.LOOP_PACKETS.contains(packet.getOpcode())) { logPacket("SEND", packet.getOpcode(), packet.getData()); } } @@ -174,14 +174,6 @@ public class GameSession implements GameSessionManager.KcpChannel { } } - private static final Set loopPacket = Set.of( - PacketOpcodes.PingReq, - PacketOpcodes.PingRsp, - PacketOpcodes.WorldPlayerRTTNotify, - PacketOpcodes.UnionCmdNotify, - PacketOpcodes.QueryPathReq - ); - @Override public void onConnected(GameSessionManager.KcpTunnel tunnel) { this.tunnel = tunnel; @@ -234,7 +226,7 @@ public class GameSession implements GameSessionManager.KcpChannel { // Log packet switch (GAME_INFO.logPackets) { case ALL -> { - if (!loopPacket.contains(opcode)) { + if (!PacketOpcodesUtils.LOOP_PACKETS.contains(opcode)) { logPacket("RECV",opcode, payload); } } From b9b0f002324c5937818fef7339c00c9a6b070fb5 Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Wed, 20 Jul 2022 03:17:59 -0700 Subject: [PATCH 37/61] Move PlayerManagers and GameServerSystems around --- .../managers/collection/CollectionData.java | 30 ------------------- .../emu/grasscutter/game/player/Player.java | 9 +++--- .../PlayerCollectionRecords.java} | 4 +-- .../AnnouncementSystem.java | 2 +- .../InventorySystem.java | 2 +- .../MultiplayerSystem.java | 2 +- .../grasscutter/server/game/GameServer.java | 6 ++-- .../task/tasks/AnnouncementTask.java | 2 +- 8 files changed, 13 insertions(+), 44 deletions(-) delete mode 100644 src/main/java/emu/grasscutter/game/managers/collection/CollectionData.java rename src/main/java/emu/grasscutter/game/{managers/collection/CollectionRecordStore.java => player/PlayerCollectionRecords.java} (94%) rename src/main/java/emu/grasscutter/game/{managers => systems}/AnnouncementSystem.java (98%) rename src/main/java/emu/grasscutter/game/{managers => systems}/InventorySystem.java (99%) rename src/main/java/emu/grasscutter/game/{managers => systems}/MultiplayerSystem.java (99%) diff --git a/src/main/java/emu/grasscutter/game/managers/collection/CollectionData.java b/src/main/java/emu/grasscutter/game/managers/collection/CollectionData.java deleted file mode 100644 index ee3123283..000000000 --- a/src/main/java/emu/grasscutter/game/managers/collection/CollectionData.java +++ /dev/null @@ -1,30 +0,0 @@ -package emu.grasscutter.game.managers.collection; - - -import emu.grasscutter.game.props.FightProperty; -import emu.grasscutter.utils.Position; - -public class CollectionData { - Gadget gadget; - MotionInfo motionInfo; - Prop[] fightPropList; - static class GatherGadget{ - int itemId; - } - static class Gadget{ - int gadgetId; - int authorityPeerId; - int configId; - int groupId; - boolean isEnableInteract; - GatherGadget gatherGadget; - } - static class MotionInfo{ - Position pos; - Position rot; - } - static class Prop{ - int propType; - float propValue; - } -} diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index 4172368e2..df4bad584 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -31,7 +31,6 @@ import emu.grasscutter.game.mail.MailHandler; import emu.grasscutter.game.managers.CookingManager; import emu.grasscutter.game.managers.FurnitureManager; import emu.grasscutter.game.managers.ResinManager; -import emu.grasscutter.game.managers.collection.CollectionRecordStore; import emu.grasscutter.game.managers.deforestation.DeforestationManager; import emu.grasscutter.game.managers.energy.EnergyManager; import emu.grasscutter.game.managers.forging.ActiveForgeData; @@ -158,7 +157,7 @@ public class Player { private TowerData towerData; private PlayerGachaInfo gachaInfo; private PlayerOpenStateManager openStateManager; - private CollectionRecordStore collectionRecordStore; + private PlayerCollectionRecords collectionRecordStore; private ArrayList shopLimit; @Getter private transient GameHome home; @@ -213,7 +212,7 @@ public class Player { this.flyCloakList = new HashSet<>(); this.costumeList = new HashSet<>(); this.towerData = new TowerData(); - this.collectionRecordStore = new CollectionRecordStore(); + this.collectionRecordStore = new PlayerCollectionRecords(); this.unlockedForgingBlueprints = new HashSet<>(); this.unlockedCombines = new HashSet<>(); this.unlockedFurniture = new HashSet<>(); @@ -1148,9 +1147,9 @@ public class Player { this.battlePassManager.getMissions().values().removeIf(mission -> mission.getData() == null); } - public CollectionRecordStore getCollectionRecordStore() { + public PlayerCollectionRecords getCollectionRecordStore() { if(this.collectionRecordStore==null){ - this.collectionRecordStore = new CollectionRecordStore(); + this.collectionRecordStore = new PlayerCollectionRecords(); } return collectionRecordStore; } diff --git a/src/main/java/emu/grasscutter/game/managers/collection/CollectionRecordStore.java b/src/main/java/emu/grasscutter/game/player/PlayerCollectionRecords.java similarity index 94% rename from src/main/java/emu/grasscutter/game/managers/collection/CollectionRecordStore.java rename to src/main/java/emu/grasscutter/game/player/PlayerCollectionRecords.java index be250998d..6b75a1f7e 100644 --- a/src/main/java/emu/grasscutter/game/managers/collection/CollectionRecordStore.java +++ b/src/main/java/emu/grasscutter/game/player/PlayerCollectionRecords.java @@ -1,4 +1,4 @@ -package emu.grasscutter.game.managers.collection; +package emu.grasscutter.game.player; import java.util.HashMap; import java.util.Map; @@ -6,7 +6,7 @@ import java.util.Map; import dev.morphia.annotations.Entity; @Entity -public class CollectionRecordStore { +public class PlayerCollectionRecords { private Map records; private Map getRecords() { diff --git a/src/main/java/emu/grasscutter/game/managers/AnnouncementSystem.java b/src/main/java/emu/grasscutter/game/systems/AnnouncementSystem.java similarity index 98% rename from src/main/java/emu/grasscutter/game/managers/AnnouncementSystem.java rename to src/main/java/emu/grasscutter/game/systems/AnnouncementSystem.java index 22f23ffcf..5d2161b94 100644 --- a/src/main/java/emu/grasscutter/game/managers/AnnouncementSystem.java +++ b/src/main/java/emu/grasscutter/game/systems/AnnouncementSystem.java @@ -1,4 +1,4 @@ -package emu.grasscutter.game.managers; +package emu.grasscutter.game.systems; import com.google.gson.reflect.TypeToken; import emu.grasscutter.Grasscutter; diff --git a/src/main/java/emu/grasscutter/game/managers/InventorySystem.java b/src/main/java/emu/grasscutter/game/systems/InventorySystem.java similarity index 99% rename from src/main/java/emu/grasscutter/game/managers/InventorySystem.java rename to src/main/java/emu/grasscutter/game/systems/InventorySystem.java index bf38f64cb..37b988ff8 100644 --- a/src/main/java/emu/grasscutter/game/managers/InventorySystem.java +++ b/src/main/java/emu/grasscutter/game/systems/InventorySystem.java @@ -1,4 +1,4 @@ -package emu.grasscutter.game.managers; +package emu.grasscutter.game.systems; import java.util.ArrayList; import java.util.Arrays; diff --git a/src/main/java/emu/grasscutter/game/managers/MultiplayerSystem.java b/src/main/java/emu/grasscutter/game/systems/MultiplayerSystem.java similarity index 99% rename from src/main/java/emu/grasscutter/game/managers/MultiplayerSystem.java rename to src/main/java/emu/grasscutter/game/systems/MultiplayerSystem.java index d64a34572..a3f23a448 100644 --- a/src/main/java/emu/grasscutter/game/managers/MultiplayerSystem.java +++ b/src/main/java/emu/grasscutter/game/systems/MultiplayerSystem.java @@ -1,4 +1,4 @@ -package emu.grasscutter.game.managers; +package emu.grasscutter.game.systems; import emu.grasscutter.game.CoopRequest; import emu.grasscutter.game.props.EnterReason; diff --git a/src/main/java/emu/grasscutter/server/game/GameServer.java b/src/main/java/emu/grasscutter/server/game/GameServer.java index 84c4c2605..f115b2c3b 100644 --- a/src/main/java/emu/grasscutter/server/game/GameServer.java +++ b/src/main/java/emu/grasscutter/server/game/GameServer.java @@ -12,10 +12,7 @@ import emu.grasscutter.game.dungeons.DungeonSystem; import emu.grasscutter.game.dungeons.challenge.DungeonChallenge; import emu.grasscutter.game.expedition.ExpeditionSystem; import emu.grasscutter.game.gacha.GachaSystem; -import emu.grasscutter.game.managers.AnnouncementSystem; import emu.grasscutter.game.managers.CookingManager; -import emu.grasscutter.game.managers.InventorySystem; -import emu.grasscutter.game.managers.MultiplayerSystem; import emu.grasscutter.game.managers.chat.ChatManager; import emu.grasscutter.game.managers.chat.ChatManagerHandler; import emu.grasscutter.game.managers.energy.EnergyManager; @@ -23,6 +20,9 @@ import emu.grasscutter.game.managers.stamina.StaminaManager; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.quest.QuestSystem; import emu.grasscutter.game.shop.ShopSystem; +import emu.grasscutter.game.systems.AnnouncementSystem; +import emu.grasscutter.game.systems.InventorySystem; +import emu.grasscutter.game.systems.MultiplayerSystem; import emu.grasscutter.game.tower.TowerSystem; import emu.grasscutter.game.world.World; import emu.grasscutter.game.world.WorldDataSystem; diff --git a/src/main/java/emu/grasscutter/task/tasks/AnnouncementTask.java b/src/main/java/emu/grasscutter/task/tasks/AnnouncementTask.java index c6ec1619b..a8d99698e 100644 --- a/src/main/java/emu/grasscutter/task/tasks/AnnouncementTask.java +++ b/src/main/java/emu/grasscutter/task/tasks/AnnouncementTask.java @@ -1,7 +1,7 @@ package emu.grasscutter.task.tasks; import emu.grasscutter.Grasscutter; -import emu.grasscutter.game.managers.AnnouncementSystem; +import emu.grasscutter.game.systems.AnnouncementSystem; import emu.grasscutter.task.Task; import emu.grasscutter.task.TaskHandler; import org.quartz.JobExecutionContext; From bc701cfad05ea42e9930d3ca281bcf9b338e9975 Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Wed, 20 Jul 2022 19:43:33 -0700 Subject: [PATCH 38/61] Add missing scene load state to PacketPlayerEnterSceneNotify --- .../server/packet/send/PacketPlayerEnterSceneNotify.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerEnterSceneNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerEnterSceneNotify.java index 180fd2e7a..a74ac4145 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerEnterSceneNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerEnterSceneNotify.java @@ -44,6 +44,7 @@ public class PacketPlayerEnterSceneNotify extends BasePacket { public PacketPlayerEnterSceneNotify(Player player, Player target, EnterType type, EnterReason reason, int newScene, Position newPos) { super(PacketOpcodes.PlayerEnterSceneNotify); + player.setSceneLoadState(SceneLoadState.LOADING); player.setEnterSceneToken(Utils.randomRange(1000, 99999)); PlayerEnterSceneNotify.Builder proto = PlayerEnterSceneNotify.newBuilder() From 510d564bcb2416814cc4c47ea7aa30ffab831b1d Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Wed, 20 Jul 2022 22:12:31 -0700 Subject: [PATCH 39/61] Dont use discriminator for `PlayerCollectionRecords` --- .../emu/grasscutter/game/player/PlayerCollectionRecords.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/emu/grasscutter/game/player/PlayerCollectionRecords.java b/src/main/java/emu/grasscutter/game/player/PlayerCollectionRecords.java index 6b75a1f7e..676caee40 100644 --- a/src/main/java/emu/grasscutter/game/player/PlayerCollectionRecords.java +++ b/src/main/java/emu/grasscutter/game/player/PlayerCollectionRecords.java @@ -5,7 +5,7 @@ import java.util.Map; import dev.morphia.annotations.Entity; -@Entity +@Entity(useDiscriminator = false) public class PlayerCollectionRecords { private Map records; From ae2d1fe43815ee36d2a4ea2199fe0b17de85806e Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Jul 2022 07:21:22 +0000 Subject: [PATCH 40/61] Fix whitespace [skip actions] --- .../java/emu/grasscutter/GameConstants.java | 40 +- .../java/emu/grasscutter/Grasscutter.java | 2 +- .../auth/DefaultAuthentication.java | 2 +- .../emu/grasscutter/command/CommandMap.java | 4 +- .../command/commands/AccountCommand.java | 14 +- .../command/commands/AnnounceCommand.java | 4 +- .../command/commands/CoopCommand.java | 2 +- .../command/commands/EnterDungeonCommand.java | 6 +- .../command/commands/GiveCommand.java | 20 +- .../command/commands/HelpCommand.java | 4 +- .../command/commands/ReloadCommand.java | 4 +- .../command/commands/SendMailCommand.java | 4 +- .../command/commands/SetPropCommand.java | 410 +-- .../command/commands/SpawnCommand.java | 22 +- .../command/commands/TeamCommand.java | 510 ++-- .../command/commands/TeleportAllCommand.java | 4 +- .../command/commands/TeleportCommand.java | 4 +- .../grasscutter/config/ConfigContainer.java | 16 +- .../emu/grasscutter/config/Configuration.java | 22 +- .../java/emu/grasscutter/data/DataLoader.java | 2 +- .../java/emu/grasscutter/data/GameDepot.java | 58 +- .../emu/grasscutter/data/ResourceLoader.java | 686 ++--- .../data/common/ItemParamData.java | 50 +- .../excels/EnvAnimalGatherConfigData.java | 70 +- .../grasscutter/data/excels/ForgeData.java | 6 +- .../data/excels/ReliquaryLevelData.java | 108 +- .../grasscutter/database/DatabaseManager.java | 164 +- .../java/emu/grasscutter/game/Account.java | 340 +-- .../game/ability/AbilityManager.java | 296 +- .../game/activity/ActivityManager.java | 24 +- .../musicgame/MusicGameActivityHandler.java | 8 +- .../musicgame/MusicGamePlayerData.java | 10 +- .../emu/grasscutter/game/avatar/Avatar.java | 1658 +++++------ .../game/avatar/AvatarStorage.java | 284 +- .../game/battlepass/BattlePassManager.java | 564 ++-- .../game/battlepass/BattlePassSystem.java | 114 +- .../game/combine/CombineManger.java | 66 +- .../emu/grasscutter/game/drop/DropSystem.java | 4 +- .../game/dungeons/DungeonSystem.java | 168 +- .../dungeons/challenge/DungeonChallenge.java | 294 +- .../grasscutter/game/entity/EntityAvatar.java | 520 ++-- .../grasscutter/game/entity/EntityGadget.java | 298 +- .../grasscutter/game/entity/EntityItem.java | 212 +- .../game/entity/EntityMonster.java | 460 +-- .../game/entity/EntityVehicle.java | 158 +- .../grasscutter/game/entity/GameEntity.java | 414 +-- .../game/entity/gadget/GadgetChest.java | 80 +- .../chest/BossChestInteractHandler.java | 2 +- .../game/expedition/ExpeditionSystem.java | 8 +- .../grasscutter/game/friends/FriendsList.java | 462 +-- .../grasscutter/game/gacha/GachaBanner.java | 298 +- .../grasscutter/game/gacha/GachaSystem.java | 700 ++--- .../grasscutter/game/inventory/Inventory.java | 820 +++--- .../grasscutter/game/mail/MailHandler.java | 154 +- .../game/managers/CookingManager.java | 6 +- .../game/managers/FurnitureManager.java | 30 +- .../game/managers/ResinManager.java | 12 +- .../game/managers/SotSManager.java | 382 +-- .../game/managers/chat/ChatManager.java | 328 +-- .../deforestation/DeforestationManager.java | 18 +- .../game/managers/energy/EnergyManager.java | 2 +- .../game/managers/forging/ForgingManager.java | 480 +-- .../managers/mapmark/MapMarksManager.java | 4 +- .../game/managers/stamina/StaminaManager.java | 26 +- .../game/player/BasePlayerDataManager.java | 8 +- .../game/player/BasePlayerManager.java | 6 +- .../emu/grasscutter/game/player/Player.java | 2576 ++++++++--------- .../game/player/PlayerCollectionRecords.java | 64 +- .../game/player/PlayerOpenStateManager.java | 20 +- .../emu/grasscutter/game/player/TeamInfo.java | 132 +- .../grasscutter/game/player/TeamManager.java | 1162 ++++---- .../emu/grasscutter/game/props/OpenState.java | 430 +-- .../emu/grasscutter/game/quest/GameQuest.java | 320 +- .../grasscutter/game/quest/QuestManager.java | 278 +- .../grasscutter/game/quest/QuestSystem.java | 112 +- .../emu/grasscutter/game/shop/ShopSystem.java | 198 +- .../game/systems/AnnouncementSystem.java | 12 +- .../game/systems/InventorySystem.java | 1756 +++++------ .../game/systems/MultiplayerSystem.java | 260 +- .../grasscutter/game/tower/TowerManager.java | 34 +- .../grasscutter/game/tower/TowerSystem.java | 32 +- .../emu/grasscutter/game/world/Scene.java | 1340 ++++----- .../game/world/SpawnDataEntry.java | 124 +- .../emu/grasscutter/game/world/World.java | 544 ++-- .../game/world/WorldDataSystem.java | 32 +- .../grasscutter/net/packet/BasePacket.java | 220 +- .../grasscutter/net/packet/PacketOpcodes.java | 2 +- .../net/packet/PacketOpcodesUtils.java | 64 +- .../java/emu/grasscutter/plugin/Plugin.java | 16 +- .../emu/grasscutter/plugin/PluginManager.java | 10 +- .../grasscutter/plugin/api/PlayerHook.java | 8 +- .../grasscutter/scripts/data/SceneBlock.java | 84 +- .../grasscutter/scripts/data/SceneGroup.java | 162 +- .../grasscutter/scripts/data/SceneMeta.java | 2 +- .../server/game/BaseGameSystem.java | 4 +- .../grasscutter/server/game/GameServer.java | 312 +- .../server/game/GameServerPacketHandler.java | 132 +- .../grasscutter/server/game/GameSession.java | 422 +-- .../grasscutter/server/http/HttpServer.java | 48 +- .../server/http/dispatch/RegionHandler.java | 8 +- .../http/handlers/AnnouncementsHandler.java | 10 +- .../server/http/handlers/GachaHandler.java | 16 +- .../server/http/handlers/GenericHandler.java | 8 +- .../server/http/objects/HttpJsonResponse.java | 50 +- .../objects/WebStaticVersionResponse.java | 4 +- .../HandlerAvatarExpeditionGetRewardReq.java | 6 +- .../packet/recv/HandlerAvatarPromoteReq.java | 16 +- .../recv/HandlerAvatarSkillUpgradeReq.java | 16 +- .../packet/recv/HandlerAvatarUpgradeReq.java | 26 +- ...andlerCalcWeaponUpgradeReturnItemsReq.java | 36 +- .../server/packet/recv/HandlerCombineReq.java | 4 +- .../recv/HandlerDestroyMaterialReq.java | 14 +- .../server/packet/recv/HandlerDoGachaReq.java | 12 +- .../recv/HandlerDungeonEntryInfoReq.java | 14 +- .../packet/recv/HandlerGetGachaInfoReq.java | 10 +- .../HandlerGetInvestigationMonsterReq.java | 18 +- .../packet/recv/HandlerGetPlayerTokenReq.java | 112 +- .../packet/recv/HandlerHomeUnknown2Req.java | 16 +- .../recv/HandlerPlayerApplyEnterMpReq.java | 16 +- .../HandlerPlayerApplyEnterMpResultReq.java | 16 +- .../recv/HandlerPlayerEnterDungeonReq.java | 16 +- .../HandlerPlayerGetForceQuitBanInfoReq.java | 24 +- .../packet/recv/HandlerPlayerLoginReq.java | 58 +- .../recv/HandlerPlayerQuitDungeonReq.java | 10 +- .../recv/HandlerPullPrivateChatReq.java | 16 +- .../packet/recv/HandlerPullRecentChatReq.java | 8 +- .../packet/recv/HandlerQueryPathReq.java | 12 +- .../recv/HandlerReliquaryDecomposeReq.java | 10 +- .../recv/HandlerReliquaryUpgradeReq.java | 14 +- .../recv/HandlerSceneKickPlayerReq.java | 26 +- .../recv/HandlerSetEquipLockStateReq.java | 14 +- .../packet/recv/HandlerSetOpenStateReq.java | 2 +- .../recv/HandlerSetPlayerBornDataReq.java | 112 +- .../packet/recv/HandlerTowerAllDataReq.java | 16 +- .../packet/recv/HandlerUnionCmdNotify.java | 26 +- .../recv/HandlerUnlockAvatarTalentReq.java | 16 +- .../server/packet/recv/HandlerUseItemReq.java | 24 +- .../packet/recv/HandlerWeaponAwakenReq.java | 16 +- .../packet/recv/HandlerWeaponPromoteReq.java | 16 +- .../packet/recv/HandlerWeaponUpgradeReq.java | 26 +- .../packet/send/PacketGetAllMailRsp.java | 4 +- .../packet/send/PacketGetGachaInfoRsp.java | 12 +- .../PacketGetInvestigationMonsterRsp.java | 12 +- .../send/PacketGetPlayerFriendListRsp.java | 54 +- .../packet/send/PacketGetSceneAreaRsp.java | 32 +- .../server/packet/send/PacketGetShopRsp.java | 104 +- .../send/PacketHomeBasicInfoNotify.java | 38 +- .../packet/send/PacketMailChangeNotify.java | 6 +- .../server/packet/send/PacketMarkMapRsp.java | 2 +- .../send/PacketOpenStateChangeNotify.java | 2 +- .../send/PacketOpenStateUpdateNotify.java | 26 +- .../send/PacketPlayerEnterSceneNotify.java | 104 +- .../packet/send/PacketPlayerLoginRsp.java | 86 +- .../packet/send/PacketPlayerStoreNotify.java | 34 +- .../PacketPlayerWorldSceneInfoListNotify.java | 110 +- .../packet/send/PacketPrivateChatNotify.java | 76 +- .../packet/send/PacketPullPrivateChatRsp.java | 30 +- .../packet/send/PacketPullRecentChatRsp.java | 14 +- .../packet/send/PacketSetOpenStateRsp.java | 2 +- .../send/PacketStoreWeightLimitNotify.java | 28 +- .../packet/send/PacketTowerAllDataRsp.java | 78 +- .../java/emu/grasscutter/tools/Tools.java | 434 +-- .../emu/grasscutter/utils/ByteHelper.java | 48 +- .../java/emu/grasscutter/utils/Crypto.java | 52 +- .../java/emu/grasscutter/utils/Language.java | 34 +- .../java/emu/grasscutter/utils/Utils.java | 676 ++--- 166 files changed, 12928 insertions(+), 12928 deletions(-) diff --git a/src/main/java/emu/grasscutter/GameConstants.java b/src/main/java/emu/grasscutter/GameConstants.java index fccc59ed1..c1f0ac9e0 100644 --- a/src/main/java/emu/grasscutter/GameConstants.java +++ b/src/main/java/emu/grasscutter/GameConstants.java @@ -6,29 +6,29 @@ import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Utils; public final class GameConstants { - public static String VERSION = "2.8.0"; + public static String VERSION = "2.8.0"; - public static final int MAX_TEAMS = 4; - public static final int MAIN_CHARACTER_MALE = 10000005; - public static final int MAIN_CHARACTER_FEMALE = 10000007; - public static final Position START_POSITION = new Position(2747, 194, -1719); + public static final int MAX_TEAMS = 4; + public static final int MAIN_CHARACTER_MALE = 10000005; + public static final int MAIN_CHARACTER_FEMALE = 10000007; + public static final Position START_POSITION = new Position(2747, 194, -1719); - public static final int MAX_FRIENDS = 45; - public static final int MAX_FRIEND_REQUESTS = 50; + public static final int MAX_FRIENDS = 45; + public static final int MAX_FRIEND_REQUESTS = 50; - public static final int SERVER_CONSOLE_UID = 99; // The UID of the server console's "player". + public static final int SERVER_CONSOLE_UID = 99; // The UID of the server console's "player". - public static final int BATTLE_PASS_MAX_LEVEL = 50; - public static final int BATTLE_PASS_POINT_PER_LEVEL = 1000; - public static final int BATTLE_PASS_POINT_PER_WEEK = 10000; - public static final int BATTLE_PASS_LEVEL_PRICE = 150; - public static final int BATTLE_PASS_CURRENT_INDEX = 2; + public static final int BATTLE_PASS_MAX_LEVEL = 50; + public static final int BATTLE_PASS_POINT_PER_LEVEL = 1000; + public static final int BATTLE_PASS_POINT_PER_WEEK = 10000; + public static final int BATTLE_PASS_LEVEL_PRICE = 150; + public static final int BATTLE_PASS_CURRENT_INDEX = 2; - // Default entity ability hashes. - public static final String[] DEFAULT_ABILITY_STRINGS = { - "Avatar_DefaultAbility_VisionReplaceDieInvincible", "Avatar_DefaultAbility_AvartarInShaderChange", "Avatar_SprintBS_Invincible", - "Avatar_Freeze_Duration_Reducer", "Avatar_Attack_ReviveEnergy", "Avatar_Component_Initializer", "Avatar_FallAnthem_Achievement_Listener" - }; - public static final int[] DEFAULT_ABILITY_HASHES = Arrays.stream(DEFAULT_ABILITY_STRINGS).mapToInt(Utils::abilityHash).toArray(); - public static final int DEFAULT_ABILITY_NAME = Utils.abilityHash("Default"); + // Default entity ability hashes. + public static final String[] DEFAULT_ABILITY_STRINGS = { + "Avatar_DefaultAbility_VisionReplaceDieInvincible", "Avatar_DefaultAbility_AvartarInShaderChange", "Avatar_SprintBS_Invincible", + "Avatar_Freeze_Duration_Reducer", "Avatar_Attack_ReviveEnergy", "Avatar_Component_Initializer", "Avatar_FallAnthem_Achievement_Listener" + }; + public static final int[] DEFAULT_ABILITY_HASHES = Arrays.stream(DEFAULT_ABILITY_STRINGS).mapToInt(Utils::abilityHash).toArray(); + public static final int DEFAULT_ABILITY_NAME = Utils.abilityHash("Default"); } diff --git a/src/main/java/emu/grasscutter/Grasscutter.java b/src/main/java/emu/grasscutter/Grasscutter.java index 2e9523e29..8a8c36e18 100644 --- a/src/main/java/emu/grasscutter/Grasscutter.java +++ b/src/main/java/emu/grasscutter/Grasscutter.java @@ -217,7 +217,7 @@ public final class Grasscutter { */ private static void onShutdown() { // Disable all plugins. - if(pluginManager != null) + if (pluginManager != null) pluginManager.disablePlugins(); } diff --git a/src/main/java/emu/grasscutter/auth/DefaultAuthentication.java b/src/main/java/emu/grasscutter/auth/DefaultAuthentication.java index 62d512ebd..9fa1ec4aa 100644 --- a/src/main/java/emu/grasscutter/auth/DefaultAuthentication.java +++ b/src/main/java/emu/grasscutter/auth/DefaultAuthentication.java @@ -21,7 +21,7 @@ public final class DefaultAuthentication implements AuthenticationSystem { private OAuthAuthenticator oAuthAuthenticator = new OAuthAuthentication(); public DefaultAuthentication() { - if(ACCOUNT.EXPERIMENTAL_RealPassword) { + if (ACCOUNT.EXPERIMENTAL_RealPassword) { passwordAuthenticator = new ExperimentalPasswordAuthenticator(); } else { passwordAuthenticator = new PasswordAuthenticator(); diff --git a/src/main/java/emu/grasscutter/command/CommandMap.java b/src/main/java/emu/grasscutter/command/CommandMap.java index fe19075bf..da37f0b37 100644 --- a/src/main/java/emu/grasscutter/command/CommandMap.java +++ b/src/main/java/emu/grasscutter/command/CommandMap.java @@ -167,7 +167,7 @@ public final class CommandMap { CommandHandler.sendTranslatedMessage(player, "commands.execution.clear_target"); return true; } - + // Sets default targetPlayer to the UID provided. try { int uid = Integer.parseInt(targetUid); @@ -237,7 +237,7 @@ public final class CommandMap { Command annotation = this.annotations.get(label); // Resolve targetPlayer - try{ + try { targetPlayer = getTargetPlayer(playerId, player, targetPlayer, args); } catch (IllegalArgumentException e) { return; diff --git a/src/main/java/emu/grasscutter/command/commands/AccountCommand.java b/src/main/java/emu/grasscutter/command/commands/AccountCommand.java index 3d622a505..843b78913 100644 --- a/src/main/java/emu/grasscutter/command/commands/AccountCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/AccountCommand.java @@ -39,8 +39,8 @@ public final class AccountCommand implements CommandHandler { int uid = 0; String password = ""; - if(Configuration.ACCOUNT.EXPERIMENTAL_RealPassword == true) { - if(args.size() < 3) { + if (Configuration.ACCOUNT.EXPERIMENTAL_RealPassword == true) { + if (args.size() < 3) { CommandHandler.sendMessage(null, "EXPERIMENTAL_RealPassword requires a password argument"); CommandHandler.sendMessage(null, "Usage: account create [uid]"); @@ -53,7 +53,7 @@ public final class AccountCommand implements CommandHandler { uid = Integer.parseInt(args.get(3)); } catch (NumberFormatException ignored) { CommandHandler.sendMessage(null, translate(sender, "commands.account.invalid")); - if(Configuration.ACCOUNT.EXPERIMENTAL_RealPassword == true) { + if (Configuration.ACCOUNT.EXPERIMENTAL_RealPassword == true) { CommandHandler.sendMessage(null, "EXPERIMENTAL_RealPassword requires argument 2 to be a password, not a uid"); CommandHandler.sendMessage(null, "Usage: account create [uid]"); } @@ -76,7 +76,7 @@ public final class AccountCommand implements CommandHandler { CommandHandler.sendMessage(null, translate(sender, "commands.account.exists")); return; } else { - if(Configuration.ACCOUNT.EXPERIMENTAL_RealPassword == true) { + if (Configuration.ACCOUNT.EXPERIMENTAL_RealPassword == true) { account.setPassword(BCrypt.withDefaults().hashToString(12, password.toCharArray())); } account.addPermission("*"); @@ -93,7 +93,7 @@ public final class AccountCommand implements CommandHandler { CommandHandler.sendMessage(null, translate(sender, "commands.account.no_account")); return; } - + // Get the player for the account. // If that player is currently online, we kick them before proceeding with the deletion. Player player = Grasscutter.getGameServer().getPlayerByAccountId(toDelete.getId()); @@ -106,12 +106,12 @@ public final class AccountCommand implements CommandHandler { CommandHandler.sendMessage(null, translate(sender, "commands.account.delete")); return; case "resetpass": - if(Configuration.ACCOUNT.EXPERIMENTAL_RealPassword != true) { + if (Configuration.ACCOUNT.EXPERIMENTAL_RealPassword != true) { CommandHandler.sendMessage(null, "resetpass requires EXPERIMENTAL_RealPassword to be true."); return; } - if(args.size() != 3) { + if (args.size() != 3) { CommandHandler.sendMessage(null, "Invalid Args"); CommandHandler.sendMessage(null, "Usage: account resetpass "); return; diff --git a/src/main/java/emu/grasscutter/command/commands/AnnounceCommand.java b/src/main/java/emu/grasscutter/command/commands/AnnounceCommand.java index 455e79453..136db705d 100644 --- a/src/main/java/emu/grasscutter/command/commands/AnnounceCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/AnnounceCommand.java @@ -28,7 +28,7 @@ public final class AnnounceCommand implements CommandHandler { return; } - switch (args.get(0)){ + switch (args.get(0)) { case "tpl": if (args.size() < 2) { CommandHandler.sendTranslatedMessage(sender, "commands.announce.command_usage"); @@ -37,7 +37,7 @@ public final class AnnounceCommand implements CommandHandler { var templateId = Integer.parseInt(args.get(1)); var tpl = manager.getAnnounceConfigItemMap().get(templateId); - if(tpl == null){ + if (tpl == null) { CommandHandler.sendMessage(sender, translate(sender, "commands.announce.not_found", templateId)); return; } diff --git a/src/main/java/emu/grasscutter/command/commands/CoopCommand.java b/src/main/java/emu/grasscutter/command/commands/CoopCommand.java index 8c1479718..e36c47ce2 100644 --- a/src/main/java/emu/grasscutter/command/commands/CoopCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/CoopCommand.java @@ -38,7 +38,7 @@ public final class CoopCommand implements CommandHandler { CommandHandler.sendMessage(sender, translate(sender, "commands.coop.usage")); return; } - + // There's no target==host check but this just places them in multiplayer in their own world which seems fine. if (targetPlayer.isInMultiplayer()) { targetPlayer.getServer().getMultiplayerSystem().leaveCoop(targetPlayer); diff --git a/src/main/java/emu/grasscutter/command/commands/EnterDungeonCommand.java b/src/main/java/emu/grasscutter/command/commands/EnterDungeonCommand.java index 94de4a294..e940e8e36 100644 --- a/src/main/java/emu/grasscutter/command/commands/EnterDungeonCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/EnterDungeonCommand.java @@ -21,10 +21,10 @@ public final class EnterDungeonCommand implements CommandHandler { try { int dungeonId = Integer.parseInt(args.get(0)); if (dungeonId == targetPlayer.getSceneId()) { - CommandHandler.sendMessage(sender, translate(sender, "commands.enter_dungeon.in_dungeon_error")); - return; + CommandHandler.sendMessage(sender, translate(sender, "commands.enter_dungeon.in_dungeon_error")); + return; } - + boolean result = targetPlayer.getServer().getDungeonSystem().enterDungeon(targetPlayer.getSession().getPlayer(), 0, dungeonId); if (!result) { diff --git a/src/main/java/emu/grasscutter/command/commands/GiveCommand.java b/src/main/java/emu/grasscutter/command/commands/GiveCommand.java index dab45378d..d86cbb19a 100644 --- a/src/main/java/emu/grasscutter/command/commands/GiveCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/GiveCommand.java @@ -257,7 +257,7 @@ public final class GiveCommand implements CommandHandler { if (avatar.getAvatarId() == GameConstants.MAIN_CHARACTER_MALE) { avatar.setSkillDepotData(GameData.getAvatarSkillDepotDataMap().get(504)); } - else if(avatar.getAvatarId() == GameConstants.MAIN_CHARACTER_FEMALE) { + else if (avatar.getAvatarId() == GameConstants.MAIN_CHARACTER_FEMALE) { avatar.setSkillDepotData(GameData.getAvatarSkillDepotDataMap().get(704)); } @@ -352,11 +352,11 @@ public final class GiveCommand implements CommandHandler { return affixes; } - private static int getAppendPropId(String substatText, ItemData itemData) throws IllegalArgumentException { - // If the given substat text is an integer, we just use that as the append prop ID. - try { - return Integer.parseInt(substatText); - } catch (NumberFormatException ignored) { + private static int getAppendPropId(String substatText, ItemData itemData) throws IllegalArgumentException { + // If the given substat text is an integer, we just use that as the append prop ID. + try { + return Integer.parseInt(substatText); + } catch (NumberFormatException ignored) { // If the argument was not an integer, we try to determine // the append prop ID from the given text + artifact information. // A substat string has the format `substat_tier`, with the @@ -378,8 +378,8 @@ public final class GiveCommand implements CommandHandler { substatTier -= 1; // 1-indexed to 0-indexed substatTier = Math.min(Math.max(0, substatTier), substats.size() - 1); return substats.get(substatTier); - } - } + } + } private static void parseRelicArgs(GiveItemParameters param, List args) throws IllegalArgumentException { // Get the main stat from the arguments. @@ -476,11 +476,11 @@ public final class GiveCommand implements CommandHandler { 10000-10008, 11411, 11506-11508, 12505, 12506, 12508, 12509, 13503, 13506, 14411, 14503, 14505, 14508, 15504-15506 """); - + private static final SparseSet illegalRelicIds = new SparseSet(""" 20001, 23300-23340, 23383-23385, 78310-78554, 99310-99554 """); - + private static final SparseSet illegalItemIds = new SparseSet(""" 100086, 100087, 100100-101000, 101106-101110, 101306, 101500-104000, 105001, 105004, 106000-107000, 107011, 108000, 109000-110000, diff --git a/src/main/java/emu/grasscutter/command/commands/HelpCommand.java b/src/main/java/emu/grasscutter/command/commands/HelpCommand.java index 65e7228cc..418a5fd76 100644 --- a/src/main/java/emu/grasscutter/command/commands/HelpCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/HelpCommand.java @@ -22,13 +22,13 @@ public final class HelpCommand implements CommandHandler { } } builder.append("\n\t").append(translate(player, "commands.help.tip_need_permission")); - if(annotation.permission().isEmpty() || annotation.permission().isBlank()) { + if (annotation.permission().isEmpty() || annotation.permission().isBlank()) { builder.append(translate(player, "commands.help.tip_need_no_permission")); } else { builder.append(annotation.permission()); } - if(!annotation.permissionTargeted().isEmpty() && !annotation.permissionTargeted().isBlank()) { + if (!annotation.permissionTargeted().isEmpty() && !annotation.permissionTargeted().isBlank()) { String permissionTargeted = annotation.permissionTargeted(); builder.append(" ").append(translate(player, "commands.help.tip_permission_targeted", permissionTargeted)); } diff --git a/src/main/java/emu/grasscutter/command/commands/ReloadCommand.java b/src/main/java/emu/grasscutter/command/commands/ReloadCommand.java index 0d052da3b..6f1dd6a91 100644 --- a/src/main/java/emu/grasscutter/command/commands/ReloadCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/ReloadCommand.java @@ -15,13 +15,13 @@ public final class ReloadCommand implements CommandHandler { @Override public void execute(Player sender, Player targetPlayer, List args) { CommandHandler.sendMessage(sender, translate(sender, "commands.reload.reload_start")); - + Grasscutter.loadConfig(); Grasscutter.loadLanguage(); Grasscutter.getGameServer().getGachaSystem().load(); Grasscutter.getGameServer().getDropSystem().load(); Grasscutter.getGameServer().getShopSystem().load(); - + CommandHandler.sendMessage(sender, translate(sender, "commands.reload.reload_done")); } } diff --git a/src/main/java/emu/grasscutter/command/commands/SendMailCommand.java b/src/main/java/emu/grasscutter/command/commands/SendMailCommand.java index 79f13e208..34c2b2bf4 100644 --- a/src/main/java/emu/grasscutter/command/commands/SendMailCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/SendMailCommand.java @@ -27,7 +27,7 @@ public final class SendMailCommand implements CommandHandler { @Override public void execute(Player sender, Player targetPlayer, List args) { int senderId; - if(sender != null) { + if (sender != null) { senderId = sender.getUid(); } else { senderId = -1; @@ -162,7 +162,7 @@ public final class SendMailCommand implements CommandHandler { } private String getConstructionArgs(int stage, Player sender) { - return switch(stage) { + return switch (stage) { case 0 -> translate(sender, "commands.sendMail.title"); case 1 -> translate(sender, "commands.sendMail.message"); case 2 -> translate(sender, "commands.sendMail.sender"); diff --git a/src/main/java/emu/grasscutter/command/commands/SetPropCommand.java b/src/main/java/emu/grasscutter/command/commands/SetPropCommand.java index 122eb782e..64989c86b 100644 --- a/src/main/java/emu/grasscutter/command/commands/SetPropCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/SetPropCommand.java @@ -1,205 +1,205 @@ -package emu.grasscutter.command.commands; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import emu.grasscutter.command.Command; -import emu.grasscutter.command.CommandHandler; -import emu.grasscutter.game.player.Player; -import emu.grasscutter.game.props.PlayerProperty; -import emu.grasscutter.game.tower.TowerLevelRecord; - -@Command(label = "setprop", usage = "setprop|prop ", aliases = {"prop"}, permission = "player.setprop", permissionTargeted = "player.setprop.others", description = "commands.setProp.description") -public final class SetPropCommand implements CommandHandler { - static enum PseudoProp { - NONE, - WORLD_LEVEL, - TOWER_LEVEL, - BP_LEVEL, - GOD_MODE, - NO_STAMINA, - UNLIMITED_ENERGY - } - - static class Prop { - String name; - PlayerProperty prop; - PseudoProp pseudoProp; - - public Prop(PlayerProperty prop) { - this(prop.toString(), prop, PseudoProp.NONE); - } - - public Prop(String name) { - this(name, PlayerProperty.PROP_NONE, PseudoProp.NONE); - } - - public Prop(String name, PseudoProp pseudoProp) { - this(name, PlayerProperty.PROP_NONE, pseudoProp); - } - - public Prop(String name, PlayerProperty prop) { - this(name, prop, PseudoProp.NONE); - } - - public Prop(String name, PlayerProperty prop, PseudoProp pseudoProp) { - this.name = name; - this.prop = prop; - this.pseudoProp = pseudoProp; - } - } - - Map props; - - public SetPropCommand() { - this.props = new HashMap<>(); - // Full PlayerProperty enum that won't be advertised but can be used by devs - for (PlayerProperty prop : PlayerProperty.values()) { - String name = prop.toString().substring(5); // PROP_EXP -> EXP - String key = name.toLowerCase(); // EXP -> exp - this.props.put(key, new Prop(name, prop)); - } - // Add special props - Prop worldlevel = new Prop("World Level", PlayerProperty.PROP_PLAYER_WORLD_LEVEL, PseudoProp.WORLD_LEVEL); - this.props.put("worldlevel", worldlevel); - this.props.put("wl", worldlevel); - - Prop abyss = new Prop("Tower Level", PseudoProp.TOWER_LEVEL); - this.props.put("abyss", abyss); - this.props.put("abyssfloor", abyss); - this.props.put("ut", abyss); - this.props.put("tower", abyss); - this.props.put("towerlevel", abyss); - this.props.put("unlocktower", abyss); - - Prop bplevel = new Prop("BP Level", PseudoProp.BP_LEVEL); - this.props.put("bplevel", bplevel); - this.props.put("bp", bplevel); - this.props.put("battlepass", bplevel); - - Prop godmode = new Prop("godmode", PseudoProp.GOD_MODE); - this.props.put("godmode", godmode); - this.props.put("god", godmode); - - Prop nostamina = new Prop("nostamina", PseudoProp.NO_STAMINA); - this.props.put("nostamina", nostamina); - this.props.put("nostam", nostamina); - this.props.put("ns", nostamina); - - Prop unlimitedenergy = new Prop("unlimitedenergy", PseudoProp.UNLIMITED_ENERGY); - this.props.put("unlimitedenergy", unlimitedenergy); - this.props.put("ue", unlimitedenergy); - } - - @Override - public void execute(Player sender, Player targetPlayer, List args) { - if (args.size() != 2) { - CommandHandler.sendTranslatedMessage(sender, "commands.setProp.usage"); - return; - } - String propStr = args.get(0).toLowerCase(); - String valueStr = args.get(1).toLowerCase(); - int value; - - if (!props.containsKey(propStr)) { - CommandHandler.sendTranslatedMessage(sender, "commands.setProp.usage"); - return; - } - try { - value = switch(valueStr.toLowerCase()) { - case "on", "true" -> 1; - case "off", "false" -> 0; - case "toggle" -> -1; - default -> Integer.parseInt(valueStr); - }; - } catch (NumberFormatException ignored) { - CommandHandler.sendTranslatedMessage(sender, "commands.execution.argument_error"); - return; - } - - boolean success = false; - Prop prop = props.get(propStr); - - success = switch (prop.pseudoProp) { - case WORLD_LEVEL -> targetPlayer.setWorldLevel(value); - case BP_LEVEL -> targetPlayer.getBattlePassManager().setLevel(value); - case TOWER_LEVEL -> this.setTowerLevel(sender, targetPlayer, value); - case GOD_MODE, NO_STAMINA, UNLIMITED_ENERGY -> this.setBool(sender, targetPlayer, prop.pseudoProp, value); - default -> targetPlayer.setProperty(prop.prop, value); - }; - - if (success) { - if (targetPlayer == sender) { - CommandHandler.sendTranslatedMessage(sender, "commands.generic.set_to", prop.name, valueStr); - } else { - String uidStr = targetPlayer.getAccount().getId(); - CommandHandler.sendTranslatedMessage(sender, "commands.generic.set_for_to", prop.name, uidStr, valueStr); - } - } else { - if (prop.prop != PlayerProperty.PROP_NONE) { // PseudoProps need to do their own error messages - String min = Integer.toString(targetPlayer.getPropertyMin(prop.prop)); - String max = Integer.toString(targetPlayer.getPropertyMax(prop.prop)); - CommandHandler.sendTranslatedMessage(sender, "commands.generic.invalid.value_between", prop.name, min, max); - } - } - } - - private boolean setTowerLevel(Player sender, Player targetPlayer, int topFloor) { - List floorIds = targetPlayer.getServer().getTowerSystem().getAllFloors(); - if (topFloor < 0 || topFloor > floorIds.size()) { - String min = Integer.toString(0); - String max = Integer.toString(floorIds.size()); - CommandHandler.sendTranslatedMessage(sender, "commands.generic.invalid.value_between", "Tower Level", min, max); - return false; - } - - Map recordMap = targetPlayer.getTowerManager().getRecordMap(); - // Add records for each unlocked floor - for (int floor : floorIds.subList(0, topFloor)) { - if (!recordMap.containsKey(floor)) { - recordMap.put(floor, new TowerLevelRecord(floor)); - } - } - // Remove records for each floor past our target - for (int floor : floorIds.subList(topFloor, floorIds.size())) { - if (recordMap.containsKey(floor)) { - recordMap.remove(floor); - } - } - // Six stars required on Floor 8 to unlock Floor 9+ - if (topFloor > 8) { - recordMap.get(floorIds.get(7)).setLevelStars(0, 6); // levelIds seem to start at 1 for Floor 1 Chamber 1, so this doesn't get shown at all - } - return true; - } - - private boolean setBool(Player sender, Player targetPlayer, PseudoProp pseudoProp, int value) { - boolean enabled = switch (pseudoProp) { - case GOD_MODE -> targetPlayer.inGodmode(); - case NO_STAMINA -> targetPlayer.getUnlimitedStamina(); - case UNLIMITED_ENERGY -> !targetPlayer.getEnergyManager().getEnergyUsage(); - default -> false; - }; - enabled = switch (value) { - case -1 -> !enabled; - case 0 -> false; - default -> true; - }; - - switch (pseudoProp) { - case GOD_MODE: - targetPlayer.setGodmode(enabled); - break; - case NO_STAMINA: - targetPlayer.setUnlimitedStamina(enabled); - break; - case UNLIMITED_ENERGY: - targetPlayer.getEnergyManager().setEnergyUsage(!enabled); - break; - default: - return false; - } - return true; - } -} +package emu.grasscutter.command.commands; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import emu.grasscutter.command.Command; +import emu.grasscutter.command.CommandHandler; +import emu.grasscutter.game.player.Player; +import emu.grasscutter.game.props.PlayerProperty; +import emu.grasscutter.game.tower.TowerLevelRecord; + +@Command(label = "setprop", usage = "setprop|prop ", aliases = {"prop"}, permission = "player.setprop", permissionTargeted = "player.setprop.others", description = "commands.setProp.description") +public final class SetPropCommand implements CommandHandler { + static enum PseudoProp { + NONE, + WORLD_LEVEL, + TOWER_LEVEL, + BP_LEVEL, + GOD_MODE, + NO_STAMINA, + UNLIMITED_ENERGY + } + + static class Prop { + String name; + PlayerProperty prop; + PseudoProp pseudoProp; + + public Prop(PlayerProperty prop) { + this(prop.toString(), prop, PseudoProp.NONE); + } + + public Prop(String name) { + this(name, PlayerProperty.PROP_NONE, PseudoProp.NONE); + } + + public Prop(String name, PseudoProp pseudoProp) { + this(name, PlayerProperty.PROP_NONE, pseudoProp); + } + + public Prop(String name, PlayerProperty prop) { + this(name, prop, PseudoProp.NONE); + } + + public Prop(String name, PlayerProperty prop, PseudoProp pseudoProp) { + this.name = name; + this.prop = prop; + this.pseudoProp = pseudoProp; + } + } + + Map props; + + public SetPropCommand() { + this.props = new HashMap<>(); + // Full PlayerProperty enum that won't be advertised but can be used by devs + for (PlayerProperty prop : PlayerProperty.values()) { + String name = prop.toString().substring(5); // PROP_EXP -> EXP + String key = name.toLowerCase(); // EXP -> exp + this.props.put(key, new Prop(name, prop)); + } + // Add special props + Prop worldlevel = new Prop("World Level", PlayerProperty.PROP_PLAYER_WORLD_LEVEL, PseudoProp.WORLD_LEVEL); + this.props.put("worldlevel", worldlevel); + this.props.put("wl", worldlevel); + + Prop abyss = new Prop("Tower Level", PseudoProp.TOWER_LEVEL); + this.props.put("abyss", abyss); + this.props.put("abyssfloor", abyss); + this.props.put("ut", abyss); + this.props.put("tower", abyss); + this.props.put("towerlevel", abyss); + this.props.put("unlocktower", abyss); + + Prop bplevel = new Prop("BP Level", PseudoProp.BP_LEVEL); + this.props.put("bplevel", bplevel); + this.props.put("bp", bplevel); + this.props.put("battlepass", bplevel); + + Prop godmode = new Prop("godmode", PseudoProp.GOD_MODE); + this.props.put("godmode", godmode); + this.props.put("god", godmode); + + Prop nostamina = new Prop("nostamina", PseudoProp.NO_STAMINA); + this.props.put("nostamina", nostamina); + this.props.put("nostam", nostamina); + this.props.put("ns", nostamina); + + Prop unlimitedenergy = new Prop("unlimitedenergy", PseudoProp.UNLIMITED_ENERGY); + this.props.put("unlimitedenergy", unlimitedenergy); + this.props.put("ue", unlimitedenergy); + } + + @Override + public void execute(Player sender, Player targetPlayer, List args) { + if (args.size() != 2) { + CommandHandler.sendTranslatedMessage(sender, "commands.setProp.usage"); + return; + } + String propStr = args.get(0).toLowerCase(); + String valueStr = args.get(1).toLowerCase(); + int value; + + if (!props.containsKey(propStr)) { + CommandHandler.sendTranslatedMessage(sender, "commands.setProp.usage"); + return; + } + try { + value = switch (valueStr.toLowerCase()) { + case "on", "true" -> 1; + case "off", "false" -> 0; + case "toggle" -> -1; + default -> Integer.parseInt(valueStr); + }; + } catch (NumberFormatException ignored) { + CommandHandler.sendTranslatedMessage(sender, "commands.execution.argument_error"); + return; + } + + boolean success = false; + Prop prop = props.get(propStr); + + success = switch (prop.pseudoProp) { + case WORLD_LEVEL -> targetPlayer.setWorldLevel(value); + case BP_LEVEL -> targetPlayer.getBattlePassManager().setLevel(value); + case TOWER_LEVEL -> this.setTowerLevel(sender, targetPlayer, value); + case GOD_MODE, NO_STAMINA, UNLIMITED_ENERGY -> this.setBool(sender, targetPlayer, prop.pseudoProp, value); + default -> targetPlayer.setProperty(prop.prop, value); + }; + + if (success) { + if (targetPlayer == sender) { + CommandHandler.sendTranslatedMessage(sender, "commands.generic.set_to", prop.name, valueStr); + } else { + String uidStr = targetPlayer.getAccount().getId(); + CommandHandler.sendTranslatedMessage(sender, "commands.generic.set_for_to", prop.name, uidStr, valueStr); + } + } else { + if (prop.prop != PlayerProperty.PROP_NONE) { // PseudoProps need to do their own error messages + String min = Integer.toString(targetPlayer.getPropertyMin(prop.prop)); + String max = Integer.toString(targetPlayer.getPropertyMax(prop.prop)); + CommandHandler.sendTranslatedMessage(sender, "commands.generic.invalid.value_between", prop.name, min, max); + } + } + } + + private boolean setTowerLevel(Player sender, Player targetPlayer, int topFloor) { + List floorIds = targetPlayer.getServer().getTowerSystem().getAllFloors(); + if (topFloor < 0 || topFloor > floorIds.size()) { + String min = Integer.toString(0); + String max = Integer.toString(floorIds.size()); + CommandHandler.sendTranslatedMessage(sender, "commands.generic.invalid.value_between", "Tower Level", min, max); + return false; + } + + Map recordMap = targetPlayer.getTowerManager().getRecordMap(); + // Add records for each unlocked floor + for (int floor : floorIds.subList(0, topFloor)) { + if (!recordMap.containsKey(floor)) { + recordMap.put(floor, new TowerLevelRecord(floor)); + } + } + // Remove records for each floor past our target + for (int floor : floorIds.subList(topFloor, floorIds.size())) { + if (recordMap.containsKey(floor)) { + recordMap.remove(floor); + } + } + // Six stars required on Floor 8 to unlock Floor 9+ + if (topFloor > 8) { + recordMap.get(floorIds.get(7)).setLevelStars(0, 6); // levelIds seem to start at 1 for Floor 1 Chamber 1, so this doesn't get shown at all + } + return true; + } + + private boolean setBool(Player sender, Player targetPlayer, PseudoProp pseudoProp, int value) { + boolean enabled = switch (pseudoProp) { + case GOD_MODE -> targetPlayer.inGodmode(); + case NO_STAMINA -> targetPlayer.getUnlimitedStamina(); + case UNLIMITED_ENERGY -> !targetPlayer.getEnergyManager().getEnergyUsage(); + default -> false; + }; + enabled = switch (value) { + case -1 -> !enabled; + case 0 -> false; + default -> true; + }; + + switch (pseudoProp) { + case GOD_MODE: + targetPlayer.setGodmode(enabled); + break; + case NO_STAMINA: + targetPlayer.setUnlimitedStamina(enabled); + break; + case UNLIMITED_ENERGY: + targetPlayer.getEnergyManager().setEnergyUsage(!enabled); + break; + default: + return false; + } + return true; + } +} diff --git a/src/main/java/emu/grasscutter/command/commands/SpawnCommand.java b/src/main/java/emu/grasscutter/command/commands/SpawnCommand.java index 1306991ef..b6a5040c0 100644 --- a/src/main/java/emu/grasscutter/command/commands/SpawnCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/SpawnCommand.java @@ -31,7 +31,7 @@ public final class SpawnCommand implements CommandHandler { int id = 0; // This is just to shut up the linter, it's not a real default int amount = 1; int level = 1; - float x = 0, y = 0, z = 0; + float x = 0, y = 0, z = 0; switch (args.size()) { case 6: try { @@ -64,7 +64,7 @@ public final class SpawnCommand implements CommandHandler { CommandHandler.sendMessage(sender, translate(sender, "commands.spawn.usage")); return; } - + MonsterData monsterData = GameData.getMonsterDataMap().get(id); GadgetData gadgetData = GameData.getGadgetDataMap().get(id); ItemData itemData = GameData.getItemDataMap().get(id); @@ -72,21 +72,21 @@ public final class SpawnCommand implements CommandHandler { CommandHandler.sendMessage(sender, translate(sender, "commands.generic.invalid.entityId")); return; } - + Scene scene = targetPlayer.getScene(); - + if (scene.getEntities().size() + amount > GAME_OPTIONS.sceneEntityLimit) { - amount = Math.max(Math.min(GAME_OPTIONS.sceneEntityLimit - scene.getEntities().size(), amount), 0); - CommandHandler.sendMessage(sender, translate(sender, "commands.spawn.limit_reached", amount)); - if (amount <= 0) { - return; - } + amount = Math.max(Math.min(GAME_OPTIONS.sceneEntityLimit - scene.getEntities().size(), amount), 0); + CommandHandler.sendMessage(sender, translate(sender, "commands.spawn.limit_reached", amount)); + if (amount <= 0) { + return; + } } double maxRadius = Math.sqrt(amount * 0.2 / Math.PI); for (int i = 0; i < amount; i++) { Position pos = GetRandomPositionInCircle(targetPlayer.getPosition(), maxRadius).addY(3); - if(x != 0 && y != 0 && z != 0) { + if (x != 0 && y != 0 && z != 0) { pos = GetRandomPositionInCircle(new Position(x, y, z), maxRadius).addY(3); } GameEntity entity = null; @@ -120,7 +120,7 @@ public final class SpawnCommand implements CommandHandler { CommandHandler.sendMessage(sender, translate(sender, "commands.spawn.success", Integer.toString(amount), Integer.toString(id))); } - private Position GetRandomPositionInCircle(Position origin, double radius){ + private Position GetRandomPositionInCircle(Position origin, double radius) { Position target = origin.clone(); double angle = Math.random() * 360; double r = Math.sqrt(Math.random() * radius * radius); diff --git a/src/main/java/emu/grasscutter/command/commands/TeamCommand.java b/src/main/java/emu/grasscutter/command/commands/TeamCommand.java index afcaa4a74..bd591d25b 100644 --- a/src/main/java/emu/grasscutter/command/commands/TeamCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/TeamCommand.java @@ -1,255 +1,255 @@ -package emu.grasscutter.command.commands; - -import emu.grasscutter.command.Command; -import emu.grasscutter.command.CommandHandler; -import emu.grasscutter.game.player.Player; -import emu.grasscutter.server.packet.send.PacketChangeMpTeamAvatarRsp; - -import java.util.List; - -import static emu.grasscutter.config.Configuration.*; - -import java.util.ArrayList; -import java.util.HashSet; - -@Command(label = "team", usage = "team [avatarId,...] [index|first|last|index-index,...]", -permission = "player.team", permissionTargeted = "player.team.others", description = "commands.team.description") -public final class TeamCommand implements CommandHandler { - private static final int BASE_AVATARID = 10000000; - - @Override - public void execute(Player sender, Player targetPlayer, List args) { - if (args.isEmpty()) { - CommandHandler.sendTranslatedMessage(sender, "commands.team.usage"); - return; - } - - switch (args.get(0)) { - case "add": - if (!addCommand(sender, targetPlayer, args)) return; - break; - - case "remove": - if (!removeCommand(sender, targetPlayer, args)) return; - break; - - case "set": - if (!setCommand(sender, targetPlayer, args)) return; - break; - - default: - CommandHandler.sendTranslatedMessage(sender, "commands.team.invalid_usage"); - CommandHandler.sendTranslatedMessage(sender, "commands.team.usage"); - return; - } - - targetPlayer.getTeamManager().updateTeamEntities( - new PacketChangeMpTeamAvatarRsp(targetPlayer, targetPlayer.getTeamManager().getCurrentTeamInfo())); - } - - private boolean addCommand(Player sender, Player targetPlayer, List args) { - if (args.size() < 2) { - CommandHandler.sendTranslatedMessage(sender, "commands.team.invalid_usage"); - CommandHandler.sendTranslatedMessage(sender, "commands.team.add_usage"); - return false; - } - - int index = -1; - if (args.size() > 2) { - try { - index = Integer.parseInt(args.get(2)) - 1; - if (index < 0) index = 0; - } catch (Exception e) { - CommandHandler.sendTranslatedMessage(sender, "commands.team.invalid_index"); - return false; - } - } - - var avatarIds = args.get(1).split(","); - var currentTeamAvatars = targetPlayer.getTeamManager().getCurrentTeamInfo().getAvatars(); - - if (currentTeamAvatars.size() + avatarIds.length > GAME_OPTIONS.avatarLimits.singlePlayerTeam) { - CommandHandler.sendTranslatedMessage(sender, "commands.team.add_too_much", GAME_OPTIONS.avatarLimits.singlePlayerTeam); - return false; - } - - for (var avatarId: avatarIds) { - int id = Integer.parseInt(avatarId); - var success = addAvatar(sender, targetPlayer, id, index); - if (index > 0) ++index; - } - return true; - } - - private boolean removeCommand(Player sender, Player targetPlayer, List args) { - if (args.size() < 2) { - CommandHandler.sendTranslatedMessage(sender, "commands.team.invalid_usage"); - CommandHandler.sendTranslatedMessage(sender, "commands.team.remove_usage"); - return false; - } - - var currentTeamAvatars = targetPlayer.getTeamManager().getCurrentTeamInfo().getAvatars(); - var avatarCount = currentTeamAvatars.size(); - - var metaIndexList = args.get(1).split(","); - var indexes = new HashSet(); - var ignoreList = new ArrayList(); - for (var metaIndex: metaIndexList) { - // step 1: parse metaIndex to indexes - var subIndexes = transformToIndexes(metaIndex, avatarCount); - if (subIndexes == null) { - CommandHandler.sendTranslatedMessage(sender, "commands.team.failed_to_parse_index", metaIndex); - continue; - } - - // step 2: get all of the avatar id through indexes - for (var avatarIndex: subIndexes) { - try { - indexes.add(currentTeamAvatars.get(avatarIndex - 1)); - } catch (Exception e) { - ignoreList.add(avatarIndex); - continue; - } - } - } - - // step 3: check if user remove all of the avatar - if (indexes.size() >= avatarCount) { - CommandHandler.sendTranslatedMessage(sender, "commands.team.remove_too_much"); - return false; - } - - // step 4: hint user for ignore index - if (!ignoreList.isEmpty()) { - CommandHandler.sendTranslatedMessage(sender, "commands.team.ignore_index", ignoreList); - } - - // step 5: remove - currentTeamAvatars.removeAll(indexes); - return true; - } - - private boolean setCommand(Player sender, Player targetPlayer, List args) { - if (args.size() < 3) { - CommandHandler.sendTranslatedMessage(sender, "commands.team.invalid_usage"); - CommandHandler.sendTranslatedMessage(sender, "commands.team.set_usage"); - return false; - } - - var currentTeamAvatars = targetPlayer.getTeamManager().getCurrentTeamInfo().getAvatars(); - - int index; - try { - index = Integer.parseInt(args.get(1)) - 1; - if (index < 0) index = 0; - } catch(Exception e) { - CommandHandler.sendTranslatedMessage(sender, "commands.team.failed_to_parse_index", args.get(1)); - return false; - } - - if (index + 1 > currentTeamAvatars.size()) { - CommandHandler.sendTranslatedMessage(sender, "commands.team.index_out_of_range"); - return false; - } - - int avatarId; - try { - avatarId = Integer.parseInt(args.get(2)); - } catch(Exception e) { - CommandHandler.sendTranslatedMessage(sender, "commands.team.failed_parse_avatar_id", args.get(2)); - return false; - } - if (avatarId < BASE_AVATARID) { - avatarId += BASE_AVATARID; - } - - if (currentTeamAvatars.contains(avatarId)) { - CommandHandler.sendTranslatedMessage(sender, "commands.team.avatar_already_in_team", avatarId); - return false; - } - - if (!targetPlayer.getAvatars().hasAvatar(avatarId)) { - CommandHandler.sendTranslatedMessage(sender, "commands.team.avatar_not_found", avatarId); - return false; - } - - currentTeamAvatars.set(index, avatarId); - return true; - } - - private boolean addAvatar(Player sender, Player targetPlayer, int avatarId, int index) { - if (avatarId < BASE_AVATARID) { - avatarId += BASE_AVATARID; - } - var currentTeamAvatars = targetPlayer.getTeamManager().getCurrentTeamInfo().getAvatars(); - if (currentTeamAvatars.contains(avatarId)) { - CommandHandler.sendTranslatedMessage(sender, "commands.team.avatar_already_in_team", avatarId); - return false; - } - if (!targetPlayer.getAvatars().hasAvatar(avatarId)) { - CommandHandler.sendTranslatedMessage(sender, "commands.team.avatar_not_found", avatarId); - return false; - } - if (index < 0) { - currentTeamAvatars.add(avatarId); - } else { - currentTeamAvatars.add(index, avatarId); - } - return true; - } - - private List transformToIndexes(String metaIndexes, int listLength) { - // step 1: check if metaIndexes is a special constants - if (metaIndexes.equals("first")) { - return List.of(1); - } else if (metaIndexes.equals("last")) { - return List.of(listLength); - } - - // step 2: check if metaIndexes is a range - if (metaIndexes.contains("-")) { - var range = metaIndexes.split("-"); - if (range.length < 2) { - return null; - } - - int min, max; - try { - min = switch (range[0]) { - case "first" -> 1; - case "last" -> listLength; - default -> Integer.parseInt(range[0]); - }; - - max = switch (range[1]) { - case "first" -> 1; - case "last" -> listLength; - default -> Integer.parseInt(range[1]); - }; - } catch (Exception e) { - return null; - } - - if (min > max) { - min ^= max; - max ^= min; - min ^= max; - } - - var indexes = new ArrayList(); - for (int i = min; i <= max; ++i) { - indexes.add(i); - } - return indexes; - } - - // step 3: index is a value, simply return - try { - int index = Integer.parseInt(metaIndexes); - return List.of(index); - } catch (Exception e) { - return null; - } - } - -} +package emu.grasscutter.command.commands; + +import emu.grasscutter.command.Command; +import emu.grasscutter.command.CommandHandler; +import emu.grasscutter.game.player.Player; +import emu.grasscutter.server.packet.send.PacketChangeMpTeamAvatarRsp; + +import java.util.List; + +import static emu.grasscutter.config.Configuration.*; + +import java.util.ArrayList; +import java.util.HashSet; + +@Command(label = "team", usage = "team [avatarId,...] [index|first|last|index-index,...]", +permission = "player.team", permissionTargeted = "player.team.others", description = "commands.team.description") +public final class TeamCommand implements CommandHandler { + private static final int BASE_AVATARID = 10000000; + + @Override + public void execute(Player sender, Player targetPlayer, List args) { + if (args.isEmpty()) { + CommandHandler.sendTranslatedMessage(sender, "commands.team.usage"); + return; + } + + switch (args.get(0)) { + case "add": + if (!addCommand(sender, targetPlayer, args)) return; + break; + + case "remove": + if (!removeCommand(sender, targetPlayer, args)) return; + break; + + case "set": + if (!setCommand(sender, targetPlayer, args)) return; + break; + + default: + CommandHandler.sendTranslatedMessage(sender, "commands.team.invalid_usage"); + CommandHandler.sendTranslatedMessage(sender, "commands.team.usage"); + return; + } + + targetPlayer.getTeamManager().updateTeamEntities( + new PacketChangeMpTeamAvatarRsp(targetPlayer, targetPlayer.getTeamManager().getCurrentTeamInfo())); + } + + private boolean addCommand(Player sender, Player targetPlayer, List args) { + if (args.size() < 2) { + CommandHandler.sendTranslatedMessage(sender, "commands.team.invalid_usage"); + CommandHandler.sendTranslatedMessage(sender, "commands.team.add_usage"); + return false; + } + + int index = -1; + if (args.size() > 2) { + try { + index = Integer.parseInt(args.get(2)) - 1; + if (index < 0) index = 0; + } catch (Exception e) { + CommandHandler.sendTranslatedMessage(sender, "commands.team.invalid_index"); + return false; + } + } + + var avatarIds = args.get(1).split(","); + var currentTeamAvatars = targetPlayer.getTeamManager().getCurrentTeamInfo().getAvatars(); + + if (currentTeamAvatars.size() + avatarIds.length > GAME_OPTIONS.avatarLimits.singlePlayerTeam) { + CommandHandler.sendTranslatedMessage(sender, "commands.team.add_too_much", GAME_OPTIONS.avatarLimits.singlePlayerTeam); + return false; + } + + for (var avatarId: avatarIds) { + int id = Integer.parseInt(avatarId); + var success = addAvatar(sender, targetPlayer, id, index); + if (index > 0) ++index; + } + return true; + } + + private boolean removeCommand(Player sender, Player targetPlayer, List args) { + if (args.size() < 2) { + CommandHandler.sendTranslatedMessage(sender, "commands.team.invalid_usage"); + CommandHandler.sendTranslatedMessage(sender, "commands.team.remove_usage"); + return false; + } + + var currentTeamAvatars = targetPlayer.getTeamManager().getCurrentTeamInfo().getAvatars(); + var avatarCount = currentTeamAvatars.size(); + + var metaIndexList = args.get(1).split(","); + var indexes = new HashSet(); + var ignoreList = new ArrayList(); + for (var metaIndex: metaIndexList) { + // step 1: parse metaIndex to indexes + var subIndexes = transformToIndexes(metaIndex, avatarCount); + if (subIndexes == null) { + CommandHandler.sendTranslatedMessage(sender, "commands.team.failed_to_parse_index", metaIndex); + continue; + } + + // step 2: get all of the avatar id through indexes + for (var avatarIndex: subIndexes) { + try { + indexes.add(currentTeamAvatars.get(avatarIndex - 1)); + } catch (Exception e) { + ignoreList.add(avatarIndex); + continue; + } + } + } + + // step 3: check if user remove all of the avatar + if (indexes.size() >= avatarCount) { + CommandHandler.sendTranslatedMessage(sender, "commands.team.remove_too_much"); + return false; + } + + // step 4: hint user for ignore index + if (!ignoreList.isEmpty()) { + CommandHandler.sendTranslatedMessage(sender, "commands.team.ignore_index", ignoreList); + } + + // step 5: remove + currentTeamAvatars.removeAll(indexes); + return true; + } + + private boolean setCommand(Player sender, Player targetPlayer, List args) { + if (args.size() < 3) { + CommandHandler.sendTranslatedMessage(sender, "commands.team.invalid_usage"); + CommandHandler.sendTranslatedMessage(sender, "commands.team.set_usage"); + return false; + } + + var currentTeamAvatars = targetPlayer.getTeamManager().getCurrentTeamInfo().getAvatars(); + + int index; + try { + index = Integer.parseInt(args.get(1)) - 1; + if (index < 0) index = 0; + } catch (Exception e) { + CommandHandler.sendTranslatedMessage(sender, "commands.team.failed_to_parse_index", args.get(1)); + return false; + } + + if (index + 1 > currentTeamAvatars.size()) { + CommandHandler.sendTranslatedMessage(sender, "commands.team.index_out_of_range"); + return false; + } + + int avatarId; + try { + avatarId = Integer.parseInt(args.get(2)); + } catch (Exception e) { + CommandHandler.sendTranslatedMessage(sender, "commands.team.failed_parse_avatar_id", args.get(2)); + return false; + } + if (avatarId < BASE_AVATARID) { + avatarId += BASE_AVATARID; + } + + if (currentTeamAvatars.contains(avatarId)) { + CommandHandler.sendTranslatedMessage(sender, "commands.team.avatar_already_in_team", avatarId); + return false; + } + + if (!targetPlayer.getAvatars().hasAvatar(avatarId)) { + CommandHandler.sendTranslatedMessage(sender, "commands.team.avatar_not_found", avatarId); + return false; + } + + currentTeamAvatars.set(index, avatarId); + return true; + } + + private boolean addAvatar(Player sender, Player targetPlayer, int avatarId, int index) { + if (avatarId < BASE_AVATARID) { + avatarId += BASE_AVATARID; + } + var currentTeamAvatars = targetPlayer.getTeamManager().getCurrentTeamInfo().getAvatars(); + if (currentTeamAvatars.contains(avatarId)) { + CommandHandler.sendTranslatedMessage(sender, "commands.team.avatar_already_in_team", avatarId); + return false; + } + if (!targetPlayer.getAvatars().hasAvatar(avatarId)) { + CommandHandler.sendTranslatedMessage(sender, "commands.team.avatar_not_found", avatarId); + return false; + } + if (index < 0) { + currentTeamAvatars.add(avatarId); + } else { + currentTeamAvatars.add(index, avatarId); + } + return true; + } + + private List transformToIndexes(String metaIndexes, int listLength) { + // step 1: check if metaIndexes is a special constants + if (metaIndexes.equals("first")) { + return List.of(1); + } else if (metaIndexes.equals("last")) { + return List.of(listLength); + } + + // step 2: check if metaIndexes is a range + if (metaIndexes.contains("-")) { + var range = metaIndexes.split("-"); + if (range.length < 2) { + return null; + } + + int min, max; + try { + min = switch (range[0]) { + case "first" -> 1; + case "last" -> listLength; + default -> Integer.parseInt(range[0]); + }; + + max = switch (range[1]) { + case "first" -> 1; + case "last" -> listLength; + default -> Integer.parseInt(range[1]); + }; + } catch (Exception e) { + return null; + } + + if (min > max) { + min ^= max; + max ^= min; + min ^= max; + } + + var indexes = new ArrayList(); + for (int i = min; i <= max; ++i) { + indexes.add(i); + } + return indexes; + } + + // step 3: index is a value, simply return + try { + int index = Integer.parseInt(metaIndexes); + return List.of(index); + } catch (Exception e) { + return null; + } + } + +} diff --git a/src/main/java/emu/grasscutter/command/commands/TeleportAllCommand.java b/src/main/java/emu/grasscutter/command/commands/TeleportAllCommand.java index 5e046a207..31597ae83 100644 --- a/src/main/java/emu/grasscutter/command/commands/TeleportAllCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/TeleportAllCommand.java @@ -19,7 +19,7 @@ public final class TeleportAllCommand implements CommandHandler { CommandHandler.sendMessage(sender, translate(sender, "commands.teleportAll.error")); return; } - + for (Player player : targetPlayer.getWorld().getPlayers()) { if (player.equals(targetPlayer)) continue; @@ -27,7 +27,7 @@ public final class TeleportAllCommand implements CommandHandler { player.getWorld().transferPlayerToScene(player, targetPlayer.getSceneId(), pos); } - + CommandHandler.sendMessage(sender, translate(sender, "commands.teleportAll.success")); } } diff --git a/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java b/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java index 21d898af9..4153a83c2 100644 --- a/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/TeleportCommand.java @@ -58,8 +58,8 @@ public final class TeleportCommand implements CommandHandler { if (!result) { CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.exists_error")); } else { - CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.success", - targetPlayer.getNickname(), Float.toString(x), Float.toString(y), + CommandHandler.sendMessage(sender, translate(sender, "commands.teleport.success", + targetPlayer.getNickname(), Float.toString(x), Float.toString(y), Float.toString(z), Integer.toString(sceneId)) ); } diff --git a/src/main/java/emu/grasscutter/config/ConfigContainer.java b/src/main/java/emu/grasscutter/config/ConfigContainer.java index 619775dc8..1817ddc2a 100644 --- a/src/main/java/emu/grasscutter/config/ConfigContainer.java +++ b/src/main/java/emu/grasscutter/config/ConfigContainer.java @@ -28,7 +28,7 @@ public class ConfigContainer { try { // Check if the server is using a legacy config. JsonObject configObject = Grasscutter.getGsonFactory() .fromJson(new FileReader(Grasscutter.configFile), JsonObject.class); - if(!configObject.has("version")) { + if (!configObject.has("version")) { Grasscutter.getLogger().info("Updating legacy .."); Grasscutter.saveConfig(null); } @@ -37,7 +37,7 @@ public class ConfigContainer { var existing = config.version; var latest = version(); - if(existing == latest) + if (existing == latest) return; // Create a new configuration instance. @@ -135,20 +135,20 @@ public class ConfigContainer { public static class Game { public String bindAddress = "0.0.0.0"; public int bindPort = 22102; - + /* This is the address used in the default region. */ public String accessAddress = "127.0.0.1"; /* This is the port used in the default region. */ public int accessPort = 0; - + /* Entities within a certain range will be loaded for the player */ public int loadEntitiesForPlayerRange = 100; public boolean enableScriptInBigWorld = false; public boolean enableConsole = true; - + /* Controls whether packets should be logged in console or not */ public ServerDebugMode logPackets = ServerDebugMode.NONE; - + public GameOptions gameOptions = new GameOptions(); public JoinOptions joinOptions = new JoinOptions(); public ConsoleAccount serverAccount = new ConsoleAccount(); @@ -160,7 +160,7 @@ public class ConfigContainer { public Region[] regions = {}; public String defaultName = "Grasscutter"; - + public ServerDebugMode logRequests = ServerDebugMode.NONE; } @@ -276,4 +276,4 @@ public class ConfigContainer { public String Ip = "127.0.0.1"; public int Port = 22102; } -} \ No newline at end of file +} diff --git a/src/main/java/emu/grasscutter/config/Configuration.java b/src/main/java/emu/grasscutter/config/Configuration.java index 82c7b3f71..7c769b3a3 100644 --- a/src/main/java/emu/grasscutter/config/Configuration.java +++ b/src/main/java/emu/grasscutter/config/Configuration.java @@ -9,19 +9,19 @@ import static emu.grasscutter.Grasscutter.config; /** * A data container for the server's configuration. - * + * * Use `import static emu.grasscutter.Configuration.*;` * to import all configuration constants. */ public final class Configuration extends ConfigContainer { - + /* * Constants */ - + // 'c' is short for 'config' and makes code look 'cleaner'. public static final ConfigContainer c = config; - + public static final Locale LANGUAGE = config.language.language; public static final Locale FALLBACK_LANGUAGE = config.language.fallback; public static final String DOCUMENT_LANGUAGE = config.language.document; @@ -30,22 +30,22 @@ public final class Configuration extends ConfigContainer { private static final String PLUGINS_FOLDER = config.folderStructure.plugins; private static final String SCRIPTS_FOLDER = config.folderStructure.scripts; private static final String PACKETS_FOLDER = config.folderStructure.packets; - + public static final Server SERVER = config.server; public static final Database DATABASE = config.databaseInfo; public static final Account ACCOUNT = config.account; - + public static final HTTP HTTP_INFO = config.server.http; public static final Game GAME_INFO = config.server.game; public static final Dispatch DISPATCH_INFO = config.server.dispatch; - + public static final Encryption HTTP_ENCRYPTION = config.server.http.encryption; public static final Policies HTTP_POLICIES = config.server.http.policies; public static final Files HTTP_STATIC_FILES = config.server.http.files; - + public static final GameOptions GAME_OPTIONS = config.server.game.gameOptions; public static final GameOptions.InventoryLimits INVENTORY_LIMITS = config.server.game.gameOptions.inventoryLimits; - + /* * Utilities */ @@ -56,11 +56,11 @@ public final class Configuration extends ConfigContainer { public static String DATA(String path) { return Paths.get(DATA_FOLDER, path).toString(); } - + public static String RESOURCE(String path) { return Paths.get(RESOURCES_FOLDER, path).toString(); } - + public static String PLUGIN() { return PLUGINS_FOLDER; } diff --git a/src/main/java/emu/grasscutter/data/DataLoader.java b/src/main/java/emu/grasscutter/data/DataLoader.java index a006448f3..902996593 100644 --- a/src/main/java/emu/grasscutter/data/DataLoader.java +++ b/src/main/java/emu/grasscutter/data/DataLoader.java @@ -29,7 +29,7 @@ public class DataLoader { public static InputStream load(String resourcePath) throws FileNotFoundException { return load(resourcePath, true); } - + /** * Creates an input stream reader for a data file. If the file isn't found within the /data directory then it will fallback to the default within the jar resources * diff --git a/src/main/java/emu/grasscutter/data/GameDepot.java b/src/main/java/emu/grasscutter/data/GameDepot.java index 76b9b7c6f..a809105fa 100644 --- a/src/main/java/emu/grasscutter/data/GameDepot.java +++ b/src/main/java/emu/grasscutter/data/GameDepot.java @@ -22,47 +22,47 @@ public class GameDepot { private static Int2ObjectMap> relicMainPropDepot = new Int2ObjectOpenHashMap<>(); private static Int2ObjectMap> relicAffixDepot = new Int2ObjectOpenHashMap<>(); - private static Map playerAbilities = new HashMap<>(); + private static Map playerAbilities = new HashMap<>(); private static HashMap> spawnLists = new HashMap<>(); public static void load() { - for (ReliquaryMainPropData data : GameData.getReliquaryMainPropDataMap().values()) { - if (data.getWeight() <= 0 || data.getPropDepotId() <= 0) { - continue; - } + for (ReliquaryMainPropData data : GameData.getReliquaryMainPropDataMap().values()) { + if (data.getWeight() <= 0 || data.getPropDepotId() <= 0) { + continue; + } List list = relicMainPropDepot.computeIfAbsent(data.getPropDepotId(), k -> new ArrayList<>()); list.add(data); WeightedList weightedList = relicRandomMainPropDepot.computeIfAbsent(data.getPropDepotId(), k -> new WeightedList<>()); weightedList.add(data.getWeight(), data); - } - for (ReliquaryAffixData data : GameData.getReliquaryAffixDataMap().values()) { - if (data.getWeight() <= 0 || data.getDepotId() <= 0) { - continue; - } - List list = relicAffixDepot.computeIfAbsent(data.getDepotId(), k -> new ArrayList<>()); - list.add(data); - } - // Let the server owner know if theyre missing weights - if (relicMainPropDepot.size() == 0 || relicAffixDepot.size() == 0) { - Grasscutter.getLogger().error("Relic properties are missing weights! Please check your ReliquaryMainPropExcelConfigData or ReliquaryAffixExcelConfigData files in your ExcelBinOutput folder."); - } - } + } + for (ReliquaryAffixData data : GameData.getReliquaryAffixDataMap().values()) { + if (data.getWeight() <= 0 || data.getDepotId() <= 0) { + continue; + } + List list = relicAffixDepot.computeIfAbsent(data.getDepotId(), k -> new ArrayList<>()); + list.add(data); + } + // Let the server owner know if theyre missing weights + if (relicMainPropDepot.size() == 0 || relicAffixDepot.size() == 0) { + Grasscutter.getLogger().error("Relic properties are missing weights! Please check your ReliquaryMainPropExcelConfigData or ReliquaryAffixExcelConfigData files in your ExcelBinOutput folder."); + } + } - public static ReliquaryMainPropData getRandomRelicMainProp(int depot) { + public static ReliquaryMainPropData getRandomRelicMainProp(int depot) { WeightedList depotList = relicRandomMainPropDepot.get(depot); - if (depotList == null) { - return null; - } - return depotList.next(); - } + if (depotList == null) { + return null; + } + return depotList.next(); + } public static List getRelicMainPropList(int depot) { return relicMainPropDepot.get(depot); } public static List getRelicAffixList(int depot) { - return relicAffixDepot.get(depot); - } + return relicAffixDepot.get(depot); + } public static HashMap> getSpawnLists() { return spawnLists; @@ -72,9 +72,9 @@ public class GameDepot { spawnLists.putAll(data); } - public static void setPlayerAbilities(Map playerAbilities) { - GameDepot.playerAbilities = playerAbilities; - } + public static void setPlayerAbilities(Map playerAbilities) { + GameDepot.playerAbilities = playerAbilities; + } public static Map getPlayerAbilities() { return playerAbilities; diff --git a/src/main/java/emu/grasscutter/data/ResourceLoader.java b/src/main/java/emu/grasscutter/data/ResourceLoader.java index 70b006567..61b329250 100644 --- a/src/main/java/emu/grasscutter/data/ResourceLoader.java +++ b/src/main/java/emu/grasscutter/data/ResourceLoader.java @@ -34,281 +34,281 @@ import static emu.grasscutter.utils.Language.translate; public class ResourceLoader { - private static final List loadedResources = new ArrayList<>(); + private static final List loadedResources = new ArrayList<>(); - public static List> getResourceDefClasses() { - Reflections reflections = new Reflections(ResourceLoader.class.getPackage().getName()); - Set classes = reflections.getSubTypesOf(GameResource.class); + public static List> getResourceDefClasses() { + Reflections reflections = new Reflections(ResourceLoader.class.getPackage().getName()); + Set classes = reflections.getSubTypesOf(GameResource.class); - List> classList = new ArrayList<>(classes.size()); - classes.forEach(o -> { - Class c = (Class) o; - if (c.getAnnotation(ResourceType.class) != null) { - classList.add(c); - } - }); + List> classList = new ArrayList<>(classes.size()); + classes.forEach(o -> { + Class c = (Class) o; + if (c.getAnnotation(ResourceType.class) != null) { + classList.add(c); + } + }); - classList.sort((a, b) -> b.getAnnotation(ResourceType.class).loadPriority().value() - a.getAnnotation(ResourceType.class).loadPriority().value()); + classList.sort((a, b) -> b.getAnnotation(ResourceType.class).loadPriority().value() - a.getAnnotation(ResourceType.class).loadPriority().value()); - return classList; - } + return classList; + } - public static void loadAll() { + public static void loadAll() { Grasscutter.getLogger().info(translate("messages.status.resources.loading")); - // Load ability lists - loadAbilityEmbryos(); - loadOpenConfig(); - loadAbilityModifiers(); - // Load resources - loadResources(); - // Process into depots - GameDepot.load(); - // Load spawn data and quests - loadSpawnData(); - loadQuests(); - // Load scene points - must be done AFTER resources are loaded - loadScenePoints(); - // Load default home layout - loadHomeworldDefaultSaveData(); - loadNpcBornData(); + // Load ability lists + loadAbilityEmbryos(); + loadOpenConfig(); + loadAbilityModifiers(); + // Load resources + loadResources(); + // Process into depots + GameDepot.load(); + // Load spawn data and quests + loadSpawnData(); + loadQuests(); + // Load scene points - must be done AFTER resources are loaded + loadScenePoints(); + // Load default home layout + loadHomeworldDefaultSaveData(); + loadNpcBornData(); Grasscutter.getLogger().info(translate("messages.status.resources.finish")); - } + } - public static void loadResources() { - loadResources(false); - } + public static void loadResources() { + loadResources(false); + } - public static void loadResources(boolean doReload) { - for (Class resourceDefinition : getResourceDefClasses()) { - ResourceType type = resourceDefinition.getAnnotation(ResourceType.class); + public static void loadResources(boolean doReload) { + for (Class resourceDefinition : getResourceDefClasses()) { + ResourceType type = resourceDefinition.getAnnotation(ResourceType.class); - if (type == null) { - continue; - } + if (type == null) { + continue; + } - @SuppressWarnings("rawtypes") - Int2ObjectMap map = GameData.getMapByResourceDef(resourceDefinition); + @SuppressWarnings("rawtypes") + Int2ObjectMap map = GameData.getMapByResourceDef(resourceDefinition); - if (map == null) { - continue; - } + if (map == null) { + continue; + } - try { - loadFromResource(resourceDefinition, type, map, doReload); - } catch (Exception e) { - Grasscutter.getLogger().error("Error loading resource file: " + Arrays.toString(type.name()), e); - } - } - } + try { + loadFromResource(resourceDefinition, type, map, doReload); + } catch (Exception e) { + Grasscutter.getLogger().error("Error loading resource file: " + Arrays.toString(type.name()), e); + } + } + } - @SuppressWarnings("rawtypes") - protected static void loadFromResource(Class c, ResourceType type, Int2ObjectMap map, boolean doReload) throws Exception { - if(!loadedResources.contains(c.getSimpleName()) || doReload) { - for (String name : type.name()) { - loadFromResource(c, name, map); - } - loadedResources.add(c.getSimpleName()); + @SuppressWarnings("rawtypes") + protected static void loadFromResource(Class c, ResourceType type, Int2ObjectMap map, boolean doReload) throws Exception { + if (!loadedResources.contains(c.getSimpleName()) || doReload) { + for (String name : type.name()) { + loadFromResource(c, name, map); + } + loadedResources.add(c.getSimpleName()); Grasscutter.getLogger().debug("Loaded " + map.size() + " " + c.getSimpleName() + "s."); - } - } + } + } - @SuppressWarnings({"rawtypes", "unchecked"}) - protected static void loadFromResource(Class c, String fileName, Int2ObjectMap map) throws Exception { - try (FileReader fileReader = new FileReader(RESOURCE("ExcelBinOutput/" + fileName))) { - List list = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, c).getType()); + @SuppressWarnings({"rawtypes", "unchecked"}) + protected static void loadFromResource(Class c, String fileName, Int2ObjectMap map) throws Exception { + try (FileReader fileReader = new FileReader(RESOURCE("ExcelBinOutput/" + fileName))) { + List list = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, c).getType()); - for (Object o : list) { - GameResource res = (GameResource) o; - res.onLoad(); - map.put(res.getId(), res); - } - } - } + for (Object o : list) { + GameResource res = (GameResource) o; + res.onLoad(); + map.put(res.getId(), res); + } + } + } - private static void loadScenePoints() { - Pattern pattern = Pattern.compile("(?<=scene)(.*?)(?=_point.json)"); - File folder = new File(RESOURCE("BinOutput/Scene/Point")); + private static void loadScenePoints() { + Pattern pattern = Pattern.compile("(?<=scene)(.*?)(?=_point.json)"); + File folder = new File(RESOURCE("BinOutput/Scene/Point")); - if (!folder.isDirectory() || !folder.exists() || folder.listFiles() == null) { - Grasscutter.getLogger().error("Scene point files cannot be found, you cannot use teleport waypoints!"); - return; - } + if (!folder.isDirectory() || !folder.exists() || folder.listFiles() == null) { + Grasscutter.getLogger().error("Scene point files cannot be found, you cannot use teleport waypoints!"); + return; + } - List scenePointList = new ArrayList<>(); - for (File file : Objects.requireNonNull(folder.listFiles())) { - ScenePointConfig config; Integer sceneId; + List scenePointList = new ArrayList<>(); + for (File file : Objects.requireNonNull(folder.listFiles())) { + ScenePointConfig config; Integer sceneId; - Matcher matcher = pattern.matcher(file.getName()); - if (matcher.find()) { - sceneId = Integer.parseInt(matcher.group(1)); - } else { - continue; - } + Matcher matcher = pattern.matcher(file.getName()); + if (matcher.find()) { + sceneId = Integer.parseInt(matcher.group(1)); + } else { + continue; + } - try (FileReader fileReader = new FileReader(file)) { - config = Grasscutter.getGsonFactory().fromJson(fileReader, ScenePointConfig.class); - } catch (Exception e) { - e.printStackTrace(); - continue; - } + try (FileReader fileReader = new FileReader(file)) { + config = Grasscutter.getGsonFactory().fromJson(fileReader, ScenePointConfig.class); + } catch (Exception e) { + e.printStackTrace(); + continue; + } - if (config.points == null) { - continue; - } + if (config.points == null) { + continue; + } - for (Map.Entry entry : config.points.entrySet()) { - PointData pointData = Grasscutter.getGsonFactory().fromJson(entry.getValue(), PointData.class); - pointData.setId(Integer.parseInt(entry.getKey())); + for (Map.Entry entry : config.points.entrySet()) { + PointData pointData = Grasscutter.getGsonFactory().fromJson(entry.getValue(), PointData.class); + pointData.setId(Integer.parseInt(entry.getKey())); - ScenePointEntry sl = new ScenePointEntry(sceneId + "_" + entry.getKey(), pointData); - scenePointList.add(sl); - GameData.getScenePointIdList().add(pointData.getId()); + ScenePointEntry sl = new ScenePointEntry(sceneId + "_" + entry.getKey(), pointData); + scenePointList.add(sl); + GameData.getScenePointIdList().add(pointData.getId()); - pointData.updateDailyDungeon(); - } + pointData.updateDailyDungeon(); + } - for (ScenePointEntry entry : scenePointList) { - GameData.getScenePointEntries().put(entry.getName(), entry); - } - } - } + for (ScenePointEntry entry : scenePointList) { + GameData.getScenePointEntries().put(entry.getName(), entry); + } + } + } - private static void loadAbilityEmbryos() { - List embryoList = null; + private static void loadAbilityEmbryos() { + List embryoList = null; - // Read from cached file if exists - try (InputStream embryoCache = DataLoader.load("AbilityEmbryos.json", false)) { - embryoList = Grasscutter.getGsonFactory().fromJson(new InputStreamReader(embryoCache), TypeToken.getParameterized(Collection.class, AbilityEmbryoEntry.class).getType()); - } catch (Exception ignored) {} + // Read from cached file if exists + try (InputStream embryoCache = DataLoader.load("AbilityEmbryos.json", false)) { + embryoList = Grasscutter.getGsonFactory().fromJson(new InputStreamReader(embryoCache), TypeToken.getParameterized(Collection.class, AbilityEmbryoEntry.class).getType()); + } catch (Exception ignored) {} - if(embryoList == null) { - // Load from BinOutput - Pattern pattern = Pattern.compile("(?<=ConfigAvatar_)(.*?)(?=.json)"); + if (embryoList == null) { + // Load from BinOutput + Pattern pattern = Pattern.compile("(?<=ConfigAvatar_)(.*?)(?=.json)"); - embryoList = new LinkedList<>(); - File folder = new File(Utils.toFilePath(RESOURCE("BinOutput/Avatar/"))); - File[] files = folder.listFiles(); - if(files == null) { - Grasscutter.getLogger().error("Error loading ability embryos: no files found in " + folder.getAbsolutePath()); - return; - } + embryoList = new LinkedList<>(); + File folder = new File(Utils.toFilePath(RESOURCE("BinOutput/Avatar/"))); + File[] files = folder.listFiles(); + if (files == null) { + Grasscutter.getLogger().error("Error loading ability embryos: no files found in " + folder.getAbsolutePath()); + return; + } - for (File file : files) { - AvatarConfig config; - String avatarName; + for (File file : files) { + AvatarConfig config; + String avatarName; - Matcher matcher = pattern.matcher(file.getName()); - if (matcher.find()) { - avatarName = matcher.group(0); - } else { - continue; - } + Matcher matcher = pattern.matcher(file.getName()); + if (matcher.find()) { + avatarName = matcher.group(0); + } else { + continue; + } - try (FileReader fileReader = new FileReader(file)) { - config = Grasscutter.getGsonFactory().fromJson(fileReader, AvatarConfig.class); - } catch (Exception e) { - e.printStackTrace(); - continue; - } + try (FileReader fileReader = new FileReader(file)) { + config = Grasscutter.getGsonFactory().fromJson(fileReader, AvatarConfig.class); + } catch (Exception e) { + e.printStackTrace(); + continue; + } - if (config.abilities == null) { - continue; - } + if (config.abilities == null) { + continue; + } - int s = config.abilities.size(); - AbilityEmbryoEntry al = new AbilityEmbryoEntry(avatarName, config.abilities.stream().map(Object::toString).toArray(size -> new String[s])); - embryoList.add(al); - } + int s = config.abilities.size(); + AbilityEmbryoEntry al = new AbilityEmbryoEntry(avatarName, config.abilities.stream().map(Object::toString).toArray(size -> new String[s])); + embryoList.add(al); + } - File playerElementsFile = new File(Utils.toFilePath(RESOURCE("BinOutput/AbilityGroup/AbilityGroup_Other_PlayerElementAbility.json"))); + File playerElementsFile = new File(Utils.toFilePath(RESOURCE("BinOutput/AbilityGroup/AbilityGroup_Other_PlayerElementAbility.json"))); - if (playerElementsFile.exists()) { - try (FileReader fileReader = new FileReader(playerElementsFile)) { - GameDepot.setPlayerAbilities(Grasscutter.getGsonFactory().fromJson(fileReader, new TypeToken>(){}.getType())); - } catch (Exception e) { - e.printStackTrace(); - } - } - } + if (playerElementsFile.exists()) { + try (FileReader fileReader = new FileReader(playerElementsFile)) { + GameDepot.setPlayerAbilities(Grasscutter.getGsonFactory().fromJson(fileReader, new TypeToken>(){}.getType())); + } catch (Exception e) { + e.printStackTrace(); + } + } + } - if (embryoList == null || embryoList.isEmpty()) { - Grasscutter.getLogger().error("No embryos loaded!"); - return; - } + if (embryoList == null || embryoList.isEmpty()) { + Grasscutter.getLogger().error("No embryos loaded!"); + return; + } - for (AbilityEmbryoEntry entry : embryoList) { - GameData.getAbilityEmbryoInfo().put(entry.getName(), entry); - } - } + for (AbilityEmbryoEntry entry : embryoList) { + GameData.getAbilityEmbryoInfo().put(entry.getName(), entry); + } + } - private static void loadAbilityModifiers() { - // Load from BinOutput - File folder = new File(Utils.toFilePath(RESOURCE("BinOutput/Ability/Temp/AvatarAbilities/"))); - File[] files = folder.listFiles(); - if (files == null) { - Grasscutter.getLogger().error("Error loading ability modifiers: no files found in " + folder.getAbsolutePath()); - return; - } + private static void loadAbilityModifiers() { + // Load from BinOutput + File folder = new File(Utils.toFilePath(RESOURCE("BinOutput/Ability/Temp/AvatarAbilities/"))); + File[] files = folder.listFiles(); + if (files == null) { + Grasscutter.getLogger().error("Error loading ability modifiers: no files found in " + folder.getAbsolutePath()); + return; + } - for (File file : files) { - List abilityConfigList; + for (File file : files) { + List abilityConfigList; - try (FileReader fileReader = new FileReader(file)) { - abilityConfigList = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, AbilityConfigData.class).getType()); - } catch (Exception e) { - e.printStackTrace(); - continue; - } + try (FileReader fileReader = new FileReader(file)) { + abilityConfigList = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, AbilityConfigData.class).getType()); + } catch (Exception e) { + e.printStackTrace(); + continue; + } - for (AbilityConfigData data : abilityConfigList) { - if (data.Default.modifiers == null || data.Default.modifiers.size() == 0) { - continue; - } + for (AbilityConfigData data : abilityConfigList) { + if (data.Default.modifiers == null || data.Default.modifiers.size() == 0) { + continue; + } - AbilityModifierEntry modifierEntry = new AbilityModifierEntry(data.Default.abilityName); + AbilityModifierEntry modifierEntry = new AbilityModifierEntry(data.Default.abilityName); - for (Entry entry : data.Default.modifiers.entrySet()) { - AbilityModifier modifier = entry.getValue(); + for (Entry entry : data.Default.modifiers.entrySet()) { + AbilityModifier modifier = entry.getValue(); - // Stare. - if (modifier.onAdded != null) { - for (AbilityModifierAction action : modifier.onAdded) { - if (action.$type.contains("HealHP")) { - action.type = AbilityModifierActionType.HealHP; - modifierEntry.getOnAdded().add(action); - } - } - } + // Stare. + if (modifier.onAdded != null) { + for (AbilityModifierAction action : modifier.onAdded) { + if (action.$type.contains("HealHP")) { + action.type = AbilityModifierActionType.HealHP; + modifierEntry.getOnAdded().add(action); + } + } + } - if (modifier.onThinkInterval != null) { - for (AbilityModifierAction action : modifier.onThinkInterval) { - if (action.$type.contains("HealHP")) { - action.type = AbilityModifierActionType.HealHP; - modifierEntry.getOnThinkInterval().add(action); - } - } - } + if (modifier.onThinkInterval != null) { + for (AbilityModifierAction action : modifier.onThinkInterval) { + if (action.$type.contains("HealHP")) { + action.type = AbilityModifierActionType.HealHP; + modifierEntry.getOnThinkInterval().add(action); + } + } + } - if (modifier.onRemoved != null) { - for (AbilityModifierAction action : modifier.onRemoved) { - if (action.$type.contains("HealHP")) { - action.type = AbilityModifierActionType.HealHP; - modifierEntry.getOnRemoved().add(action); - } - } - } - } + if (modifier.onRemoved != null) { + for (AbilityModifierAction action : modifier.onRemoved) { + if (action.$type.contains("HealHP")) { + action.type = AbilityModifierActionType.HealHP; + modifierEntry.getOnRemoved().add(action); + } + } + } + } - GameData.getAbilityModifiers().put(modifierEntry.getName(), modifierEntry); - } - } - } + GameData.getAbilityModifiers().put(modifierEntry.getName(), modifierEntry); + } + } + } - private static void loadSpawnData() { - String[] spawnDataNames = {"Spawns.json", "GadgetSpawns.json"}; - ArrayList spawnEntryMap = new ArrayList<>(); + private static void loadSpawnData() { + String[] spawnDataNames = {"Spawns.json", "GadgetSpawns.json"}; + ArrayList spawnEntryMap = new ArrayList<>(); for (String name : spawnDataNames) { // Load spawn entries from file @@ -321,10 +321,10 @@ public class ResourceLoader { } catch (Exception ignored) {} } - if (spawnEntryMap.isEmpty()) { - Grasscutter.getLogger().error("No spawn data loaded!"); - return; - } + if (spawnEntryMap.isEmpty()) { + Grasscutter.getLogger().error("No spawn data loaded!"); + return; + } HashMap> areaSort = new HashMap<>(); //key = sceneId,x,z , value = ArrayList @@ -333,7 +333,7 @@ public class ResourceLoader { s -> { s.setGroup(entry); GridBlockId point = s.getBlockId(); - if(!areaSort.containsKey(point)) { + if (!areaSort.containsKey(point)) { areaSort.put(point, new ArrayList<>()); } areaSort.get(point).add(s); @@ -341,155 +341,155 @@ public class ResourceLoader { ); } GameDepot.addSpawnListById(areaSort); - } + } - private static void loadOpenConfig() { - // Read from cached file if exists - List list = null; + private static void loadOpenConfig() { + // Read from cached file if exists + List list = null; - try(InputStream openConfigCache = DataLoader.load("OpenConfig.json", false)) { - list = Grasscutter.getGsonFactory().fromJson(new InputStreamReader(openConfigCache), TypeToken.getParameterized(Collection.class, SpawnGroupEntry.class).getType()); - } catch (Exception ignored) {} + try (InputStream openConfigCache = DataLoader.load("OpenConfig.json", false)) { + list = Grasscutter.getGsonFactory().fromJson(new InputStreamReader(openConfigCache), TypeToken.getParameterized(Collection.class, SpawnGroupEntry.class).getType()); + } catch (Exception ignored) {} - if (list == null) { - Map map = new TreeMap<>(); - java.lang.reflect.Type type = new TypeToken>() {}.getType(); - String[] folderNames = {"BinOutput/Talent/EquipTalents/", "BinOutput/Talent/AvatarTalents/"}; + if (list == null) { + Map map = new TreeMap<>(); + java.lang.reflect.Type type = new TypeToken>() {}.getType(); + String[] folderNames = {"BinOutput/Talent/EquipTalents/", "BinOutput/Talent/AvatarTalents/"}; - for (String name : folderNames) { - File folder = new File(Utils.toFilePath(RESOURCE(name))); - File[] files = folder.listFiles(); - if(files == null) { - Grasscutter.getLogger().error("Error loading open config: no files found in " + folder.getAbsolutePath()); return; - } + for (String name : folderNames) { + File folder = new File(Utils.toFilePath(RESOURCE(name))); + File[] files = folder.listFiles(); + if (files == null) { + Grasscutter.getLogger().error("Error loading open config: no files found in " + folder.getAbsolutePath()); return; + } - for (File file : files) { - if (!file.getName().endsWith(".json")) { - continue; - } + for (File file : files) { + if (!file.getName().endsWith(".json")) { + continue; + } - Map config; + Map config; - try (FileReader fileReader = new FileReader(file)) { - config = Grasscutter.getGsonFactory().fromJson(fileReader, type); - } catch (Exception e) { - e.printStackTrace(); - continue; - } + try (FileReader fileReader = new FileReader(file)) { + config = Grasscutter.getGsonFactory().fromJson(fileReader, type); + } catch (Exception e) { + e.printStackTrace(); + continue; + } - for (Entry e : config.entrySet()) { - OpenConfigEntry entry = new OpenConfigEntry(e.getKey(), e.getValue()); - map.put(entry.getName(), entry); - } - } - } + for (Entry e : config.entrySet()) { + OpenConfigEntry entry = new OpenConfigEntry(e.getKey(), e.getValue()); + map.put(entry.getName(), entry); + } + } + } - list = new ArrayList<>(map.values()); - } + list = new ArrayList<>(map.values()); + } - if (list == null || list.isEmpty()) { - Grasscutter.getLogger().error("No openconfig entries loaded!"); - return; - } + if (list == null || list.isEmpty()) { + Grasscutter.getLogger().error("No openconfig entries loaded!"); + return; + } - for (OpenConfigEntry entry : list) { - GameData.getOpenConfigEntries().put(entry.getName(), entry); - } - } + for (OpenConfigEntry entry : list) { + GameData.getOpenConfigEntries().put(entry.getName(), entry); + } + } - private static void loadQuests() { - File folder = new File(RESOURCE("BinOutput/Quest/")); + private static void loadQuests() { + File folder = new File(RESOURCE("BinOutput/Quest/")); - if (!folder.exists()) { - return; - } + if (!folder.exists()) { + return; + } - for (File file : folder.listFiles()) { - MainQuestData mainQuest = null; + for (File file : folder.listFiles()) { + MainQuestData mainQuest = null; - try (FileReader fileReader = new FileReader(file)) { - mainQuest = Grasscutter.getGsonFactory().fromJson(fileReader, MainQuestData.class); - } catch (Exception e) { - e.printStackTrace(); - continue; - } + try (FileReader fileReader = new FileReader(file)) { + mainQuest = Grasscutter.getGsonFactory().fromJson(fileReader, MainQuestData.class); + } catch (Exception e) { + e.printStackTrace(); + continue; + } - GameData.getMainQuestDataMap().put(mainQuest.getId(), mainQuest); - } + GameData.getMainQuestDataMap().put(mainQuest.getId(), mainQuest); + } - Grasscutter.getLogger().debug("Loaded " + GameData.getMainQuestDataMap().size() + " MainQuestDatas."); - } + Grasscutter.getLogger().debug("Loaded " + GameData.getMainQuestDataMap().size() + " MainQuestDatas."); + } - @SneakyThrows - private static void loadHomeworldDefaultSaveData(){ - var folder = Files.list(Path.of(RESOURCE("BinOutput/HomeworldDefaultSave"))).toList(); - var pattern = Pattern.compile("scene(.*)_home_config.json"); + @SneakyThrows + private static void loadHomeworldDefaultSaveData() { + var folder = Files.list(Path.of(RESOURCE("BinOutput/HomeworldDefaultSave"))).toList(); + var pattern = Pattern.compile("scene(.*)_home_config.json"); - for(var file : folder){ - var matcher = pattern.matcher(file.getFileName().toString()); - if(!matcher.find()){ - continue; - } - var sceneId = matcher.group(1); + for (var file : folder) { + var matcher = pattern.matcher(file.getFileName().toString()); + if (!matcher.find()) { + continue; + } + var sceneId = matcher.group(1); - var data = Grasscutter.getGsonFactory().fromJson(Files.readString(file), HomeworldDefaultSaveData.class); + var data = Grasscutter.getGsonFactory().fromJson(Files.readString(file), HomeworldDefaultSaveData.class); - GameData.getHomeworldDefaultSaveData().put(Integer.parseInt(sceneId), data); - } + GameData.getHomeworldDefaultSaveData().put(Integer.parseInt(sceneId), data); + } - Grasscutter.getLogger().debug("Loaded " + GameData.getHomeworldDefaultSaveData().size() + " HomeworldDefaultSaveDatas."); - } + Grasscutter.getLogger().debug("Loaded " + GameData.getHomeworldDefaultSaveData().size() + " HomeworldDefaultSaveDatas."); + } - @SneakyThrows - private static void loadNpcBornData(){ - var folder = Files.list(Path.of(RESOURCE("BinOutput/Scene/SceneNpcBorn"))).toList(); + @SneakyThrows + private static void loadNpcBornData() { + var folder = Files.list(Path.of(RESOURCE("BinOutput/Scene/SceneNpcBorn"))).toList(); - for(var file : folder){ - if(file.toFile().isDirectory()){ - continue; - } + for (var file : folder) { + if (file.toFile().isDirectory()) { + continue; + } - var data = Grasscutter.getGsonFactory().fromJson(Files.readString(file), SceneNpcBornData.class); - if(data.getBornPosList() == null || data.getBornPosList().size() == 0){ - continue; - } + var data = Grasscutter.getGsonFactory().fromJson(Files.readString(file), SceneNpcBornData.class); + if (data.getBornPosList() == null || data.getBornPosList().size() == 0) { + continue; + } - data.setIndex(SceneIndexManager.buildIndex(3, data.getBornPosList(), item -> item.getPos().toPoint())); - GameData.getSceneNpcBornData().put(data.getSceneId(), data); - } + data.setIndex(SceneIndexManager.buildIndex(3, data.getBornPosList(), item -> item.getPos().toPoint())); + GameData.getSceneNpcBornData().put(data.getSceneId(), data); + } - Grasscutter.getLogger().debug("Loaded " + GameData.getSceneNpcBornData().size() + " SceneNpcBornDatas."); - } + Grasscutter.getLogger().debug("Loaded " + GameData.getSceneNpcBornData().size() + " SceneNpcBornDatas."); + } - // BinOutput configs + // BinOutput configs - public static class AvatarConfig { - @SerializedName(value="abilities", alternate={"targetAbilities"}) - public ArrayList abilities; - } + public static class AvatarConfig { + @SerializedName(value="abilities", alternate={"targetAbilities"}) + public ArrayList abilities; + } - public static class AvatarConfigAbility { - public String abilityName; - public String toString() { - return abilityName; - } - } + public static class AvatarConfigAbility { + public String abilityName; + public String toString() { + return abilityName; + } + } - private static class OpenConfig { - public OpenConfigData[] data; - } + private static class OpenConfig { + public OpenConfigData[] data; + } - public static class OpenConfigData { - public String $type; - public String abilityName; + public static class OpenConfigData { + public String $type; + public String abilityName; - @SerializedName(value="talentIndex", alternate={"OJOFFKLNAHN"}) - public int talentIndex; + @SerializedName(value="talentIndex", alternate={"OJOFFKLNAHN"}) + public int talentIndex; - @SerializedName(value="skillID", alternate={"overtime"}) - public int skillID; + @SerializedName(value="skillID", alternate={"overtime"}) + public int skillID; - @SerializedName(value="pointDelta", alternate={"IGEBKIHPOIF"}) - public int pointDelta; - } + @SerializedName(value="pointDelta", alternate={"IGEBKIHPOIF"}) + public int pointDelta; + } } diff --git a/src/main/java/emu/grasscutter/data/common/ItemParamData.java b/src/main/java/emu/grasscutter/data/common/ItemParamData.java index 229cbf7b9..77c168138 100644 --- a/src/main/java/emu/grasscutter/data/common/ItemParamData.java +++ b/src/main/java/emu/grasscutter/data/common/ItemParamData.java @@ -4,32 +4,32 @@ import com.google.gson.annotations.SerializedName; // Used in excels public class ItemParamData { - @SerializedName(value="id", alternate={"itemId"}) - private int id; - - @SerializedName(value="count", alternate={"itemCount"}) + @SerializedName(value="id", alternate={"itemId"}) + private int id; + + @SerializedName(value="count", alternate={"itemCount"}) private int count; public ItemParamData() {} - - public ItemParamData(int id, int count) { - this.id = id; - this.count = count; - } - - public int getId() { - return id; - } - - public int getItemId() { - return id; - } - - public int getCount() { - return count; - } - - public int getItemCount() { - return count; - } + + public ItemParamData(int id, int count) { + this.id = id; + this.count = count; + } + + public int getId() { + return id; + } + + public int getItemId() { + return id; + } + + public int getCount() { + return count; + } + + public int getItemCount() { + return count; + } } diff --git a/src/main/java/emu/grasscutter/data/excels/EnvAnimalGatherConfigData.java b/src/main/java/emu/grasscutter/data/excels/EnvAnimalGatherConfigData.java index d169b3ef7..d2e5313d3 100644 --- a/src/main/java/emu/grasscutter/data/excels/EnvAnimalGatherConfigData.java +++ b/src/main/java/emu/grasscutter/data/excels/EnvAnimalGatherConfigData.java @@ -1,35 +1,35 @@ -package emu.grasscutter.data.excels; - -import java.util.List; - -import emu.grasscutter.data.GameResource; -import emu.grasscutter.data.ResourceType; -import emu.grasscutter.data.common.ItemParamData; - -@ResourceType(name = "EnvAnimalGatherExcelConfigData.json", loadPriority = ResourceType.LoadPriority.LOW) -public class EnvAnimalGatherConfigData extends GameResource { - private int animalId; - private String entityType; - private List gatherItemId; - private String excludeWeathers; - private int aliveTime; - private int escapeTime; - private int escapeRadius; - - @Override - public int getId() { - return animalId; - } - - public int getAnimalId(){ - return animalId; - } - - public String getEntityType(){ - return entityType; - } - - public ItemParamData getGatherItem() { - return gatherItemId.size() > 0 ? gatherItemId.get(0) : null; - } -} +package emu.grasscutter.data.excels; + +import java.util.List; + +import emu.grasscutter.data.GameResource; +import emu.grasscutter.data.ResourceType; +import emu.grasscutter.data.common.ItemParamData; + +@ResourceType(name = "EnvAnimalGatherExcelConfigData.json", loadPriority = ResourceType.LoadPriority.LOW) +public class EnvAnimalGatherConfigData extends GameResource { + private int animalId; + private String entityType; + private List gatherItemId; + private String excludeWeathers; + private int aliveTime; + private int escapeTime; + private int escapeRadius; + + @Override + public int getId() { + return animalId; + } + + public int getAnimalId() { + return animalId; + } + + public String getEntityType() { + return entityType; + } + + public ItemParamData getGatherItem() { + return gatherItemId.size() > 0 ? gatherItemId.get(0) : null; + } +} diff --git a/src/main/java/emu/grasscutter/data/excels/ForgeData.java b/src/main/java/emu/grasscutter/data/excels/ForgeData.java index 3e6bf3e83..fab403170 100644 --- a/src/main/java/emu/grasscutter/data/excels/ForgeData.java +++ b/src/main/java/emu/grasscutter/data/excels/ForgeData.java @@ -23,9 +23,9 @@ public class ForgeData extends GameResource { private List materialItems; @Override - public int getId() { - return this.id; - } + public int getId() { + return this.id; + } public int getPlayerLevel() { return playerLevel; diff --git a/src/main/java/emu/grasscutter/data/excels/ReliquaryLevelData.java b/src/main/java/emu/grasscutter/data/excels/ReliquaryLevelData.java index f9580ef7d..2a3dc8e2b 100644 --- a/src/main/java/emu/grasscutter/data/excels/ReliquaryLevelData.java +++ b/src/main/java/emu/grasscutter/data/excels/ReliquaryLevelData.java @@ -12,58 +12,58 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; @ResourceType(name = "ReliquaryLevelExcelConfigData.json") public class ReliquaryLevelData extends GameResource { - private int id; - private Int2FloatMap propMap; - - private int rank; - private int level; - private int exp; - private List addProps; - - @Override - public int getId() { - return this.id; - } - - public int getRank() { - return rank; - } - - public int getLevel() { - return level; - } - - public int getExp() { - return exp; - } - - public float getPropValue(FightProperty prop) { - return getPropValue(prop.getId()); - } - - public float getPropValue(int id) { - return propMap.getOrDefault(id, 0f); - } - - @Override - public void onLoad() { - this.id = (rank << 8) + this.getLevel(); - this.propMap = new Int2FloatOpenHashMap(); - for (RelicLevelProperty p : addProps) { - this.propMap.put(FightProperty.getPropByName(p.getPropType()).getId(), p.getValue()); - } - } - - public class RelicLevelProperty { - private String propType; - private float value; - - public String getPropType() { - return propType; - } - - public float getValue() { - return value; - } - } + private int id; + private Int2FloatMap propMap; + + private int rank; + private int level; + private int exp; + private List addProps; + + @Override + public int getId() { + return this.id; + } + + public int getRank() { + return rank; + } + + public int getLevel() { + return level; + } + + public int getExp() { + return exp; + } + + public float getPropValue(FightProperty prop) { + return getPropValue(prop.getId()); + } + + public float getPropValue(int id) { + return propMap.getOrDefault(id, 0f); + } + + @Override + public void onLoad() { + this.id = (rank << 8) + this.getLevel(); + this.propMap = new Int2FloatOpenHashMap(); + for (RelicLevelProperty p : addProps) { + this.propMap.put(FightProperty.getPropByName(p.getPropType()).getId(), p.getValue()); + } + } + + public class RelicLevelProperty { + private String propType; + private float value; + + public String getPropType() { + return propType; + } + + public float getValue() { + return value; + } + } } diff --git a/src/main/java/emu/grasscutter/database/DatabaseManager.java b/src/main/java/emu/grasscutter/database/DatabaseManager.java index 15d78eb51..5bf5d0820 100644 --- a/src/main/java/emu/grasscutter/database/DatabaseManager.java +++ b/src/main/java/emu/grasscutter/database/DatabaseManager.java @@ -29,98 +29,98 @@ import emu.grasscutter.game.quest.GameMainQuest; import emu.grasscutter.game.quest.GameQuest; public final class DatabaseManager { - private static Datastore gameDatastore; - private static Datastore dispatchDatastore; + private static Datastore gameDatastore; + private static Datastore dispatchDatastore; - private static final Class[] mappedClasses = new Class[] { - DatabaseCounter.class, Account.class, Player.class, Avatar.class, GameItem.class, Friendship.class, - GachaRecord.class, Mail.class, GameMainQuest.class, GameHome.class, BattlePassManager.class, + private static final Class[] mappedClasses = new Class[] { + DatabaseCounter.class, Account.class, Player.class, Avatar.class, GameItem.class, Friendship.class, + GachaRecord.class, Mail.class, GameMainQuest.class, GameHome.class, BattlePassManager.class, PlayerActivityData.class, MusicGameBeatmap.class - }; + }; public static Datastore getGameDatastore() { - return gameDatastore; + return gameDatastore; } public static MongoDatabase getGameDatabase() { - return getGameDatastore().getDatabase(); + return getGameDatastore().getDatabase(); } - // Yes. I very dislike this method. However, this will be good for now. - // TODO: Add dispatch routes for player account management - public static Datastore getAccountDatastore() { - if(SERVER.runMode == ServerRunMode.GAME_ONLY) { - return dispatchDatastore; - } else { - return gameDatastore; - } - } - - public static void initialize() { - // Initialize - MongoClient gameMongoClient = MongoClients.create(DATABASE.game.connectionUri); - - // Set mapper options. - MapperOptions mapperOptions = MapperOptions.builder() - .storeEmpties(true).storeNulls(false).build(); - // Create data store. - gameDatastore = Morphia.createDatastore(gameMongoClient, DATABASE.game.collection, mapperOptions); - // Map classes. - gameDatastore.getMapper().map(mappedClasses); - - // Ensure indexes - try { - gameDatastore.ensureIndexes(); - } catch (MongoCommandException exception) { - Grasscutter.getLogger().info("Mongo index error: ", exception); - // Duplicate index error - if (exception.getCode() == 85) { - // Drop all indexes and re add them - MongoIterable collections = gameDatastore.getDatabase().listCollectionNames(); - for (String name : collections) { - gameDatastore.getDatabase().getCollection(name).dropIndexes(); - } - // Add back indexes - gameDatastore.ensureIndexes(); - } - } + // Yes. I very dislike this method. However, this will be good for now. + // TODO: Add dispatch routes for player account management + public static Datastore getAccountDatastore() { + if (SERVER.runMode == ServerRunMode.GAME_ONLY) { + return dispatchDatastore; + } else { + return gameDatastore; + } + } - if(SERVER.runMode == ServerRunMode.GAME_ONLY) { - MongoClient dispatchMongoClient = MongoClients.create(DATABASE.server.connectionUri); - dispatchDatastore = Morphia.createDatastore(dispatchMongoClient, DATABASE.server.collection); + public static void initialize() { + // Initialize + MongoClient gameMongoClient = MongoClients.create(DATABASE.game.connectionUri); - // Ensure indexes for dispatch server - try { - dispatchDatastore.ensureIndexes(); - } catch (MongoCommandException e) { - Grasscutter.getLogger().info("Mongo index error: ", e); - // Duplicate index error - if (e.getCode() == 85) { - // Drop all indexes and re add them - MongoIterable collections = dispatchDatastore.getDatabase().listCollectionNames(); - for (String name : collections) { - dispatchDatastore.getDatabase().getCollection(name).dropIndexes(); - } - // Add back indexes - dispatchDatastore.ensureIndexes(); - } - } - } - } + // Set mapper options. + MapperOptions mapperOptions = MapperOptions.builder() + .storeEmpties(true).storeNulls(false).build(); + // Create data store. + gameDatastore = Morphia.createDatastore(gameMongoClient, DATABASE.game.collection, mapperOptions); + // Map classes. + gameDatastore.getMapper().map(mappedClasses); - public static synchronized int getNextId(Class c) { - DatabaseCounter counter = getGameDatastore().find(DatabaseCounter.class).filter(Filters.eq("_id", c.getSimpleName())).first(); - if (counter == null) { - counter = new DatabaseCounter(c.getSimpleName()); - } - try { - return counter.getNextId(); - } finally { - getGameDatastore().save(counter); - } - } + // Ensure indexes + try { + gameDatastore.ensureIndexes(); + } catch (MongoCommandException exception) { + Grasscutter.getLogger().info("Mongo index error: ", exception); + // Duplicate index error + if (exception.getCode() == 85) { + // Drop all indexes and re add them + MongoIterable collections = gameDatastore.getDatabase().listCollectionNames(); + for (String name : collections) { + gameDatastore.getDatabase().getCollection(name).dropIndexes(); + } + // Add back indexes + gameDatastore.ensureIndexes(); + } + } - public static synchronized int getNextId(Object o) { - return getNextId(o.getClass()); - } -} \ No newline at end of file + if (SERVER.runMode == ServerRunMode.GAME_ONLY) { + MongoClient dispatchMongoClient = MongoClients.create(DATABASE.server.connectionUri); + dispatchDatastore = Morphia.createDatastore(dispatchMongoClient, DATABASE.server.collection); + + // Ensure indexes for dispatch server + try { + dispatchDatastore.ensureIndexes(); + } catch (MongoCommandException e) { + Grasscutter.getLogger().info("Mongo index error: ", e); + // Duplicate index error + if (e.getCode() == 85) { + // Drop all indexes and re add them + MongoIterable collections = dispatchDatastore.getDatabase().listCollectionNames(); + for (String name : collections) { + dispatchDatastore.getDatabase().getCollection(name).dropIndexes(); + } + // Add back indexes + dispatchDatastore.ensureIndexes(); + } + } + } + } + + public static synchronized int getNextId(Class c) { + DatabaseCounter counter = getGameDatastore().find(DatabaseCounter.class).filter(Filters.eq("_id", c.getSimpleName())).first(); + if (counter == null) { + counter = new DatabaseCounter(c.getSimpleName()); + } + try { + return counter.getNextId(); + } finally { + getGameDatastore().save(counter); + } + } + + public static synchronized int getNextId(Object o) { + return getNextId(o.getClass()); + } +} diff --git a/src/main/java/emu/grasscutter/game/Account.java b/src/main/java/emu/grasscutter/game/Account.java index 43f4efe5c..0f5c02f9d 100644 --- a/src/main/java/emu/grasscutter/game/Account.java +++ b/src/main/java/emu/grasscutter/game/Account.java @@ -14,93 +14,93 @@ import org.bson.Document; @Entity(value = "accounts", useDiscriminator = false) public class Account { - @Id private String id; - - @Indexed(options = @IndexOptions(unique = true)) - @Collation(locale = "simple", caseLevel = true) - private String username; - private String password; // Unused for now - - private int reservedPlayerId; - private String email; - - private String token; - private String sessionKey; // Session token for dispatch server - private List permissions; + @Id private String id; + + @Indexed(options = @IndexOptions(unique = true)) + @Collation(locale = "simple", caseLevel = true) + private String username; + private String password; // Unused for now + + private int reservedPlayerId; + private String email; + + private String token; + private String sessionKey; // Session token for dispatch server + private List permissions; private Locale locale; - private String banReason; - private int banEndTime; - private int banStartTime; - private boolean isBanned; - - @Deprecated - public Account() { - this.permissions = new ArrayList<>(); + private String banReason; + private int banEndTime; + private int banStartTime; + private boolean isBanned; + + @Deprecated + public Account() { + this.permissions = new ArrayList<>(); this.locale = LANGUAGE; - } + } - public String getId() { - return id; - } + public String getId() { + return id; + } - public void setId(String id) { - this.id = id; - } + public void setId(String id) { + this.id = id; + } - public String getUsername() { - return username; - } + public String getUsername() { + return username; + } - public void setUsername(String username) { - this.username = username; - } + public void setUsername(String username) { + this.username = username; + } - public String getPassword() { - return password; - } + public String getPassword() { + return password; + } - public void setPassword(String password) { - this.password = password; - } + public void setPassword(String password) { + this.password = password; + } - public String getToken() { - return token; - } + public String getToken() { + return token; + } - public void setToken(String token) { - this.token = token; - } + public void setToken(String token) { + this.token = token; + } - public int getReservedPlayerUid() { - return this.reservedPlayerId; - } + public int getReservedPlayerUid() { + return this.reservedPlayerId; + } - public void setReservedPlayerUid(int playerId) { - this.reservedPlayerId = playerId; - } - - public String getEmail() { - if(email != null && !email.isEmpty()) { - return email; - } else { - return ""; - } - } + public void setReservedPlayerUid(int playerId) { + this.reservedPlayerId = playerId; + } - public void setEmail(String email) { - this.email = email; - } + public String getEmail() { + if (email != null && !email.isEmpty()) { + return email; + } else { + return ""; + } + } - public String getSessionKey() { - return this.sessionKey; - } + public void setEmail(String email) { + this.email = email; + } - public String generateSessionKey() { - this.sessionKey = Utils.bytesToHex(Crypto.createSessionKey(32)); - this.save(); - return this.sessionKey; - } + public String getSessionKey() { + return this.sessionKey; + } + + public String generateSessionKey() { + this.sessionKey = Utils.bytesToHex(Crypto.createSessionKey(32)); + this.save(); + return this.sessionKey; + } public Locale getLocale() { return locale; @@ -110,126 +110,126 @@ public class Account { this.locale = locale; } - public String getBanReason() { - return banReason; - } + public String getBanReason() { + return banReason; + } - public void setBanReason(String banReason) { - this.banReason = banReason; - } + public void setBanReason(String banReason) { + this.banReason = banReason; + } - public int getBanEndTime() { - return banEndTime; - } + public int getBanEndTime() { + return banEndTime; + } - public void setBanEndTime(int banEndTime) { - this.banEndTime = banEndTime; - } + public void setBanEndTime(int banEndTime) { + this.banEndTime = banEndTime; + } - public int getBanStartTime() { - return banStartTime; - } + public int getBanStartTime() { + return banStartTime; + } - public void setBanStartTime(int banStartTime) { - this.banStartTime = banStartTime; - } + public void setBanStartTime(int banStartTime) { + this.banStartTime = banStartTime; + } - public boolean isBanned() { - if (banEndTime > 0 && banEndTime < System.currentTimeMillis() / 1000) { - this.isBanned = false; - this.banEndTime = 0; - this.banStartTime = 0; - this.banReason = null; - save(); - } + public boolean isBanned() { + if (banEndTime > 0 && banEndTime < System.currentTimeMillis() / 1000) { + this.isBanned = false; + this.banEndTime = 0; + this.banStartTime = 0; + this.banReason = null; + save(); + } - return isBanned; - } + return isBanned; + } - public void setBanned(boolean isBanned) { - this.isBanned = isBanned; - } + public void setBanned(boolean isBanned) { + this.isBanned = isBanned; + } - /** - * The collection of a player's permissions. - */ - public List getPermissions() { - return this.permissions; - } - - public boolean addPermission(String permission) { - if(this.permissions.contains(permission)) return false; - this.permissions.add(permission); return true; - } + /** + * The collection of a player's permissions. + */ + public List getPermissions() { + return this.permissions; + } - public static boolean permissionMatchesWildcard(String wildcard, String[] permissionParts) { - String[] wildcardParts = wildcard.split("\\."); - if (permissionParts.length < wildcardParts.length) { // A longer wildcard can never match a shorter permission - return false; - } - for (int i=0; i= (permissionParts.length-1)) { - return true; - } - break; - default: // This layer isn't a wildcard, it needs to match exactly - if (!wildcardParts[i].equals(permissionParts[i])) { - return false; - } - } - } - // At this point the wildcard will have matched every layer, but if it is shorter then the permission then this is not a match at this point (no **). - return (wildcardParts.length == permissionParts.length); - } + public boolean addPermission(String permission) { + if (this.permissions.contains(permission)) return false; + this.permissions.add(permission); return true; + } - public boolean hasPermission(String permission) { - if(this.permissions.contains("*") && this.permissions.size() == 1) return true; + public static boolean permissionMatchesWildcard(String wildcard, String[] permissionParts) { + String[] wildcardParts = wildcard.split("\\."); + if (permissionParts.length < wildcardParts.length) { // A longer wildcard can never match a shorter permission + return false; + } + for (int i=0; i= (permissionParts.length-1)) { + return true; + } + break; + default: // This layer isn't a wildcard, it needs to match exactly + if (!wildcardParts[i].equals(permissionParts[i])) { + return false; + } + } + } + // At this point the wildcard will have matched every layer, but if it is shorter then the permission then this is not a match at this point (no **). + return (wildcardParts.length == permissionParts.length); + } - // Add default permissions if it doesn't exist - List permissions = Stream.of(this.permissions, Arrays.asList(ACCOUNT.defaultPermissions)) - .flatMap(Collection::stream) - .distinct().toList(); + public boolean hasPermission(String permission) { + if (this.permissions.contains("*") && this.permissions.size() == 1) return true; - if (permissions.contains(permission)) return true; + // Add default permissions if it doesn't exist + List permissions = Stream.of(this.permissions, Arrays.asList(ACCOUNT.defaultPermissions)) + .flatMap(Collection::stream) + .distinct().toList(); - String[] permissionParts = permission.split("\\."); - for (String p : permissions) { - if (p.startsWith("-") && permissionMatchesWildcard(p.substring(1), permissionParts)) return false; - if (permissionMatchesWildcard(p, permissionParts)) return true; - } + if (permissions.contains(permission)) return true; - return permissions.contains("*"); - } + String[] permissionParts = permission.split("\\."); + for (String p : permissions) { + if (p.startsWith("-") && permissionMatchesWildcard(p.substring(1), permissionParts)) return false; + if (permissionMatchesWildcard(p, permissionParts)) return true; + } - public boolean removePermission(String permission) { - return this.permissions.remove(permission); - } + return permissions.contains("*"); + } - // TODO make unique - public String generateLoginToken() { - this.token = Utils.bytesToHex(Crypto.createSessionKey(32)); - this.save(); - return this.token; - } - - public void save() { - DatabaseHelper.saveAccount(this); - } + public boolean removePermission(String permission) { + return this.permissions.remove(permission); + } - @PreLoad - public void onLoad(Document document) { - // Grant the superuser permissions to accounts created before the permissions update - if (!document.containsKey("permissions")) { - this.addPermission("*"); - } + // TODO make unique + public String generateLoginToken() { + this.token = Utils.bytesToHex(Crypto.createSessionKey(32)); + this.save(); + return this.token; + } + + public void save() { + DatabaseHelper.saveAccount(this); + } + + @PreLoad + public void onLoad(Document document) { + // Grant the superuser permissions to accounts created before the permissions update + if (!document.containsKey("permissions")) { + this.addPermission("*"); + } // Set account default language as server default language if (!document.containsKey("locale")) { this.locale = LANGUAGE; } - } + } } diff --git a/src/main/java/emu/grasscutter/game/ability/AbilityManager.java b/src/main/java/emu/grasscutter/game/ability/AbilityManager.java index d59b8b0f1..7f2b16485 100644 --- a/src/main/java/emu/grasscutter/game/ability/AbilityManager.java +++ b/src/main/java/emu/grasscutter/game/ability/AbilityManager.java @@ -20,158 +20,158 @@ import emu.grasscutter.net.proto.ModifierActionOuterClass.ModifierAction; public class AbilityManager extends BasePlayerManager { HealAbilityManager healAbilityManager; - - public AbilityManager(Player player) { - super(player); - this.healAbilityManager = new HealAbilityManager(player); - } - public void onAbilityInvoke(AbilityInvokeEntry invoke) throws Exception { + public AbilityManager(Player player) { + super(player); + this.healAbilityManager = new HealAbilityManager(player); + } + + public void onAbilityInvoke(AbilityInvokeEntry invoke) throws Exception { healAbilityManager.healHandler(invoke); - //Grasscutter.getLogger().info(invoke.getArgumentType() + " (" + invoke.getArgumentTypeValue() + "): " + Utils.bytesToHex(invoke.toByteArray())); - switch (invoke.getArgumentType()) { - case ABILITY_INVOKE_ARGUMENT_META_OVERRIDE_PARAM: - handleOverrideParam(invoke); - break; - case ABILITY_INVOKE_ARGUMENT_META_REINIT_OVERRIDEMAP: - handleReinitOverrideMap(invoke); - break; - case ABILITY_INVOKE_ARGUMENT_META_MODIFIER_CHANGE: - handleModifierChange(invoke); - break; - case ABILITY_INVOKE_ARGUMENT_MIXIN_COST_STAMINA: - handleMixinCostStamina(invoke); - break; - case ABILITY_INVOKE_ARGUMENT_ACTION_GENERATE_ELEM_BALL: - handleGenerateElemBall(invoke); - break; - default: - break; - } - - } - - private void handleOverrideParam(AbilityInvokeEntry invoke) throws Exception { - GameEntity entity = player.getScene().getEntityById(invoke.getEntityId()); - - if (entity == null) { - return; - } - - AbilityScalarValueEntry entry = AbilityScalarValueEntry.parseFrom(invoke.getAbilityData()); - - entity.getMetaOverrideMap().put(entry.getKey().getStr(), entry.getFloatValue()); - } - - private void handleReinitOverrideMap(AbilityInvokeEntry invoke) throws Exception { - GameEntity entity = player.getScene().getEntityById(invoke.getEntityId()); - - if (entity == null) { - return; - } - - AbilityMetaReInitOverrideMap map = AbilityMetaReInitOverrideMap.parseFrom(invoke.getAbilityData()); - - for (AbilityScalarValueEntry entry : map.getOverrideMapList()) { - entity.getMetaOverrideMap().put(entry.getKey().getStr(), entry.getFloatValue()); - } - } - - private void handleModifierChange(AbilityInvokeEntry invoke) throws Exception { - // Sanity checks - GameEntity target = player.getScene().getEntityById(invoke.getEntityId()); - if (target == null) { - return; - } - - AbilityMetaModifierChange data = AbilityMetaModifierChange.parseFrom(invoke.getAbilityData()); - if (data == null) { - return; - } - - // Destroying rocks - if (target instanceof EntityGadget targetGadget && targetGadget.getContent() instanceof GadgetGatherObject gatherObject) { - if (data.getAction() == ModifierAction.REMOVED) { - gatherObject.dropItems(this.getPlayer()); - return; - } + //Grasscutter.getLogger().info(invoke.getArgumentType() + " (" + invoke.getArgumentTypeValue() + "): " + Utils.bytesToHex(invoke.toByteArray())); + switch (invoke.getArgumentType()) { + case ABILITY_INVOKE_ARGUMENT_META_OVERRIDE_PARAM: + handleOverrideParam(invoke); + break; + case ABILITY_INVOKE_ARGUMENT_META_REINIT_OVERRIDEMAP: + handleReinitOverrideMap(invoke); + break; + case ABILITY_INVOKE_ARGUMENT_META_MODIFIER_CHANGE: + handleModifierChange(invoke); + break; + case ABILITY_INVOKE_ARGUMENT_MIXIN_COST_STAMINA: + handleMixinCostStamina(invoke); + break; + case ABILITY_INVOKE_ARGUMENT_ACTION_GENERATE_ELEM_BALL: + handleGenerateElemBall(invoke); + break; + default: + break; } - - // Sanity checks - AbilityInvokeEntryHead head = invoke.getHead(); - if (head == null) { - return; - } - - GameEntity sourceEntity = player.getScene().getEntityById(data.getApplyEntityId()); - if (sourceEntity == null) { - return; - } - - // This is not how it works but we will keep it for now since healing abilities dont work properly anyways - if (data.getAction() == ModifierAction.ADDED && data.getParentAbilityName() != null) { - // Handle add modifier here - String modifierString = data.getParentAbilityName().getStr(); - AbilityModifierEntry modifier = GameData.getAbilityModifiers().get(modifierString); - - if (modifier != null && modifier.getOnAdded().size() > 0) { - for (AbilityModifierAction action : modifier.getOnAdded()) { - invokeAction(action, target, sourceEntity); - } - } - - // Add to meta modifier list - target.getMetaModifiers().put(head.getInstancedModifierId(), modifierString); - } else if (data.getAction() == ModifierAction.REMOVED) { - // Handle remove modifier - String modifierString = target.getMetaModifiers().get(head.getInstancedModifierId()); - - if (modifierString != null) { - // Get modifier and call on remove event - AbilityModifierEntry modifier = GameData.getAbilityModifiers().get(modifierString); - - if (modifier != null && modifier.getOnRemoved().size() > 0) { - for (AbilityModifierAction action : modifier.getOnRemoved()) { - invokeAction(action, target, sourceEntity); - } - } - - // Remove from meta modifiers - target.getMetaModifiers().remove(head.getInstancedModifierId()); - } - } - } - - private void handleMixinCostStamina(AbilityInvokeEntry invoke) throws InvalidProtocolBufferException { - AbilityMixinCostStamina costStamina = AbilityMixinCostStamina.parseFrom((invoke.getAbilityData())); - getPlayer().getStaminaManager().handleMixinCostStamina(costStamina.getIsSwim()); - } - private void handleGenerateElemBall(AbilityInvokeEntry invoke) throws InvalidProtocolBufferException { - this.player.getEnergyManager().handleGenerateElemBall(invoke); - } - - private void invokeAction(AbilityModifierAction action, GameEntity target, GameEntity sourceEntity) { - switch (action.type) { - case HealHP -> { - } - case LoseHP -> { - if (action.amountByTargetCurrentHPRatio == null) { - return; - } - - float damageAmount = 0; - - if (action.amount.isDynamic && action.amount.dynamicKey != null) { - damageAmount = sourceEntity.getMetaOverrideMap().getOrDefault(action.amount.dynamicKey, 0f); - } - - if (damageAmount > 0) { - target.damage(damageAmount); - } - } - } - } + } + + private void handleOverrideParam(AbilityInvokeEntry invoke) throws Exception { + GameEntity entity = player.getScene().getEntityById(invoke.getEntityId()); + + if (entity == null) { + return; + } + + AbilityScalarValueEntry entry = AbilityScalarValueEntry.parseFrom(invoke.getAbilityData()); + + entity.getMetaOverrideMap().put(entry.getKey().getStr(), entry.getFloatValue()); + } + + private void handleReinitOverrideMap(AbilityInvokeEntry invoke) throws Exception { + GameEntity entity = player.getScene().getEntityById(invoke.getEntityId()); + + if (entity == null) { + return; + } + + AbilityMetaReInitOverrideMap map = AbilityMetaReInitOverrideMap.parseFrom(invoke.getAbilityData()); + + for (AbilityScalarValueEntry entry : map.getOverrideMapList()) { + entity.getMetaOverrideMap().put(entry.getKey().getStr(), entry.getFloatValue()); + } + } + + private void handleModifierChange(AbilityInvokeEntry invoke) throws Exception { + // Sanity checks + GameEntity target = player.getScene().getEntityById(invoke.getEntityId()); + if (target == null) { + return; + } + + AbilityMetaModifierChange data = AbilityMetaModifierChange.parseFrom(invoke.getAbilityData()); + if (data == null) { + return; + } + + // Destroying rocks + if (target instanceof EntityGadget targetGadget && targetGadget.getContent() instanceof GadgetGatherObject gatherObject) { + if (data.getAction() == ModifierAction.REMOVED) { + gatherObject.dropItems(this.getPlayer()); + return; + } + } + + // Sanity checks + AbilityInvokeEntryHead head = invoke.getHead(); + if (head == null) { + return; + } + + GameEntity sourceEntity = player.getScene().getEntityById(data.getApplyEntityId()); + if (sourceEntity == null) { + return; + } + + // This is not how it works but we will keep it for now since healing abilities dont work properly anyways + if (data.getAction() == ModifierAction.ADDED && data.getParentAbilityName() != null) { + // Handle add modifier here + String modifierString = data.getParentAbilityName().getStr(); + AbilityModifierEntry modifier = GameData.getAbilityModifiers().get(modifierString); + + if (modifier != null && modifier.getOnAdded().size() > 0) { + for (AbilityModifierAction action : modifier.getOnAdded()) { + invokeAction(action, target, sourceEntity); + } + } + + // Add to meta modifier list + target.getMetaModifiers().put(head.getInstancedModifierId(), modifierString); + } else if (data.getAction() == ModifierAction.REMOVED) { + // Handle remove modifier + String modifierString = target.getMetaModifiers().get(head.getInstancedModifierId()); + + if (modifierString != null) { + // Get modifier and call on remove event + AbilityModifierEntry modifier = GameData.getAbilityModifiers().get(modifierString); + + if (modifier != null && modifier.getOnRemoved().size() > 0) { + for (AbilityModifierAction action : modifier.getOnRemoved()) { + invokeAction(action, target, sourceEntity); + } + } + + // Remove from meta modifiers + target.getMetaModifiers().remove(head.getInstancedModifierId()); + } + } + } + + private void handleMixinCostStamina(AbilityInvokeEntry invoke) throws InvalidProtocolBufferException { + AbilityMixinCostStamina costStamina = AbilityMixinCostStamina.parseFrom((invoke.getAbilityData())); + getPlayer().getStaminaManager().handleMixinCostStamina(costStamina.getIsSwim()); + } + + private void handleGenerateElemBall(AbilityInvokeEntry invoke) throws InvalidProtocolBufferException { + this.player.getEnergyManager().handleGenerateElemBall(invoke); + } + + private void invokeAction(AbilityModifierAction action, GameEntity target, GameEntity sourceEntity) { + switch (action.type) { + case HealHP -> { + } + case LoseHP -> { + if (action.amountByTargetCurrentHPRatio == null) { + return; + } + + float damageAmount = 0; + + if (action.amount.isDynamic && action.amount.dynamicKey != null) { + damageAmount = sourceEntity.getMetaOverrideMap().getOrDefault(action.amount.dynamicKey, 0f); + } + + if (damageAmount > 0) { + target.damage(damageAmount); + } + } + } + } } diff --git a/src/main/java/emu/grasscutter/game/activity/ActivityManager.java b/src/main/java/emu/grasscutter/game/activity/ActivityManager.java index f1c86b812..f4cd55f0c 100644 --- a/src/main/java/emu/grasscutter/game/activity/ActivityManager.java +++ b/src/main/java/emu/grasscutter/game/activity/ActivityManager.java @@ -45,7 +45,7 @@ public class ActivityManager extends BasePlayerManager { activityWatcherTypeMap.put(typeName.value(), ConstructorAccess.get(item)); }); - try(Reader reader = DataLoader.loadReader("ActivityConfig.json")) { + try (Reader reader = DataLoader.loadReader("ActivityConfig.json")) { List activities = Grasscutter.getGsonFactory().fromJson( reader, TypeToken.getParameterized(List.class, ActivityConfigItem.class).getType()); @@ -53,16 +53,16 @@ public class ActivityManager extends BasePlayerManager { activities.forEach(item -> { var activityData = GameData.getActivityDataMap().get(item.getActivityId()); - if(activityData == null){ + if (activityData == null) { Grasscutter.getLogger().warn("activity {} not exist.", item.getActivityId()); return; } var activityHandlerType = activityHandlerTypeMap.get(ActivityType.getTypeByName(activityData.getActivityType())); ActivityHandler activityHandler; - if(activityHandlerType != null) { + if (activityHandlerType != null) { activityHandler = (ActivityHandler) activityHandlerType.newInstance(); - }else{ + }else { activityHandler = new DefaultActivityHandler(); } activityHandler.setActivityConfigItem(item); @@ -79,14 +79,14 @@ public class ActivityManager extends BasePlayerManager { } - public ActivityManager(Player player){ + public ActivityManager(Player player) { super(player); playerActivityDataMap = new ConcurrentHashMap<>(); // load data for player activityConfigItemMap.values().forEach(item -> { var data = PlayerActivityData.getByPlayer(player, item.getActivityId()); - if(data == null){ + if (data == null) { data = item.getActivityHandler().initPlayerActivityData(player); data.save(); } @@ -116,34 +116,34 @@ public class ActivityManager extends BasePlayerManager { params)); } - public ActivityInfoOuterClass.ActivityInfo getInfoProtoByActivityId(int activityId){ + public ActivityInfoOuterClass.ActivityInfo getInfoProtoByActivityId(int activityId) { var activityHandler = activityConfigItemMap.get(activityId).getActivityHandler(); var activityData = playerActivityDataMap.get(activityId); return activityHandler.toProto(activityData); } - public Optional getActivityHandler(ActivityType type){ + public Optional getActivityHandler(ActivityType type) { return activityConfigItemMap.values().stream() .map(ActivityConfigItem::getActivityHandler) .filter(x -> type == x.getClass().getAnnotation(GameActivity.class).value()) .findFirst(); } - public Optional getActivityHandlerAs(ActivityType type, Class clazz){ + public Optional getActivityHandlerAs(ActivityType type, Class clazz) { return getActivityHandler(type).map(x -> (T)x); } - public Optional getActivityIdByActivityType(ActivityType type){ + public Optional getActivityIdByActivityType(ActivityType type) { return getActivityHandler(type) .map(ActivityHandler::getActivityConfigItem) .map(ActivityConfigItem::getActivityId); } - public Optional getPlayerActivityDataByActivityType(ActivityType type){ + public Optional getPlayerActivityDataByActivityType(ActivityType type) { return getActivityIdByActivityType(type) .map(playerActivityDataMap::get); } - public Optional getInfoProtoByActivityType(ActivityType type){ + public Optional getInfoProtoByActivityType(ActivityType type) { return getActivityIdByActivityType(type) .map(this::getInfoProtoByActivityId); } diff --git a/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGameActivityHandler.java b/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGameActivityHandler.java index 18f937c9e..7b8b81004 100644 --- a/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGameActivityHandler.java +++ b/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGameActivityHandler.java @@ -41,8 +41,8 @@ public class MusicGameActivityHandler extends ActivityHandler { .build()); } - public MusicGamePlayerData getMusicGamePlayerData(PlayerActivityData playerActivityData){ - if(playerActivityData.getDetail() == null || playerActivityData.getDetail().isBlank()){ + public MusicGamePlayerData getMusicGamePlayerData(PlayerActivityData playerActivityData) { + if (playerActivityData.getDetail() == null || playerActivityData.getDetail().isBlank()) { onInitPlayerActivityData(playerActivityData); playerActivityData.save(); } @@ -51,7 +51,7 @@ public class MusicGameActivityHandler extends ActivityHandler { MusicGamePlayerData.class); } - public boolean setMusicGameRecord(PlayerActivityData playerActivityData, MusicGamePlayerData.MusicGameRecord newRecord){ + public boolean setMusicGameRecord(PlayerActivityData playerActivityData, MusicGamePlayerData.MusicGameRecord newRecord) { var musicGamePlayerData = getMusicGamePlayerData(playerActivityData); var saveRecord = musicGamePlayerData.getMusicGameRecord().get(newRecord.getMusicId()); @@ -63,7 +63,7 @@ public class MusicGameActivityHandler extends ActivityHandler { return newRecord.getMaxScore() > saveRecord.getMaxScore(); } - public void setMusicGameCustomBeatmapRecord(PlayerActivityData playerActivityData, MusicGamePlayerData.CustomBeatmapRecord newRecord){ + public void setMusicGameCustomBeatmapRecord(PlayerActivityData playerActivityData, MusicGamePlayerData.CustomBeatmapRecord newRecord) { var musicGamePlayerData = getMusicGamePlayerData(playerActivityData); musicGamePlayerData.getOthersCustomBeatmapRecord().put(newRecord.getMusicShareId(), newRecord); diff --git a/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGamePlayerData.java b/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGamePlayerData.java index 4fd25c5bb..e99b71cb6 100644 --- a/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGamePlayerData.java +++ b/src/main/java/emu/grasscutter/game/activity/musicgame/MusicGamePlayerData.java @@ -21,7 +21,7 @@ public class MusicGamePlayerData { Map personalCustomBeatmapRecord; Map othersCustomBeatmapRecord; - public static MusicGamePlayerData create(){ + public static MusicGamePlayerData create() { return MusicGamePlayerData.of() .musicGameRecord(GameData.getMusicGameBasicDataMap().values().stream() .collect(Collectors.toMap(MusicGameBasicData::getId, MusicGamePlayerData.MusicGameRecord::create))) @@ -38,13 +38,13 @@ public class MusicGamePlayerData { int maxCombo; int maxScore; - public static MusicGameRecord create(MusicGameBasicData musicGameBasicData){ + public static MusicGameRecord create(MusicGameBasicData musicGameBasicData) { return MusicGameRecord.of() .musicId(musicGameBasicData.getId()) .build(); } - public MusicGameRecordOuterClass.MusicGameRecord toProto(){ + public MusicGameRecordOuterClass.MusicGameRecord toProto() { return MusicGameRecordOuterClass.MusicGameRecord.newBuilder() .setIsUnlock(true) .setMaxCombo(maxCombo) @@ -61,7 +61,7 @@ public class MusicGamePlayerData { int score; boolean settle; - public MusicBriefInfoOuterClass.MusicBriefInfo.Builder toPersonalBriefProto(){ + public MusicBriefInfoOuterClass.MusicBriefInfo.Builder toPersonalBriefProto() { var musicGameBeatmap = MusicGameBeatmap.getByShareId(musicShareId); return MusicBriefInfoOuterClass.MusicBriefInfo.newBuilder() @@ -74,7 +74,7 @@ public class MusicGamePlayerData { .setMusicShareId(musicShareId); } - public MusicBriefInfoOuterClass.MusicBriefInfo.Builder toOthersBriefProto(){ + public MusicBriefInfoOuterClass.MusicBriefInfo.Builder toOthersBriefProto() { var musicGameBeatmap = MusicGameBeatmap.getByShareId(musicShareId); return musicGameBeatmap.toBriefProto() diff --git a/src/main/java/emu/grasscutter/game/avatar/Avatar.java b/src/main/java/emu/grasscutter/game/avatar/Avatar.java index 3ab2e1dc8..b8adfdbd0 100644 --- a/src/main/java/emu/grasscutter/game/avatar/Avatar.java +++ b/src/main/java/emu/grasscutter/game/avatar/Avatar.java @@ -66,896 +66,896 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; @Entity(value = "avatars", useDiscriminator = false) public class Avatar { - @Id private ObjectId id; - @Indexed private int ownerId; // Id of player that this avatar belongs to - - @Transient private Player owner; - @Transient private AvatarData data; - @Transient private AvatarSkillDepotData skillDepot; - @Transient private long guid; // Player unique id - private int avatarId; // Id of avatar - - private int level = 1; - private int exp; - private int promoteLevel; - private int satiation; // ? - private int satiationPenalty; // ? - private float currentHp; - private float currentEnergy; - - @Transient private final Int2ObjectMap equips; - @Transient private final Int2FloatOpenHashMap fightProp; - @Transient private Set extraAbilityEmbryos; - - private List fetters; + @Id private ObjectId id; + @Indexed private int ownerId; // Id of player that this avatar belongs to - private Map skillLevelMap; // Talent levels - private Map skillExtraChargeMap; // Charges - private Map proudSkillBonusMap; // Talent bonus levels (from const) - private int skillDepotId; - private int coreProudSkillLevel; // Constellation level - private Set talentIdList; // Constellation id list - private Set proudSkillList; // Character passives - - private int flyCloak; - private int costume; - private int bornTime; + @Transient private Player owner; + @Transient private AvatarData data; + @Transient private AvatarSkillDepotData skillDepot; + @Transient private long guid; // Player unique id + private int avatarId; // Id of avatar - private int fetterLevel = 1; - private int fetterExp; + private int level = 1; + private int exp; + private int promoteLevel; + private int satiation; // ? + private int satiationPenalty; // ? + private float currentHp; + private float currentEnergy; - private int nameCardRewardId; - private int nameCardId; - - @Deprecated // Do not use. Morhpia only! - public Avatar() { - this.equips = new Int2ObjectOpenHashMap<>(); - this.fightProp = new Int2FloatOpenHashMap(); - this.extraAbilityEmbryos = new HashSet<>(); - this.proudSkillBonusMap = new HashMap<>(); - this.fetters = new ArrayList<>(); // TODO Move to avatar - } - - // On creation - public Avatar(int avatarId) { - this(GameData.getAvatarDataMap().get(avatarId)); - } - - public Avatar(AvatarData data) { - this(); - this.avatarId = data.getId(); - this.nameCardRewardId = data.getNameCardRewardId(); - this.nameCardId = data.getNameCardId(); - this.data = data; - this.bornTime = (int) (System.currentTimeMillis() / 1000); - this.flyCloak = 140001; - - this.skillLevelMap = new HashMap<>(); - this.skillExtraChargeMap = new HashMap<>(); - this.talentIdList = new HashSet<>(); - this.proudSkillList = new HashSet<>(); - - // Combat properties - for (FightProperty prop : FightProperty.values()) { - if (prop.getId() <= 0 || prop.getId() >= 3000) { - continue; - } - this.setFightProperty(prop, 0f); - } - - // Skill depot - this.setSkillDepotData(getAvatarData().getSkillDepot()); - - // Set stats - this.recalcStats(); - this.currentHp = getFightProperty(FightProperty.FIGHT_PROP_MAX_HP); - setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, this.currentHp); - this.currentEnergy = 0f; - // Load handler - this.onLoad(); - } - - public Player getPlayer() { - return this.owner; - } + @Transient private final Int2ObjectMap equips; + @Transient private final Int2FloatOpenHashMap fightProp; + @Transient private Set extraAbilityEmbryos; - public ObjectId getObjectId() { - return id; - } + private List fetters; - public AvatarData getAvatarData() { - return data; - } + private Map skillLevelMap; // Talent levels + private Map skillExtraChargeMap; // Charges + private Map proudSkillBonusMap; // Talent bonus levels (from const) + private int skillDepotId; + private int coreProudSkillLevel; // Constellation level + private Set talentIdList; // Constellation id list + private Set proudSkillList; // Character passives - protected void setAvatarData(AvatarData data) { - if (this.data != null) return; - this.data = data; // Used while loading this from the database - } + private int flyCloak; + private int costume; + private int bornTime; - public int getOwnerId() { - return ownerId; - } + private int fetterLevel = 1; + private int fetterExp; - public void setOwner(Player player) { - this.owner = player; - this.ownerId = player.getUid(); - this.guid = player.getNextGameGuid(); - } - - public int getSatiation() { - return satiation; - } + private int nameCardRewardId; + private int nameCardId; - public void setSatiation(int satiation) { - this.satiation = satiation; - } + @Deprecated // Do not use. Morhpia only! + public Avatar() { + this.equips = new Int2ObjectOpenHashMap<>(); + this.fightProp = new Int2FloatOpenHashMap(); + this.extraAbilityEmbryos = new HashSet<>(); + this.proudSkillBonusMap = new HashMap<>(); + this.fetters = new ArrayList<>(); // TODO Move to avatar + } - public int getNameCardRewardId() { - return nameCardRewardId; - } + // On creation + public Avatar(int avatarId) { + this(GameData.getAvatarDataMap().get(avatarId)); + } - public void setNameCardRewardId(int nameCardRewardId) { - this.nameCardRewardId = nameCardRewardId; - } + public Avatar(AvatarData data) { + this(); + this.avatarId = data.getId(); + this.nameCardRewardId = data.getNameCardRewardId(); + this.nameCardId = data.getNameCardId(); + this.data = data; + this.bornTime = (int) (System.currentTimeMillis() / 1000); + this.flyCloak = 140001; - public int getSatiationPenalty() { - return satiationPenalty; - } + this.skillLevelMap = new HashMap<>(); + this.skillExtraChargeMap = new HashMap<>(); + this.talentIdList = new HashSet<>(); + this.proudSkillList = new HashSet<>(); - public void setSatiationPenalty(int satiationPenalty) { - this.satiationPenalty = satiationPenalty; - } + // Combat properties + for (FightProperty prop : FightProperty.values()) { + if (prop.getId() <= 0 || prop.getId() >= 3000) { + continue; + } + this.setFightProperty(prop, 0f); + } - public AvatarData getData() { - return data; - } + // Skill depot + this.setSkillDepotData(getAvatarData().getSkillDepot()); - public long getGuid() { - return guid; - } + // Set stats + this.recalcStats(); + this.currentHp = getFightProperty(FightProperty.FIGHT_PROP_MAX_HP); + setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, this.currentHp); + this.currentEnergy = 0f; + // Load handler + this.onLoad(); + } - public int getAvatarId() { - return avatarId; - } + public Player getPlayer() { + return this.owner; + } - public int getLevel() { - return level; - } - - public void setLevel(int level) { - this.level = level; - } + public ObjectId getObjectId() { + return id; + } - public int getExp() { - return exp; - } - - public void setExp(int exp) { - this.exp = exp; - } + public AvatarData getAvatarData() { + return data; + } - public int getPromoteLevel() { - return promoteLevel; - } + protected void setAvatarData(AvatarData data) { + if (this.data != null) return; + this.data = data; // Used while loading this from the database + } - public void setPromoteLevel(int promoteLevel) { - this.promoteLevel = promoteLevel; - } + public int getOwnerId() { + return ownerId; + } - static public int getMinPromoteLevel(int level) { - if (level > 80) { - return 6; - } else if (level > 70) { - return 5; - } else if (level > 60) { - return 4; - } else if (level > 50) { - return 3; - } else if (level > 40) { - return 2; - } else if (level > 20) { - return 1; - } - return 0; - } + public void setOwner(Player player) { + this.owner = player; + this.ownerId = player.getUid(); + this.guid = player.getNextGameGuid(); + } - public Int2ObjectMap getEquips() { - return equips; - } - - public GameItem getEquipBySlot(EquipType slot) { - return this.getEquips().get(slot.getValue()); - } - - private GameItem getEquipBySlot(int slotId) { - return this.getEquips().get(slotId); - } - - public GameItem getWeapon() { - return this.getEquipBySlot(EquipType.EQUIP_WEAPON); - } + public int getSatiation() { + return satiation; + } - public int getSkillDepotId() { - return skillDepotId; - } + public void setSatiation(int satiation) { + this.satiation = satiation; + } - public AvatarSkillDepotData getSkillDepot() { - return skillDepot; - } - - protected void setSkillDepot(AvatarSkillDepotData skillDepot) { - if (this.skillDepot != null) return; - this.skillDepot = skillDepot; // Used while loading this from the database - } + public int getNameCardRewardId() { + return nameCardRewardId; + } - public void setSkillDepotData(AvatarSkillDepotData skillDepot) { - // Set id and depot - this.skillDepotId = skillDepot.getId(); - this.skillDepot = skillDepot; - // Clear, then add skills - getSkillLevelMap().clear(); - if (skillDepot.getEnergySkill() > 0) { - getSkillLevelMap().put(skillDepot.getEnergySkill(), 1); - } - for (int skillId : skillDepot.getSkills()) { - if (skillId > 0) { - getSkillLevelMap().put(skillId, 1); - } - } - // Add proud skills - this.getProudSkillList().clear(); - for (InherentProudSkillOpens openData : skillDepot.getInherentProudSkillOpens()) { - if (openData.getProudSkillGroupId() == 0) { - continue; - } - if (openData.getNeedAvatarPromoteLevel() <= this.getPromoteLevel()) { - int proudSkillId = (openData.getProudSkillGroupId() * 100) + 1; - if (GameData.getProudSkillDataMap().containsKey(proudSkillId)) { - this.getProudSkillList().add(proudSkillId); - } - } - } - } + public void setNameCardRewardId(int nameCardRewardId) { + this.nameCardRewardId = nameCardRewardId; + } - public Map getSkillLevelMap() { - return skillLevelMap; - } - - public Map getSkillExtraChargeMap() { - if (skillExtraChargeMap == null) { - skillExtraChargeMap = new HashMap<>(); - } - return skillExtraChargeMap; - } + public int getSatiationPenalty() { + return satiationPenalty; + } - public Map getProudSkillBonusMap() { - return proudSkillBonusMap; - } + public void setSatiationPenalty(int satiationPenalty) { + this.satiationPenalty = satiationPenalty; + } - public Set getExtraAbilityEmbryos() { - return extraAbilityEmbryos; - } + public AvatarData getData() { + return data; + } - public void setFetterList(List fetterList) { - this.fetters = fetterList; - } + public long getGuid() { + return guid; + } - public List getFetterList() { - return fetters; - } + public int getAvatarId() { + return avatarId; + } - public int getFetterLevel() { - return fetterLevel; - } + public int getLevel() { + return level; + } - public void setFetterLevel(int fetterLevel) { - this.fetterLevel = fetterLevel; - } + public void setLevel(int level) { + this.level = level; + } - public int getFetterExp() { - return fetterExp; - } + public int getExp() { + return exp; + } - public void setFetterExp(int fetterExp) { - this.fetterExp = fetterExp; - } + public void setExp(int exp) { + this.exp = exp; + } - public int getNameCardId() { - return nameCardId; - } + public int getPromoteLevel() { + return promoteLevel; + } - public void setNameCardId(int nameCardId) { - this.nameCardId = nameCardId; - } + public void setPromoteLevel(int promoteLevel) { + this.promoteLevel = promoteLevel; + } - public float getCurrentHp() { - return currentHp; - } + static public int getMinPromoteLevel(int level) { + if (level > 80) { + return 6; + } else if (level > 70) { + return 5; + } else if (level > 60) { + return 4; + } else if (level > 50) { + return 3; + } else if (level > 40) { + return 2; + } else if (level > 20) { + return 1; + } + return 0; + } - public void setCurrentHp(float currentHp) { - this.currentHp = currentHp; - } + public Int2ObjectMap getEquips() { + return equips; + } - public void setCurrentEnergy() { - if (GAME_OPTIONS.energyUsage) { - this.setCurrentEnergy(this.currentEnergy); - } - } - - public void setCurrentEnergy(float currentEnergy) { - if (this.getSkillDepot() != null && this.getSkillDepot().getEnergySkillData() != null) { - ElementType element = this.getSkillDepot().getElementType(); - this.setFightProperty(element.getMaxEnergyProp(), this.getSkillDepot().getEnergySkillData().getCostElemVal()); - - if (GAME_OPTIONS.energyUsage) { - this.setFightProperty(element.getCurEnergyProp(), currentEnergy); - } - else { - this.setFightProperty(element.getCurEnergyProp(), this.getSkillDepot().getEnergySkillData().getCostElemVal()); - } - } - } + public GameItem getEquipBySlot(EquipType slot) { + return this.getEquips().get(slot.getValue()); + } - public void setCurrentEnergy(FightProperty curEnergyProp, float currentEnergy) { - if (GAME_OPTIONS.energyUsage) { - this.setFightProperty(curEnergyProp, currentEnergy); - this.currentEnergy = currentEnergy; - this.save(); - } - } + private GameItem getEquipBySlot(int slotId) { + return this.getEquips().get(slotId); + } - public Int2FloatOpenHashMap getFightProperties() { - return fightProp; - } - - public void setFightProperty(FightProperty prop, float value) { - this.getFightProperties().put(prop.getId(), value); - } - - private void setFightProperty(int id, float value) { - this.getFightProperties().put(id, value); - } - - public void addFightProperty(FightProperty prop, float value) { - this.getFightProperties().put(prop.getId(), getFightProperty(prop) + value); - } - - public float getFightProperty(FightProperty prop) { - return getFightProperties().getOrDefault(prop.getId(), 0f); - } + public GameItem getWeapon() { + return this.getEquipBySlot(EquipType.EQUIP_WEAPON); + } - public Set getTalentIdList() { - return talentIdList; - } + public int getSkillDepotId() { + return skillDepotId; + } - public int getCoreProudSkillLevel() { - return coreProudSkillLevel; - } + public AvatarSkillDepotData getSkillDepot() { + return skillDepot; + } - public void setCoreProudSkillLevel(int constLevel) { - this.coreProudSkillLevel = constLevel; - } + protected void setSkillDepot(AvatarSkillDepotData skillDepot) { + if (this.skillDepot != null) return; + this.skillDepot = skillDepot; // Used while loading this from the database + } - public Set getProudSkillList() { - return proudSkillList; - } - - public int getFlyCloak() { - return flyCloak; - } - - public void setFlyCloak(int flyCloak) { - this.flyCloak = flyCloak; - } + public void setSkillDepotData(AvatarSkillDepotData skillDepot) { + // Set id and depot + this.skillDepotId = skillDepot.getId(); + this.skillDepot = skillDepot; + // Clear, then add skills + getSkillLevelMap().clear(); + if (skillDepot.getEnergySkill() > 0) { + getSkillLevelMap().put(skillDepot.getEnergySkill(), 1); + } + for (int skillId : skillDepot.getSkills()) { + if (skillId > 0) { + getSkillLevelMap().put(skillId, 1); + } + } + // Add proud skills + this.getProudSkillList().clear(); + for (InherentProudSkillOpens openData : skillDepot.getInherentProudSkillOpens()) { + if (openData.getProudSkillGroupId() == 0) { + continue; + } + if (openData.getNeedAvatarPromoteLevel() <= this.getPromoteLevel()) { + int proudSkillId = (openData.getProudSkillGroupId() * 100) + 1; + if (GameData.getProudSkillDataMap().containsKey(proudSkillId)) { + this.getProudSkillList().add(proudSkillId); + } + } + } + } - public int getCostume() { - return costume; - } + public Map getSkillLevelMap() { + return skillLevelMap; + } - public void setCostume(int costume) { - this.costume = costume; - } + public Map getSkillExtraChargeMap() { + if (skillExtraChargeMap == null) { + skillExtraChargeMap = new HashMap<>(); + } + return skillExtraChargeMap; + } - public int getBornTime() { - return bornTime; - } - - public boolean equipItem(GameItem item, boolean shouldRecalc) { - // Sanity check equip type - EquipType itemEquipType = item.getItemData().getEquipType(); - if (itemEquipType == EquipType.EQUIP_NONE) { - return false; - } + public Map getProudSkillBonusMap() { + return proudSkillBonusMap; + } - // Check if other avatars have this item equipped - Avatar otherAvatar = getPlayer().getAvatars().getAvatarById(item.getEquipCharacter()); - if (otherAvatar != null) { - // Unequip other avatar's item - if (otherAvatar.unequipItem(item.getItemData().getEquipType())) { - getPlayer().sendPacket(new PacketAvatarEquipChangeNotify(otherAvatar, item.getItemData().getEquipType())); - } - // Swap with other avatar - if (getEquips().containsKey(itemEquipType.getValue())) { - GameItem toSwap = this.getEquipBySlot(itemEquipType); - otherAvatar.equipItem(toSwap, false); - } - // Recalc - otherAvatar.recalcStats(); - } else if (getEquips().containsKey(itemEquipType.getValue())) { - // Unequip item in current slot if it exists - unequipItem(itemEquipType); - } - - // Set equip - getEquips().put(itemEquipType.getValue(), item); - - if (itemEquipType == EquipType.EQUIP_WEAPON && getPlayer().getWorld() != null) { - item.setWeaponEntityId(this.getPlayer().getWorld().getNextEntityId(EntityIdType.WEAPON)); - } - - item.setEquipCharacter(this.getAvatarId()); - item.save(); - - if (this.getPlayer().hasSentAvatarDataNotify()) { - this.getPlayer().sendPacket(new PacketAvatarEquipChangeNotify(this, item)); - } - - if (shouldRecalc) { - this.recalcStats(); - } - - return true; - } - - public boolean unequipItem(EquipType slot) { - GameItem item = getEquips().remove(slot.getValue()); - - if (item != null) { - item.setEquipCharacter(0); - item.save(); - return true; - } - - return false; - } - - public void recalcStats() { - recalcStats(false); - } - - public void recalcStats(boolean forceSendAbilityChange) { - // Setup - AvatarData data = this.getAvatarData(); - AvatarPromoteData promoteData = GameData.getAvatarPromoteData(data.getAvatarPromoteId(), this.getPromoteLevel()); - Int2IntOpenHashMap setMap = new Int2IntOpenHashMap(); - - // Extra ability embryos - Set prevExtraAbilityEmbryos = this.getExtraAbilityEmbryos(); - this.extraAbilityEmbryos = new HashSet<>(); + public Set getExtraAbilityEmbryos() { + return extraAbilityEmbryos; + } - // Fetters - this.setFetterList(data.getFetters()); - this.setNameCardRewardId(data.getNameCardRewardId()); - this.setNameCardId(data.getNameCardId()); - - // Get hp percent, set to 100% if none - float hpPercent = this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) <= 0 ? 1f : this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) / this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP); - - // Store current energy value for later - float currentEnergy = (this.getSkillDepot() != null) ? this.getFightProperty(this.getSkillDepot().getElementType().getCurEnergyProp()) : 0f; + public void setFetterList(List fetterList) { + this.fetters = fetterList; + } - // Clear properties - this.getFightProperties().clear(); - - // Base stats - this.setFightProperty(FightProperty.FIGHT_PROP_BASE_HP, data.getBaseHp(this.getLevel())); - this.setFightProperty(FightProperty.FIGHT_PROP_BASE_ATTACK, data.getBaseAttack(this.getLevel())); - this.setFightProperty(FightProperty.FIGHT_PROP_BASE_DEFENSE, data.getBaseDefense(this.getLevel())); - this.setFightProperty(FightProperty.FIGHT_PROP_CRITICAL, data.getBaseCritical()); - this.setFightProperty(FightProperty.FIGHT_PROP_CRITICAL_HURT, data.getBaseCriticalHurt()); - this.setFightProperty(FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY, 1f); - - if (promoteData != null) { - for (FightPropData fightPropData : promoteData.getAddProps()) { - this.addFightProperty(fightPropData.getProp(), fightPropData.getValue()); - } - } - - // Set energy usage - setCurrentEnergy(currentEnergy); - - // Artifacts - for (int slotId = 1; slotId <= 5; slotId++) { - // Get artifact - GameItem equip = this.getEquipBySlot(slotId); - if (equip == null) { - continue; - } - // Artifact main stat - ReliquaryMainPropData mainPropData = GameData.getReliquaryMainPropDataMap().get(equip.getMainPropId()); - if (mainPropData != null) { - ReliquaryLevelData levelData = GameData.getRelicLevelData(equip.getItemData().getRankLevel(), equip.getLevel()); - if (levelData != null) { - this.addFightProperty(mainPropData.getFightProp(), levelData.getPropValue(mainPropData.getFightProp())); - } - } - // Artifact sub stats - for (int appendPropId : equip.getAppendPropIdList()) { - ReliquaryAffixData affixData = GameData.getReliquaryAffixDataMap().get(appendPropId); - if (affixData != null) { - this.addFightProperty(affixData.getFightProp(), affixData.getPropValue()); - } - } - // Set bonus - if (equip.getItemData().getSetId() > 0) { - setMap.addTo(equip.getItemData().getSetId(), 1); - } - } + public List getFetterList() { + return fetters; + } - // Set stuff - for (Int2IntOpenHashMap.Entry e : setMap.int2IntEntrySet()) { - ReliquarySetData setData = GameData.getReliquarySetDataMap().get(e.getIntKey()); - if (setData == null) { - continue; - } - - // Calculate how many items are from the set - int amount = e.getIntValue(); - - // Add affix data from set bonus - for (int setIndex = 0; setIndex < setData.getSetNeedNum().length; setIndex++) { - if (amount >= setData.getSetNeedNum()[setIndex]) { - int affixId = (setData.getEquipAffixId() * 10) + setIndex; - - EquipAffixData affix = GameData.getEquipAffixDataMap().get(affixId); - if (affix == null) { - continue; - } - - // Add properties from this affix to our avatar - for (FightPropData prop : affix.getAddProps()) { - this.addFightProperty(prop.getProp(), prop.getValue()); - } - - // Add any skill strings from this affix - this.addToExtraAbilityEmbryos(affix.getOpenConfig(), true); - } else { - break; - } - } - } - - // Weapon - GameItem weapon = this.getWeapon(); - if (weapon != null) { - // Add stats - WeaponCurveData curveData = GameData.getWeaponCurveDataMap().get(weapon.getLevel()); - if (curveData != null) { - for (WeaponProperty weaponProperty : weapon.getItemData().getWeaponProperties()) { - this.addFightProperty(weaponProperty.getFightProp(), weaponProperty.getInitValue() * curveData.getMultByProp(weaponProperty.getType())); - } - } - // Weapon promotion stats - WeaponPromoteData wepPromoteData = GameData.getWeaponPromoteData(weapon.getItemData().getWeaponPromoteId(), weapon.getPromoteLevel()); - if (wepPromoteData != null) { - for (FightPropData prop : wepPromoteData.getAddProps()) { - if (prop.getValue() == 0f || prop.getProp() == null) { - continue; - } - this.addFightProperty(prop.getProp(), prop.getValue()); - } - } - // Add weapon skill from affixes - if (weapon.getAffixes() != null && weapon.getAffixes().size() > 0) { - // Weapons usually dont have more than one affix but just in case... - for (int af : weapon.getAffixes()) { - if (af == 0) { - continue; - } - // Calculate affix id - int affixId = (af * 10) + weapon.getRefinement(); - EquipAffixData affix = GameData.getEquipAffixDataMap().get(affixId); - if (affix == null) { - continue; - } - - // Add properties from this affix to our avatar - for (FightPropData prop : affix.getAddProps()) { - this.addFightProperty(prop.getProp(), prop.getValue()); - } - - // Add any skill strings from this affix - this.addToExtraAbilityEmbryos(affix.getOpenConfig(), true); - } - } - } - - // Add proud skills and unlock them if needed - AvatarSkillDepotData skillDepot = GameData.getAvatarSkillDepotDataMap().get(this.getSkillDepotId()); - this.getProudSkillList().clear(); - for (InherentProudSkillOpens openData : skillDepot.getInherentProudSkillOpens()) { - if (openData.getProudSkillGroupId() == 0) { - continue; - } - if (openData.getNeedAvatarPromoteLevel() <= this.getPromoteLevel()) { - int proudSkillId = (openData.getProudSkillGroupId() * 100) + 1; - if (GameData.getProudSkillDataMap().containsKey(proudSkillId)) { - this.getProudSkillList().add(proudSkillId); - } - } - } + public int getFetterLevel() { + return fetterLevel; + } - // Proud skills - for (int proudSkillId : this.getProudSkillList()) { - ProudSkillData proudSkillData = GameData.getProudSkillDataMap().get(proudSkillId); - if (proudSkillData == null) { - continue; - } - - // Add properties from this proud skill to our avatar - for (FightPropData prop : proudSkillData.getAddProps()) { - this.addFightProperty(prop.getProp(), prop.getValue()); - } - - // Add any skill strings from this proud skill - this.addToExtraAbilityEmbryos(proudSkillData.getOpenConfig(), true); - } - - // Constellations - if (this.getTalentIdList().size() > 0) { - for (int talentId : this.getTalentIdList()) { - AvatarTalentData avatarTalentData = GameData.getAvatarTalentDataMap().get(talentId); - if (avatarTalentData == null) { - return; - } - - // Add any skill strings from this constellation - this.addToExtraAbilityEmbryos(avatarTalentData.getOpenConfig(), false); - } - } + public void setFetterLevel(int fetterLevel) { + this.fetterLevel = fetterLevel; + } - // Set % stats - this.setFightProperty( - FightProperty.FIGHT_PROP_MAX_HP, - (getFightProperty(FightProperty.FIGHT_PROP_BASE_HP) * (1f + getFightProperty(FightProperty.FIGHT_PROP_HP_PERCENT))) + getFightProperty(FightProperty.FIGHT_PROP_HP) - ); - this.setFightProperty( - FightProperty.FIGHT_PROP_CUR_ATTACK, - (getFightProperty(FightProperty.FIGHT_PROP_BASE_ATTACK) * (1f + getFightProperty(FightProperty.FIGHT_PROP_ATTACK_PERCENT))) + getFightProperty(FightProperty.FIGHT_PROP_ATTACK) - ); - this.setFightProperty( - FightProperty.FIGHT_PROP_CUR_DEFENSE, - (getFightProperty(FightProperty.FIGHT_PROP_BASE_DEFENSE) * (1f + getFightProperty(FightProperty.FIGHT_PROP_DEFENSE_PERCENT))) + getFightProperty(FightProperty.FIGHT_PROP_DEFENSE) - ); - - // Set current hp - this.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * hpPercent); - - // Packet - if (getPlayer() != null && getPlayer().hasSentAvatarDataNotify()) { - // Update stats for client - getPlayer().sendPacket(new PacketAvatarFightPropNotify(this)); - // Update client abilities - EntityAvatar entity = this.getAsEntity(); - if (entity != null && (!this.getExtraAbilityEmbryos().equals(prevExtraAbilityEmbryos) || forceSendAbilityChange)) { - getPlayer().sendPacket(new PacketAbilityChangeNotify(entity)); - } - } - } - - public void addToExtraAbilityEmbryos(String openConfig, boolean forceAdd) { - if (openConfig == null || openConfig.length() == 0) { - return; - } - - OpenConfigEntry entry = GameData.getOpenConfigEntries().get(openConfig); - if (entry == null) { - if (forceAdd) { - // Add config string to ability skill list anyways - this.getExtraAbilityEmbryos().add(openConfig); - } - return; - } - - if (entry.getAddAbilities() != null) { - for (String ability : entry.getAddAbilities()) { - this.getExtraAbilityEmbryos().add(ability); - } - } - } - - public void recalcConstellations() { - // Clear first - this.getProudSkillBonusMap().clear(); - this.getSkillExtraChargeMap().clear(); - - // Sanity checks - if (getData() == null || getData().getSkillDepot() == null) { - return; - } - - if (this.getTalentIdList().size() > 0) { - for (int talentId : this.getTalentIdList()) { - AvatarTalentData avatarTalentData = GameData.getAvatarTalentDataMap().get(talentId); - - if (avatarTalentData == null || avatarTalentData.getOpenConfig() == null || avatarTalentData.getOpenConfig().length() == 0) { - continue; - } - - // Get open config to find which skill should be boosted - OpenConfigEntry entry = GameData.getOpenConfigEntries().get(avatarTalentData.getOpenConfig()); - if (entry == null) { - continue; - } - - // Check if we can add charges to a skill - if (entry.getSkillPointModifiers() != null) { - for (SkillPointModifier mod : entry.getSkillPointModifiers()) { - AvatarSkillData skillData = GameData.getAvatarSkillDataMap().get(mod.getSkillId()); - - if (skillData == null) continue; - - int charges = skillData.getMaxChargeNum() + mod.getDelta(); - - this.getSkillExtraChargeMap().put(mod.getSkillId(), charges); - } - continue; - } - - // Check if a skill can be boosted by +3 levels - int skillId = 0; - - if (entry.getExtraTalentIndex() == 2 && this.getData().getSkillDepot().getSkills().size() >= 2) { - // E skill - skillId = this.getData().getSkillDepot().getSkills().get(1); - } else if (entry.getExtraTalentIndex() == 9) { - // Ult skill - skillId = this.getData().getSkillDepot().getEnergySkill(); - } - - // Sanity check - if (skillId == 0) { - continue; - } - - // Get proud skill group id - AvatarSkillData skillData = GameData.getAvatarSkillDataMap().get(skillId); - - if (skillData == null) { - continue; - } - - // Add to bonus list - this.getProudSkillBonusMap().put(skillData.getProudSkillGroupId(), 3); - } - } - } - - public EntityAvatar getAsEntity() { - for (EntityAvatar entity : getPlayer().getTeamManager().getActiveTeam()) { - if (entity.getAvatar() == this) { - return entity; - } - } - return null; - } - - public int getEntityId() { - EntityAvatar entity = getAsEntity(); - return entity != null ? entity.getId() : 0; - } + public int getFetterExp() { + return fetterExp; + } - public void save() { - DatabaseHelper.saveAvatar(this); - } - - public AvatarInfo toProto() { - int fetterLevel = this.getFetterLevel(); - AvatarFetterInfo.Builder avatarFetter = AvatarFetterInfo.newBuilder() - .setExpLevel(fetterLevel); - - if (fetterLevel != 10) { - avatarFetter.setExpNumber(this.getFetterExp()); - } - - - if (this.getFetterList() != null) { - for (int i = 0; i < this.getFetterList().size(); i++) { - avatarFetter.addFetterList( - FetterData.newBuilder() - .setFetterId(this.getFetterList().get(i)) - .setFetterState(FetterState.FINISH.getValue()) - ); - } - } + public void setFetterExp(int fetterExp) { + this.fetterExp = fetterExp; + } - int cardId = this.getNameCardId(); + public int getNameCardId() { + return nameCardId; + } - if (this.getPlayer().getNameCardList().contains(cardId)) { - avatarFetter.addRewardedFetterLevelList(10); - } + public void setNameCardId(int nameCardId) { + this.nameCardId = nameCardId; + } - AvatarInfo.Builder avatarInfo = AvatarInfo.newBuilder() - .setAvatarId(this.getAvatarId()) - .setGuid(this.getGuid()) - .setLifeState(1) - .addAllTalentIdList(this.getTalentIdList()) - .putAllFightPropMap(this.getFightProperties()) - .setSkillDepotId(this.getSkillDepotId()) - .setCoreProudSkillLevel(this.getCoreProudSkillLevel()) - .putAllSkillLevelMap(this.getSkillLevelMap()) - .addAllInherentProudSkillList(this.getProudSkillList()) - .putAllProudSkillExtraLevelMap(getProudSkillBonusMap()) - .setAvatarType(1) - .setBornTime(this.getBornTime()) - .setFetterInfo(avatarFetter) - .setWearingFlycloakId(this.getFlyCloak()) - .setCostumeId(this.getCostume()); - - for (Entry entry : this.getSkillExtraChargeMap().entrySet()) { - avatarInfo.putSkillMap(entry.getKey(), AvatarSkillInfo.newBuilder().setMaxChargeCount(entry.getValue()).build()); - } - - for (GameItem item : this.getEquips().values()) { - avatarInfo.addEquipGuidList(item.getGuid()); - } - - avatarInfo.putPropMap(PlayerProperty.PROP_LEVEL.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, this.getLevel())); - avatarInfo.putPropMap(PlayerProperty.PROP_EXP.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_EXP, this.getExp())); - avatarInfo.putPropMap(PlayerProperty.PROP_BREAK_LEVEL.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_BREAK_LEVEL, this.getPromoteLevel())); - avatarInfo.putPropMap(PlayerProperty.PROP_SATIATION_VAL.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_SATIATION_VAL, 0)); - avatarInfo.putPropMap(PlayerProperty.PROP_SATIATION_PENALTY_TIME.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_SATIATION_PENALTY_TIME, 0)); - - return avatarInfo.build(); - } + public float getCurrentHp() { + return currentHp; + } - // used only in character showcase - public ShowAvatarInfo toShowAvatarInfoProto() { - AvatarFetterInfo.Builder avatarFetter = AvatarFetterInfo.newBuilder() - .setExpLevel(this.getFetterLevel()); + public void setCurrentHp(float currentHp) { + this.currentHp = currentHp; + } - ShowAvatarInfo.Builder showAvatarInfo = ShowAvatarInfoOuterClass.ShowAvatarInfo.newBuilder() - .setAvatarId(avatarId) - .addAllTalentIdList(this.getTalentIdList()) - .putAllFightPropMap(this.getFightProperties()) - .setSkillDepotId(this.getSkillDepotId()) - .setCoreProudSkillLevel(this.getCoreProudSkillLevel()) - .addAllInherentProudSkillList(this.getProudSkillList()) - .putAllSkillLevelMap(this.getSkillLevelMap()) - .putAllProudSkillExtraLevelMap(this.getProudSkillBonusMap()) - .setFetterInfo(avatarFetter) - .setCostumeId(this.getCostume()); + public void setCurrentEnergy() { + if (GAME_OPTIONS.energyUsage) { + this.setCurrentEnergy(this.currentEnergy); + } + } - showAvatarInfo.putPropMap(PlayerProperty.PROP_LEVEL.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, this.getLevel())); - showAvatarInfo.putPropMap(PlayerProperty.PROP_EXP.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_EXP, this.getExp())); - showAvatarInfo.putPropMap(PlayerProperty.PROP_BREAK_LEVEL.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_BREAK_LEVEL, this.getPromoteLevel())); - showAvatarInfo.putPropMap(PlayerProperty.PROP_SATIATION_VAL.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_SATIATION_VAL, this.getSatiation())); - showAvatarInfo.putPropMap(PlayerProperty.PROP_SATIATION_PENALTY_TIME.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_SATIATION_VAL, this.getSatiationPenalty())); - int maxStamina = this.getPlayer().getProperty(PlayerProperty.PROP_MAX_STAMINA); - showAvatarInfo.putPropMap(PlayerProperty.PROP_MAX_STAMINA.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_MAX_STAMINA, maxStamina)); + public void setCurrentEnergy(float currentEnergy) { + if (this.getSkillDepot() != null && this.getSkillDepot().getEnergySkillData() != null) { + ElementType element = this.getSkillDepot().getElementType(); + this.setFightProperty(element.getMaxEnergyProp(), this.getSkillDepot().getEnergySkillData().getCostElemVal()); - for (GameItem item : this.getEquips().values()) { - if (item.getItemType() == ItemType.ITEM_RELIQUARY) { - showAvatarInfo.addEquipList(ShowEquip.newBuilder() - .setItemId(item.getItemId()) - .setReliquary(item.toReliquaryProto())); - } else if (item.getItemType() == ItemType.ITEM_WEAPON) { - showAvatarInfo.addEquipList(ShowEquip.newBuilder() - .setItemId(item.getItemId()) - .setWeapon(item.toWeaponProto())); - } - } + if (GAME_OPTIONS.energyUsage) { + this.setFightProperty(element.getCurEnergyProp(), currentEnergy); + } + else { + this.setFightProperty(element.getCurEnergyProp(), this.getSkillDepot().getEnergySkillData().getCostElemVal()); + } + } + } - return showAvatarInfo.build(); - } - - @PostLoad - private void onLoad() { - - } - - @PrePersist - private void prePersist() { - this.currentHp = this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP); - } + public void setCurrentEnergy(FightProperty curEnergyProp, float currentEnergy) { + if (GAME_OPTIONS.energyUsage) { + this.setFightProperty(curEnergyProp, currentEnergy); + this.currentEnergy = currentEnergy; + this.save(); + } + } + + public Int2FloatOpenHashMap getFightProperties() { + return fightProp; + } + + public void setFightProperty(FightProperty prop, float value) { + this.getFightProperties().put(prop.getId(), value); + } + + private void setFightProperty(int id, float value) { + this.getFightProperties().put(id, value); + } + + public void addFightProperty(FightProperty prop, float value) { + this.getFightProperties().put(prop.getId(), getFightProperty(prop) + value); + } + + public float getFightProperty(FightProperty prop) { + return getFightProperties().getOrDefault(prop.getId(), 0f); + } + + public Set getTalentIdList() { + return talentIdList; + } + + public int getCoreProudSkillLevel() { + return coreProudSkillLevel; + } + + public void setCoreProudSkillLevel(int constLevel) { + this.coreProudSkillLevel = constLevel; + } + + public Set getProudSkillList() { + return proudSkillList; + } + + public int getFlyCloak() { + return flyCloak; + } + + public void setFlyCloak(int flyCloak) { + this.flyCloak = flyCloak; + } + + public int getCostume() { + return costume; + } + + public void setCostume(int costume) { + this.costume = costume; + } + + public int getBornTime() { + return bornTime; + } + + public boolean equipItem(GameItem item, boolean shouldRecalc) { + // Sanity check equip type + EquipType itemEquipType = item.getItemData().getEquipType(); + if (itemEquipType == EquipType.EQUIP_NONE) { + return false; + } + + // Check if other avatars have this item equipped + Avatar otherAvatar = getPlayer().getAvatars().getAvatarById(item.getEquipCharacter()); + if (otherAvatar != null) { + // Unequip other avatar's item + if (otherAvatar.unequipItem(item.getItemData().getEquipType())) { + getPlayer().sendPacket(new PacketAvatarEquipChangeNotify(otherAvatar, item.getItemData().getEquipType())); + } + // Swap with other avatar + if (getEquips().containsKey(itemEquipType.getValue())) { + GameItem toSwap = this.getEquipBySlot(itemEquipType); + otherAvatar.equipItem(toSwap, false); + } + // Recalc + otherAvatar.recalcStats(); + } else if (getEquips().containsKey(itemEquipType.getValue())) { + // Unequip item in current slot if it exists + unequipItem(itemEquipType); + } + + // Set equip + getEquips().put(itemEquipType.getValue(), item); + + if (itemEquipType == EquipType.EQUIP_WEAPON && getPlayer().getWorld() != null) { + item.setWeaponEntityId(this.getPlayer().getWorld().getNextEntityId(EntityIdType.WEAPON)); + } + + item.setEquipCharacter(this.getAvatarId()); + item.save(); + + if (this.getPlayer().hasSentAvatarDataNotify()) { + this.getPlayer().sendPacket(new PacketAvatarEquipChangeNotify(this, item)); + } + + if (shouldRecalc) { + this.recalcStats(); + } + + return true; + } + + public boolean unequipItem(EquipType slot) { + GameItem item = getEquips().remove(slot.getValue()); + + if (item != null) { + item.setEquipCharacter(0); + item.save(); + return true; + } + + return false; + } + + public void recalcStats() { + recalcStats(false); + } + + public void recalcStats(boolean forceSendAbilityChange) { + // Setup + AvatarData data = this.getAvatarData(); + AvatarPromoteData promoteData = GameData.getAvatarPromoteData(data.getAvatarPromoteId(), this.getPromoteLevel()); + Int2IntOpenHashMap setMap = new Int2IntOpenHashMap(); + + // Extra ability embryos + Set prevExtraAbilityEmbryos = this.getExtraAbilityEmbryos(); + this.extraAbilityEmbryos = new HashSet<>(); + + // Fetters + this.setFetterList(data.getFetters()); + this.setNameCardRewardId(data.getNameCardRewardId()); + this.setNameCardId(data.getNameCardId()); + + // Get hp percent, set to 100% if none + float hpPercent = this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) <= 0 ? 1f : this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) / this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP); + + // Store current energy value for later + float currentEnergy = (this.getSkillDepot() != null) ? this.getFightProperty(this.getSkillDepot().getElementType().getCurEnergyProp()) : 0f; + + // Clear properties + this.getFightProperties().clear(); + + // Base stats + this.setFightProperty(FightProperty.FIGHT_PROP_BASE_HP, data.getBaseHp(this.getLevel())); + this.setFightProperty(FightProperty.FIGHT_PROP_BASE_ATTACK, data.getBaseAttack(this.getLevel())); + this.setFightProperty(FightProperty.FIGHT_PROP_BASE_DEFENSE, data.getBaseDefense(this.getLevel())); + this.setFightProperty(FightProperty.FIGHT_PROP_CRITICAL, data.getBaseCritical()); + this.setFightProperty(FightProperty.FIGHT_PROP_CRITICAL_HURT, data.getBaseCriticalHurt()); + this.setFightProperty(FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY, 1f); + + if (promoteData != null) { + for (FightPropData fightPropData : promoteData.getAddProps()) { + this.addFightProperty(fightPropData.getProp(), fightPropData.getValue()); + } + } + + // Set energy usage + setCurrentEnergy(currentEnergy); + + // Artifacts + for (int slotId = 1; slotId <= 5; slotId++) { + // Get artifact + GameItem equip = this.getEquipBySlot(slotId); + if (equip == null) { + continue; + } + // Artifact main stat + ReliquaryMainPropData mainPropData = GameData.getReliquaryMainPropDataMap().get(equip.getMainPropId()); + if (mainPropData != null) { + ReliquaryLevelData levelData = GameData.getRelicLevelData(equip.getItemData().getRankLevel(), equip.getLevel()); + if (levelData != null) { + this.addFightProperty(mainPropData.getFightProp(), levelData.getPropValue(mainPropData.getFightProp())); + } + } + // Artifact sub stats + for (int appendPropId : equip.getAppendPropIdList()) { + ReliquaryAffixData affixData = GameData.getReliquaryAffixDataMap().get(appendPropId); + if (affixData != null) { + this.addFightProperty(affixData.getFightProp(), affixData.getPropValue()); + } + } + // Set bonus + if (equip.getItemData().getSetId() > 0) { + setMap.addTo(equip.getItemData().getSetId(), 1); + } + } + + // Set stuff + for (Int2IntOpenHashMap.Entry e : setMap.int2IntEntrySet()) { + ReliquarySetData setData = GameData.getReliquarySetDataMap().get(e.getIntKey()); + if (setData == null) { + continue; + } + + // Calculate how many items are from the set + int amount = e.getIntValue(); + + // Add affix data from set bonus + for (int setIndex = 0; setIndex < setData.getSetNeedNum().length; setIndex++) { + if (amount >= setData.getSetNeedNum()[setIndex]) { + int affixId = (setData.getEquipAffixId() * 10) + setIndex; + + EquipAffixData affix = GameData.getEquipAffixDataMap().get(affixId); + if (affix == null) { + continue; + } + + // Add properties from this affix to our avatar + for (FightPropData prop : affix.getAddProps()) { + this.addFightProperty(prop.getProp(), prop.getValue()); + } + + // Add any skill strings from this affix + this.addToExtraAbilityEmbryos(affix.getOpenConfig(), true); + } else { + break; + } + } + } + + // Weapon + GameItem weapon = this.getWeapon(); + if (weapon != null) { + // Add stats + WeaponCurveData curveData = GameData.getWeaponCurveDataMap().get(weapon.getLevel()); + if (curveData != null) { + for (WeaponProperty weaponProperty : weapon.getItemData().getWeaponProperties()) { + this.addFightProperty(weaponProperty.getFightProp(), weaponProperty.getInitValue() * curveData.getMultByProp(weaponProperty.getType())); + } + } + // Weapon promotion stats + WeaponPromoteData wepPromoteData = GameData.getWeaponPromoteData(weapon.getItemData().getWeaponPromoteId(), weapon.getPromoteLevel()); + if (wepPromoteData != null) { + for (FightPropData prop : wepPromoteData.getAddProps()) { + if (prop.getValue() == 0f || prop.getProp() == null) { + continue; + } + this.addFightProperty(prop.getProp(), prop.getValue()); + } + } + // Add weapon skill from affixes + if (weapon.getAffixes() != null && weapon.getAffixes().size() > 0) { + // Weapons usually dont have more than one affix but just in case... + for (int af : weapon.getAffixes()) { + if (af == 0) { + continue; + } + // Calculate affix id + int affixId = (af * 10) + weapon.getRefinement(); + EquipAffixData affix = GameData.getEquipAffixDataMap().get(affixId); + if (affix == null) { + continue; + } + + // Add properties from this affix to our avatar + for (FightPropData prop : affix.getAddProps()) { + this.addFightProperty(prop.getProp(), prop.getValue()); + } + + // Add any skill strings from this affix + this.addToExtraAbilityEmbryos(affix.getOpenConfig(), true); + } + } + } + + // Add proud skills and unlock them if needed + AvatarSkillDepotData skillDepot = GameData.getAvatarSkillDepotDataMap().get(this.getSkillDepotId()); + this.getProudSkillList().clear(); + for (InherentProudSkillOpens openData : skillDepot.getInherentProudSkillOpens()) { + if (openData.getProudSkillGroupId() == 0) { + continue; + } + if (openData.getNeedAvatarPromoteLevel() <= this.getPromoteLevel()) { + int proudSkillId = (openData.getProudSkillGroupId() * 100) + 1; + if (GameData.getProudSkillDataMap().containsKey(proudSkillId)) { + this.getProudSkillList().add(proudSkillId); + } + } + } + + // Proud skills + for (int proudSkillId : this.getProudSkillList()) { + ProudSkillData proudSkillData = GameData.getProudSkillDataMap().get(proudSkillId); + if (proudSkillData == null) { + continue; + } + + // Add properties from this proud skill to our avatar + for (FightPropData prop : proudSkillData.getAddProps()) { + this.addFightProperty(prop.getProp(), prop.getValue()); + } + + // Add any skill strings from this proud skill + this.addToExtraAbilityEmbryos(proudSkillData.getOpenConfig(), true); + } + + // Constellations + if (this.getTalentIdList().size() > 0) { + for (int talentId : this.getTalentIdList()) { + AvatarTalentData avatarTalentData = GameData.getAvatarTalentDataMap().get(talentId); + if (avatarTalentData == null) { + return; + } + + // Add any skill strings from this constellation + this.addToExtraAbilityEmbryos(avatarTalentData.getOpenConfig(), false); + } + } + + // Set % stats + this.setFightProperty( + FightProperty.FIGHT_PROP_MAX_HP, + (getFightProperty(FightProperty.FIGHT_PROP_BASE_HP) * (1f + getFightProperty(FightProperty.FIGHT_PROP_HP_PERCENT))) + getFightProperty(FightProperty.FIGHT_PROP_HP) + ); + this.setFightProperty( + FightProperty.FIGHT_PROP_CUR_ATTACK, + (getFightProperty(FightProperty.FIGHT_PROP_BASE_ATTACK) * (1f + getFightProperty(FightProperty.FIGHT_PROP_ATTACK_PERCENT))) + getFightProperty(FightProperty.FIGHT_PROP_ATTACK) + ); + this.setFightProperty( + FightProperty.FIGHT_PROP_CUR_DEFENSE, + (getFightProperty(FightProperty.FIGHT_PROP_BASE_DEFENSE) * (1f + getFightProperty(FightProperty.FIGHT_PROP_DEFENSE_PERCENT))) + getFightProperty(FightProperty.FIGHT_PROP_DEFENSE) + ); + + // Set current hp + this.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * hpPercent); + + // Packet + if (getPlayer() != null && getPlayer().hasSentAvatarDataNotify()) { + // Update stats for client + getPlayer().sendPacket(new PacketAvatarFightPropNotify(this)); + // Update client abilities + EntityAvatar entity = this.getAsEntity(); + if (entity != null && (!this.getExtraAbilityEmbryos().equals(prevExtraAbilityEmbryos) || forceSendAbilityChange)) { + getPlayer().sendPacket(new PacketAbilityChangeNotify(entity)); + } + } + } + + public void addToExtraAbilityEmbryos(String openConfig, boolean forceAdd) { + if (openConfig == null || openConfig.length() == 0) { + return; + } + + OpenConfigEntry entry = GameData.getOpenConfigEntries().get(openConfig); + if (entry == null) { + if (forceAdd) { + // Add config string to ability skill list anyways + this.getExtraAbilityEmbryos().add(openConfig); + } + return; + } + + if (entry.getAddAbilities() != null) { + for (String ability : entry.getAddAbilities()) { + this.getExtraAbilityEmbryos().add(ability); + } + } + } + + public void recalcConstellations() { + // Clear first + this.getProudSkillBonusMap().clear(); + this.getSkillExtraChargeMap().clear(); + + // Sanity checks + if (getData() == null || getData().getSkillDepot() == null) { + return; + } + + if (this.getTalentIdList().size() > 0) { + for (int talentId : this.getTalentIdList()) { + AvatarTalentData avatarTalentData = GameData.getAvatarTalentDataMap().get(talentId); + + if (avatarTalentData == null || avatarTalentData.getOpenConfig() == null || avatarTalentData.getOpenConfig().length() == 0) { + continue; + } + + // Get open config to find which skill should be boosted + OpenConfigEntry entry = GameData.getOpenConfigEntries().get(avatarTalentData.getOpenConfig()); + if (entry == null) { + continue; + } + + // Check if we can add charges to a skill + if (entry.getSkillPointModifiers() != null) { + for (SkillPointModifier mod : entry.getSkillPointModifiers()) { + AvatarSkillData skillData = GameData.getAvatarSkillDataMap().get(mod.getSkillId()); + + if (skillData == null) continue; + + int charges = skillData.getMaxChargeNum() + mod.getDelta(); + + this.getSkillExtraChargeMap().put(mod.getSkillId(), charges); + } + continue; + } + + // Check if a skill can be boosted by +3 levels + int skillId = 0; + + if (entry.getExtraTalentIndex() == 2 && this.getData().getSkillDepot().getSkills().size() >= 2) { + // E skill + skillId = this.getData().getSkillDepot().getSkills().get(1); + } else if (entry.getExtraTalentIndex() == 9) { + // Ult skill + skillId = this.getData().getSkillDepot().getEnergySkill(); + } + + // Sanity check + if (skillId == 0) { + continue; + } + + // Get proud skill group id + AvatarSkillData skillData = GameData.getAvatarSkillDataMap().get(skillId); + + if (skillData == null) { + continue; + } + + // Add to bonus list + this.getProudSkillBonusMap().put(skillData.getProudSkillGroupId(), 3); + } + } + } + + public EntityAvatar getAsEntity() { + for (EntityAvatar entity : getPlayer().getTeamManager().getActiveTeam()) { + if (entity.getAvatar() == this) { + return entity; + } + } + return null; + } + + public int getEntityId() { + EntityAvatar entity = getAsEntity(); + return entity != null ? entity.getId() : 0; + } + + public void save() { + DatabaseHelper.saveAvatar(this); + } + + public AvatarInfo toProto() { + int fetterLevel = this.getFetterLevel(); + AvatarFetterInfo.Builder avatarFetter = AvatarFetterInfo.newBuilder() + .setExpLevel(fetterLevel); + + if (fetterLevel != 10) { + avatarFetter.setExpNumber(this.getFetterExp()); + } + + + if (this.getFetterList() != null) { + for (int i = 0; i < this.getFetterList().size(); i++) { + avatarFetter.addFetterList( + FetterData.newBuilder() + .setFetterId(this.getFetterList().get(i)) + .setFetterState(FetterState.FINISH.getValue()) + ); + } + } + + int cardId = this.getNameCardId(); + + if (this.getPlayer().getNameCardList().contains(cardId)) { + avatarFetter.addRewardedFetterLevelList(10); + } + + AvatarInfo.Builder avatarInfo = AvatarInfo.newBuilder() + .setAvatarId(this.getAvatarId()) + .setGuid(this.getGuid()) + .setLifeState(1) + .addAllTalentIdList(this.getTalentIdList()) + .putAllFightPropMap(this.getFightProperties()) + .setSkillDepotId(this.getSkillDepotId()) + .setCoreProudSkillLevel(this.getCoreProudSkillLevel()) + .putAllSkillLevelMap(this.getSkillLevelMap()) + .addAllInherentProudSkillList(this.getProudSkillList()) + .putAllProudSkillExtraLevelMap(getProudSkillBonusMap()) + .setAvatarType(1) + .setBornTime(this.getBornTime()) + .setFetterInfo(avatarFetter) + .setWearingFlycloakId(this.getFlyCloak()) + .setCostumeId(this.getCostume()); + + for (Entry entry : this.getSkillExtraChargeMap().entrySet()) { + avatarInfo.putSkillMap(entry.getKey(), AvatarSkillInfo.newBuilder().setMaxChargeCount(entry.getValue()).build()); + } + + for (GameItem item : this.getEquips().values()) { + avatarInfo.addEquipGuidList(item.getGuid()); + } + + avatarInfo.putPropMap(PlayerProperty.PROP_LEVEL.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, this.getLevel())); + avatarInfo.putPropMap(PlayerProperty.PROP_EXP.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_EXP, this.getExp())); + avatarInfo.putPropMap(PlayerProperty.PROP_BREAK_LEVEL.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_BREAK_LEVEL, this.getPromoteLevel())); + avatarInfo.putPropMap(PlayerProperty.PROP_SATIATION_VAL.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_SATIATION_VAL, 0)); + avatarInfo.putPropMap(PlayerProperty.PROP_SATIATION_PENALTY_TIME.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_SATIATION_PENALTY_TIME, 0)); + + return avatarInfo.build(); + } + + // used only in character showcase + public ShowAvatarInfo toShowAvatarInfoProto() { + AvatarFetterInfo.Builder avatarFetter = AvatarFetterInfo.newBuilder() + .setExpLevel(this.getFetterLevel()); + + ShowAvatarInfo.Builder showAvatarInfo = ShowAvatarInfoOuterClass.ShowAvatarInfo.newBuilder() + .setAvatarId(avatarId) + .addAllTalentIdList(this.getTalentIdList()) + .putAllFightPropMap(this.getFightProperties()) + .setSkillDepotId(this.getSkillDepotId()) + .setCoreProudSkillLevel(this.getCoreProudSkillLevel()) + .addAllInherentProudSkillList(this.getProudSkillList()) + .putAllSkillLevelMap(this.getSkillLevelMap()) + .putAllProudSkillExtraLevelMap(this.getProudSkillBonusMap()) + .setFetterInfo(avatarFetter) + .setCostumeId(this.getCostume()); + + showAvatarInfo.putPropMap(PlayerProperty.PROP_LEVEL.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, this.getLevel())); + showAvatarInfo.putPropMap(PlayerProperty.PROP_EXP.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_EXP, this.getExp())); + showAvatarInfo.putPropMap(PlayerProperty.PROP_BREAK_LEVEL.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_BREAK_LEVEL, this.getPromoteLevel())); + showAvatarInfo.putPropMap(PlayerProperty.PROP_SATIATION_VAL.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_SATIATION_VAL, this.getSatiation())); + showAvatarInfo.putPropMap(PlayerProperty.PROP_SATIATION_PENALTY_TIME.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_SATIATION_VAL, this.getSatiationPenalty())); + int maxStamina = this.getPlayer().getProperty(PlayerProperty.PROP_MAX_STAMINA); + showAvatarInfo.putPropMap(PlayerProperty.PROP_MAX_STAMINA.getId(), ProtoHelper.newPropValue(PlayerProperty.PROP_MAX_STAMINA, maxStamina)); + + for (GameItem item : this.getEquips().values()) { + if (item.getItemType() == ItemType.ITEM_RELIQUARY) { + showAvatarInfo.addEquipList(ShowEquip.newBuilder() + .setItemId(item.getItemId()) + .setReliquary(item.toReliquaryProto())); + } else if (item.getItemType() == ItemType.ITEM_WEAPON) { + showAvatarInfo.addEquipList(ShowEquip.newBuilder() + .setItemId(item.getItemId()) + .setWeapon(item.toWeaponProto())); + } + } + + return showAvatarInfo.build(); + } + + @PostLoad + private void onLoad() { + + } + + @PrePersist + private void prePersist() { + this.currentHp = this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP); + } } diff --git a/src/main/java/emu/grasscutter/game/avatar/AvatarStorage.java b/src/main/java/emu/grasscutter/game/avatar/AvatarStorage.java index 3c3596277..d7f6272f0 100644 --- a/src/main/java/emu/grasscutter/game/avatar/AvatarStorage.java +++ b/src/main/java/emu/grasscutter/game/avatar/AvatarStorage.java @@ -19,155 +19,155 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; public class AvatarStorage extends BasePlayerManager implements Iterable { - private final Int2ObjectMap avatars; - private final Long2ObjectMap avatarsGuid; - - public AvatarStorage(Player player) { - super(player); - this.avatars = new Int2ObjectOpenHashMap<>(); - this.avatarsGuid = new Long2ObjectOpenHashMap<>(); - } + private final Int2ObjectMap avatars; + private final Long2ObjectMap avatarsGuid; - public Int2ObjectMap getAvatars() { - return avatars; - } - - public int getAvatarCount() { - return this.avatars.size(); - } - - public Avatar getAvatarById(int id) { - return getAvatars().get(id); - } - - public Avatar getAvatarByGuid(long id) { - return avatarsGuid.get(id); - } - - public boolean hasAvatar(int id) { - return getAvatars().containsKey(id); - } - - public boolean addAvatar(Avatar avatar) { - if (avatar.getAvatarData() == null || this.hasAvatar(avatar.getAvatarId())) { - return false; - } - - // Set owner first - avatar.setOwner(getPlayer()); + public AvatarStorage(Player player) { + super(player); + this.avatars = new Int2ObjectOpenHashMap<>(); + this.avatarsGuid = new Long2ObjectOpenHashMap<>(); + } - // Put into maps - this.avatars.put(avatar.getAvatarId(), avatar); - this.avatarsGuid.put(avatar.getGuid(), avatar); + public Int2ObjectMap getAvatars() { + return avatars; + } - avatar.save(); + public int getAvatarCount() { + return this.avatars.size(); + } - return true; - } - - public void addStartingWeapon(Avatar avatar) { - // Make sure avatar owner is this player - if (avatar.getPlayer() != this.getPlayer()) { - return; - } - - // Create weapon - GameItem weapon = new GameItem(avatar.getAvatarData().getInitialWeapon()); - - if (weapon.getItemData() != null) { - this.getPlayer().getInventory().addItem(weapon); - - avatar.equipItem(weapon, true); - } - } - - public boolean wearFlycloak(long avatarGuid, int flycloakId) { - Avatar avatar = this.getAvatarByGuid(avatarGuid); + public Avatar getAvatarById(int id) { + return getAvatars().get(id); + } - if (avatar == null || !getPlayer().getFlyCloakList().contains(flycloakId)) { - return false; - } - - avatar.setFlyCloak(flycloakId); - avatar.save(); - - // Update - getPlayer().sendPacket(new PacketAvatarFlycloakChangeNotify(avatar)); + public Avatar getAvatarByGuid(long id) { + return avatarsGuid.get(id); + } - return true; - } - - public boolean changeCostume(long avatarGuid, int costumeId) { - Avatar avatar = this.getAvatarByGuid(avatarGuid); + public boolean hasAvatar(int id) { + return getAvatars().containsKey(id); + } - if (avatar == null) { - return false; - } - - if (costumeId != 0 && !getPlayer().getCostumeList().contains(costumeId)) { - return false; - } - - // TODO make sure avatar can wear costume - - avatar.setCostume(costumeId); - avatar.save(); + public boolean addAvatar(Avatar avatar) { + if (avatar.getAvatarData() == null || this.hasAvatar(avatar.getAvatarId())) { + return false; + } - // Update entity - EntityAvatar entity = avatar.getAsEntity(); - if (entity == null) { - entity = new EntityAvatar(avatar); - getPlayer().sendPacket(new PacketAvatarChangeCostumeNotify(entity)); - } else { - getPlayer().getScene().broadcastPacket(new PacketAvatarChangeCostumeNotify(entity)); - } - - // Done - return true; - } - - public void loadFromDatabase() { - List avatars = DatabaseHelper.getAvatars(getPlayer()); - - for (Avatar avatar : avatars) { - // Should never happen - if (avatar.getObjectId() == null) { - continue; - } - - AvatarData avatarData = GameData.getAvatarDataMap().get(avatar.getAvatarId()); - AvatarSkillDepotData skillDepot = GameData.getAvatarSkillDepotDataMap().get(avatar.getSkillDepotId()); - if (avatarData == null || skillDepot == null) { - continue; - } - - // Set ownerships - avatar.setAvatarData(avatarData); - avatar.setSkillDepot(skillDepot); - avatar.setOwner(getPlayer()); - - // Force recalc of const boosted skills - avatar.recalcConstellations(); - - // Add to avatar storage - this.avatars.put(avatar.getAvatarId(), avatar); - this.avatarsGuid.put(avatar.getGuid(), avatar); - } - } - - public void postLoad() { - for (Avatar avatar : this) { - // Weapon check - if (avatar.getWeapon() == null) { - this.addStartingWeapon(avatar); - } - // Recalc stats - avatar.recalcStats(); - } - } + // Set owner first + avatar.setOwner(getPlayer()); - @Override - public Iterator iterator() { - return getAvatars().values().iterator(); - } + // Put into maps + this.avatars.put(avatar.getAvatarId(), avatar); + this.avatarsGuid.put(avatar.getGuid(), avatar); + + avatar.save(); + + return true; + } + + public void addStartingWeapon(Avatar avatar) { + // Make sure avatar owner is this player + if (avatar.getPlayer() != this.getPlayer()) { + return; + } + + // Create weapon + GameItem weapon = new GameItem(avatar.getAvatarData().getInitialWeapon()); + + if (weapon.getItemData() != null) { + this.getPlayer().getInventory().addItem(weapon); + + avatar.equipItem(weapon, true); + } + } + + public boolean wearFlycloak(long avatarGuid, int flycloakId) { + Avatar avatar = this.getAvatarByGuid(avatarGuid); + + if (avatar == null || !getPlayer().getFlyCloakList().contains(flycloakId)) { + return false; + } + + avatar.setFlyCloak(flycloakId); + avatar.save(); + + // Update + getPlayer().sendPacket(new PacketAvatarFlycloakChangeNotify(avatar)); + + return true; + } + + public boolean changeCostume(long avatarGuid, int costumeId) { + Avatar avatar = this.getAvatarByGuid(avatarGuid); + + if (avatar == null) { + return false; + } + + if (costumeId != 0 && !getPlayer().getCostumeList().contains(costumeId)) { + return false; + } + + // TODO make sure avatar can wear costume + + avatar.setCostume(costumeId); + avatar.save(); + + // Update entity + EntityAvatar entity = avatar.getAsEntity(); + if (entity == null) { + entity = new EntityAvatar(avatar); + getPlayer().sendPacket(new PacketAvatarChangeCostumeNotify(entity)); + } else { + getPlayer().getScene().broadcastPacket(new PacketAvatarChangeCostumeNotify(entity)); + } + + // Done + return true; + } + + public void loadFromDatabase() { + List avatars = DatabaseHelper.getAvatars(getPlayer()); + + for (Avatar avatar : avatars) { + // Should never happen + if (avatar.getObjectId() == null) { + continue; + } + + AvatarData avatarData = GameData.getAvatarDataMap().get(avatar.getAvatarId()); + AvatarSkillDepotData skillDepot = GameData.getAvatarSkillDepotDataMap().get(avatar.getSkillDepotId()); + if (avatarData == null || skillDepot == null) { + continue; + } + + // Set ownerships + avatar.setAvatarData(avatarData); + avatar.setSkillDepot(skillDepot); + avatar.setOwner(getPlayer()); + + // Force recalc of const boosted skills + avatar.recalcConstellations(); + + // Add to avatar storage + this.avatars.put(avatar.getAvatarId(), avatar); + this.avatarsGuid.put(avatar.getGuid(), avatar); + } + } + + public void postLoad() { + for (Avatar avatar : this) { + // Weapon check + if (avatar.getWeapon() == null) { + this.addStartingWeapon(avatar); + } + // Recalc stats + avatar.recalcStats(); + } + } + + @Override + public Iterator iterator() { + return getAvatars().values().iterator(); + } } diff --git a/src/main/java/emu/grasscutter/game/battlepass/BattlePassManager.java b/src/main/java/emu/grasscutter/game/battlepass/BattlePassManager.java index 6c95db479..ac5608503 100644 --- a/src/main/java/emu/grasscutter/game/battlepass/BattlePassManager.java +++ b/src/main/java/emu/grasscutter/game/battlepass/BattlePassManager.java @@ -42,322 +42,322 @@ import lombok.Getter; @Entity(value = "battlepass", useDiscriminator = false) public class BattlePassManager extends BasePlayerDataManager { - @Id @Getter private ObjectId id; - - @Indexed private int ownerUid; + @Id @Getter private ObjectId id; + + @Indexed private int ownerUid; @Getter private int point; @Getter private int cyclePoints; // Weekly maximum cap @Getter private int level; - + @Getter private boolean viewed; private boolean paid; - + private Map missions; private Map takenRewards; - + @Deprecated // Morphia only public BattlePassManager() {} public BattlePassManager(Player player) { super(player); } - + public void setPlayer(Player player) { - this.player = player; - this.ownerUid = player.getUid(); + this.player = player; + this.ownerUid = player.getUid(); } - + public void updateViewed() { - this.viewed = true; + this.viewed = true; } - public boolean setLevel(int level) { - if (level >= 0 && level <= GameConstants.BATTLE_PASS_MAX_LEVEL) { - this.level = level; - this.point = 0; - this.player.sendPacket(new PacketBattlePassCurScheduleUpdateNotify(this.player)); - return true; - } - return false; - } + public boolean setLevel(int level) { + if (level >= 0 && level <= GameConstants.BATTLE_PASS_MAX_LEVEL) { + this.level = level; + this.point = 0; + this.player.sendPacket(new PacketBattlePassCurScheduleUpdateNotify(this.player)); + return true; + } + return false; + } - public void addPoints(int points){ + public void addPoints(int points) { this.addPointsDirectly(points, false); - + this.player.sendPacket(new PacketBattlePassCurScheduleUpdateNotify(player)); this.save(); } public void addPointsDirectly(int points, boolean isWeekly) { - int amount = points; - - if (isWeekly) { - amount = Math.min(amount, GameConstants.BATTLE_PASS_POINT_PER_WEEK - this.cyclePoints); - } - - if (amount <= 0) { - return; - } - + int amount = points; + + if (isWeekly) { + amount = Math.min(amount, GameConstants.BATTLE_PASS_POINT_PER_WEEK - this.cyclePoints); + } + + if (amount <= 0) { + return; + } + this.point += amount; this.cyclePoints += amount; - + if (this.point >= GameConstants.BATTLE_PASS_POINT_PER_LEVEL && this.getLevel() < GameConstants.BATTLE_PASS_MAX_LEVEL) { - int levelups = Math.floorDiv(this.point, GameConstants.BATTLE_PASS_POINT_PER_LEVEL); - - // Make sure player cant go above max BP level - levelups = Math.min(levelups, GameConstants.BATTLE_PASS_MAX_LEVEL - levelups); - - // Set new points after level up - this.point = this.point - (levelups * GameConstants.BATTLE_PASS_POINT_PER_LEVEL); - this.level += levelups; + int levelups = Math.floorDiv(this.point, GameConstants.BATTLE_PASS_POINT_PER_LEVEL); + + // Make sure player cant go above max BP level + levelups = Math.min(levelups, GameConstants.BATTLE_PASS_MAX_LEVEL - levelups); + + // Set new points after level up + this.point = this.point - (levelups * GameConstants.BATTLE_PASS_POINT_PER_LEVEL); + this.level += levelups; } } - - public Map getMissions() { - if (this.missions == null) this.missions = new HashMap<>(); - return this.missions; - } - // Will return a new empty mission if the mission id is not found - public BattlePassMission loadMissionById(int id) { - return getMissions().computeIfAbsent(id, i -> new BattlePassMission(i)); - } - - public boolean hasMission(int id) { - return getMissions().containsKey(id); - } + public Map getMissions() { + if (this.missions == null) this.missions = new HashMap<>(); + return this.missions; + } - public boolean isPaid() { - // ToDo: Change this when we actually support unlocking "paid" BP. - return true; - } + // Will return a new empty mission if the mission id is not found + public BattlePassMission loadMissionById(int id) { + return getMissions().computeIfAbsent(id, i -> new BattlePassMission(i)); + } - public Map getTakenRewards() { - if (this.takenRewards == null) this.takenRewards = new HashMap<>(); - return this.takenRewards; - } - - // Mission triggers - public void triggerMission(WatcherTriggerType triggerType) { - getPlayer().getServer().getBattlePassSystem().triggerMission(getPlayer(), triggerType); - } - - public void triggerMission(WatcherTriggerType triggerType, int param, int progress) { - getPlayer().getServer().getBattlePassSystem().triggerMission(getPlayer(), triggerType, param, progress); - } - - // Handlers - public void takeMissionPoint(List missionIdList) { - // Obvious exploit check - if (missionIdList.size() > GameData.getBattlePassMissionDataMap().size()) { - return; - } - - List updatedMissions = new ArrayList<>(missionIdList.size()); - - for (int id : missionIdList) { - // Skip if we dont have this mission - if (!this.hasMission(id)) { - continue; - } - - BattlePassMission mission = this.loadMissionById(id); - - if (mission.getData() == null) { - this.getMissions().remove(mission.getId()); - continue; - } - - // Take reward - if (mission.getStatus() == BattlePassMissionStatus.MISSION_STATUS_FINISHED) { - this.addPointsDirectly(mission.getData().getAddPoint(), mission.getData().isCycleRefresh()); - mission.setStatus(BattlePassMissionStatus.MISSION_STATUS_POINT_TAKEN); - - updatedMissions.add(mission); - } - } - - if (updatedMissions.size() > 0) { - // Save to db - this.save(); - - // Packet - getPlayer().sendPacket(new PacketBattlePassMissionUpdateNotify(updatedMissions)); - getPlayer().sendPacket(new PacketBattlePassCurScheduleUpdateNotify(getPlayer())); - } - } + public boolean hasMission(int id) { + return getMissions().containsKey(id); + } - private void takeRewardsFromSelectChest(ItemData rewardItemData, int index, ItemParamData entry, List rewardItems) { - // Sanity checks. - if (rewardItemData.getItemUse().size() < 1) { - return; - } + public boolean isPaid() { + // ToDo: Change this when we actually support unlocking "paid" BP. + return true; + } - // Get possible item choices. - String[] choices = rewardItemData.getItemUse().get(0).getUseParam().get(0).split(","); - if (choices.length < index) { - return; - } + public Map getTakenRewards() { + if (this.takenRewards == null) this.takenRewards = new HashMap<>(); + return this.takenRewards; + } - // Get data for the selected item. - // This depends on the type of chest. - int chosenId = Integer.parseInt(choices[index - 1]); + // Mission triggers + public void triggerMission(WatcherTriggerType triggerType) { + getPlayer().getServer().getBattlePassSystem().triggerMission(getPlayer(), triggerType); + } - // For ITEM_USE_ADD_SELECT_ITEM chests, we can directly add the item specified in the chest's data. - if (rewardItemData.getItemUse().get(0).getUseOp().equals("ITEM_USE_ADD_SELECT_ITEM")) { - GameItem rewardItem = new GameItem(GameData.getItemDataMap().get(chosenId), entry.getItemCount()); - rewardItems.add(rewardItem); - } - // For ITEM_USE_GRANT_SELECT_REWARD chests, we have to again look up reward data. - else if (rewardItemData.getItemUse().get(0).getUseOp().equals("ITEM_USE_GRANT_SELECT_REWARD")) { - RewardData selectedReward = GameData.getRewardDataMap().get(chosenId); + public void triggerMission(WatcherTriggerType triggerType, int param, int progress) { + getPlayer().getServer().getBattlePassSystem().triggerMission(getPlayer(), triggerType, param, progress); + } - for (var r : selectedReward.getRewardItemList()) { - GameItem rewardItem = new GameItem(GameData.getItemDataMap().get(r.getItemId()), r.getItemCount()); - rewardItems.add(rewardItem); - } - } - else { - Grasscutter.getLogger().error("Invalid chest type for BP reward."); - } - } - - public void takeReward(List takeOptionList) { - List rewardList = new ArrayList<>(); - - for (BattlePassRewardTakeOption option : takeOptionList) { - // Duplicate check - if (option.getTag().getRewardId() == 0 || getTakenRewards().containsKey(option.getTag().getRewardId())) { - continue; - } - - // Level check - if (option.getTag().getLevel() > this.getLevel()) { - continue; - } - - BattlePassRewardData rewardData = GameData.getBattlePassRewardDataMap().get(GameConstants.BATTLE_PASS_CURRENT_INDEX * 100 + option.getTag().getLevel()); - - // Sanity check with excel data - if (rewardData.getFreeRewardIdList().contains(option.getTag().getRewardId())) { - rewardList.add(option); - } else if (this.isPaid() && rewardData.getPaidRewardIdList().contains(option.getTag().getRewardId())) { - rewardList.add(option); - } - else { - Grasscutter.getLogger().info("Not in rewards list: {}", option.getTag().getRewardId()); - } - } - - // Get rewards - List rewardItems = null; - - if (rewardList.size() > 0) { + // Handlers + public void takeMissionPoint(List missionIdList) { + // Obvious exploit check + if (missionIdList.size() > GameData.getBattlePassMissionDataMap().size()) { + return; + } - rewardItems = new ArrayList<>(); - - for (var option : rewardList) { - var tag = option.getTag(); - int index = option.getOptionIdx(); + List updatedMissions = new ArrayList<>(missionIdList.size()); - // Make sure we have reward data. - RewardData reward = GameData.getRewardDataMap().get(tag.getRewardId()); - if (reward == null) { - continue; - } - - // Add reward items. - for (var entry : reward.getRewardItemList()) { - ItemData rewardItemData = GameData.getItemDataMap().get(entry.getItemId()); + for (int id : missionIdList) { + // Skip if we dont have this mission + if (!this.hasMission(id)) { + continue; + } - // Some rewards are chests where the user can select the item they want. - if (rewardItemData.getMaterialType() == MaterialType.MATERIAL_SELECTABLE_CHEST) { - this.takeRewardsFromSelectChest(rewardItemData, index, entry, rewardItems); - } - // All other rewards directly give us the right item. - else { - GameItem rewardItem = new GameItem(rewardItemData, entry.getItemCount()); - rewardItems.add(rewardItem); - } - } + BattlePassMission mission = this.loadMissionById(id); - // Construct the reward and set as taken. - BattlePassReward bpReward = new BattlePassReward(tag.getLevel(), tag.getRewardId(), tag.getUnlockStatus() == BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_PAID); - this.getTakenRewards().put(bpReward.getRewardId(), bpReward); - } - - // Save to db - this.save(); - - // Add items and send battle pass schedule packet - getPlayer().getInventory().addItems(rewardItems); - getPlayer().sendPacket(new PacketBattlePassCurScheduleUpdateNotify(getPlayer())); - } - - getPlayer().sendPacket(new PacketTakeBattlePassRewardRsp(takeOptionList, rewardItems)); - } - - public int buyLevels(int buyLevel) { - int boughtLevels = Math.min(buyLevel, GameConstants.BATTLE_PASS_MAX_LEVEL - buyLevel); - - if (boughtLevels > 0) { - int price = GameConstants.BATTLE_PASS_LEVEL_PRICE * boughtLevels; - - if (getPlayer().getPrimogems() < price) { - return 0; - } - - this.level += boughtLevels; - this.save(); - - getPlayer().sendPacket(new PacketBattlePassCurScheduleUpdateNotify(getPlayer())); - } - - return boughtLevels; - } - - public void resetDailyMissions() { - var resetMissions = new ArrayList(); + if (mission.getData() == null) { + this.getMissions().remove(mission.getId()); + continue; + } - for (var mission : this.missions.values()) { - if (mission.getData().getRefreshType() == null || mission.getData().getRefreshType() == BattlePassMissionRefreshType.BATTLE_PASS_MISSION_REFRESH_DAILY) { - mission.setStatus(BattlePassMissionStatus.MISSION_STATUS_UNFINISHED); - mission.setProgress(0); + // Take reward + if (mission.getStatus() == BattlePassMissionStatus.MISSION_STATUS_FINISHED) { + this.addPointsDirectly(mission.getData().getAddPoint(), mission.getData().isCycleRefresh()); + mission.setStatus(BattlePassMissionStatus.MISSION_STATUS_POINT_TAKEN); - resetMissions.add(mission); - } - } + updatedMissions.add(mission); + } + } - this.getPlayer().sendPacket(new PacketBattlePassMissionUpdateNotify(resetMissions)); - this.getPlayer().sendPacket(new PacketBattlePassCurScheduleUpdateNotify(this.getPlayer())); - } - - public void resetWeeklyMissions() { - var resetMissions = new ArrayList(); + if (updatedMissions.size() > 0) { + // Save to db + this.save(); - for (var mission : this.missions.values()) { - if (mission.getData().getRefreshType() == BattlePassMissionRefreshType.BATTLE_PASS_MISSION_REFRESH_CYCLE_CROSS_SCHEDULE) { - mission.setStatus(BattlePassMissionStatus.MISSION_STATUS_UNFINISHED); - mission.setProgress(0); + // Packet + getPlayer().sendPacket(new PacketBattlePassMissionUpdateNotify(updatedMissions)); + getPlayer().sendPacket(new PacketBattlePassCurScheduleUpdateNotify(getPlayer())); + } + } - resetMissions.add(mission); - } - } + private void takeRewardsFromSelectChest(ItemData rewardItemData, int index, ItemParamData entry, List rewardItems) { + // Sanity checks. + if (rewardItemData.getItemUse().size() < 1) { + return; + } - this.getPlayer().sendPacket(new PacketBattlePassMissionUpdateNotify(resetMissions)); - this.getPlayer().sendPacket(new PacketBattlePassCurScheduleUpdateNotify(this.getPlayer())); - } - - // - public BattlePassSchedule getScheduleProto() { - var currentDate = LocalDate.now(); - var nextSundayDate = (currentDate.getDayOfWeek() == DayOfWeek.SUNDAY) - ? currentDate - : LocalDate.now().with(TemporalAdjusters.next(DayOfWeek.SUNDAY)); - var nextSundayTime = LocalDateTime.of(nextSundayDate.getYear(), nextSundayDate.getMonthValue(), nextSundayDate.getDayOfMonth(), 23, 59, 59); - - BattlePassSchedule.Builder schedule = BattlePassSchedule.newBuilder() + // Get possible item choices. + String[] choices = rewardItemData.getItemUse().get(0).getUseParam().get(0).split(","); + if (choices.length < index) { + return; + } + + // Get data for the selected item. + // This depends on the type of chest. + int chosenId = Integer.parseInt(choices[index - 1]); + + // For ITEM_USE_ADD_SELECT_ITEM chests, we can directly add the item specified in the chest's data. + if (rewardItemData.getItemUse().get(0).getUseOp().equals("ITEM_USE_ADD_SELECT_ITEM")) { + GameItem rewardItem = new GameItem(GameData.getItemDataMap().get(chosenId), entry.getItemCount()); + rewardItems.add(rewardItem); + } + // For ITEM_USE_GRANT_SELECT_REWARD chests, we have to again look up reward data. + else if (rewardItemData.getItemUse().get(0).getUseOp().equals("ITEM_USE_GRANT_SELECT_REWARD")) { + RewardData selectedReward = GameData.getRewardDataMap().get(chosenId); + + for (var r : selectedReward.getRewardItemList()) { + GameItem rewardItem = new GameItem(GameData.getItemDataMap().get(r.getItemId()), r.getItemCount()); + rewardItems.add(rewardItem); + } + } + else { + Grasscutter.getLogger().error("Invalid chest type for BP reward."); + } + } + + public void takeReward(List takeOptionList) { + List rewardList = new ArrayList<>(); + + for (BattlePassRewardTakeOption option : takeOptionList) { + // Duplicate check + if (option.getTag().getRewardId() == 0 || getTakenRewards().containsKey(option.getTag().getRewardId())) { + continue; + } + + // Level check + if (option.getTag().getLevel() > this.getLevel()) { + continue; + } + + BattlePassRewardData rewardData = GameData.getBattlePassRewardDataMap().get(GameConstants.BATTLE_PASS_CURRENT_INDEX * 100 + option.getTag().getLevel()); + + // Sanity check with excel data + if (rewardData.getFreeRewardIdList().contains(option.getTag().getRewardId())) { + rewardList.add(option); + } else if (this.isPaid() && rewardData.getPaidRewardIdList().contains(option.getTag().getRewardId())) { + rewardList.add(option); + } + else { + Grasscutter.getLogger().info("Not in rewards list: {}", option.getTag().getRewardId()); + } + } + + // Get rewards + List rewardItems = null; + + if (rewardList.size() > 0) { + + rewardItems = new ArrayList<>(); + + for (var option : rewardList) { + var tag = option.getTag(); + int index = option.getOptionIdx(); + + // Make sure we have reward data. + RewardData reward = GameData.getRewardDataMap().get(tag.getRewardId()); + if (reward == null) { + continue; + } + + // Add reward items. + for (var entry : reward.getRewardItemList()) { + ItemData rewardItemData = GameData.getItemDataMap().get(entry.getItemId()); + + // Some rewards are chests where the user can select the item they want. + if (rewardItemData.getMaterialType() == MaterialType.MATERIAL_SELECTABLE_CHEST) { + this.takeRewardsFromSelectChest(rewardItemData, index, entry, rewardItems); + } + // All other rewards directly give us the right item. + else { + GameItem rewardItem = new GameItem(rewardItemData, entry.getItemCount()); + rewardItems.add(rewardItem); + } + } + + // Construct the reward and set as taken. + BattlePassReward bpReward = new BattlePassReward(tag.getLevel(), tag.getRewardId(), tag.getUnlockStatus() == BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_PAID); + this.getTakenRewards().put(bpReward.getRewardId(), bpReward); + } + + // Save to db + this.save(); + + // Add items and send battle pass schedule packet + getPlayer().getInventory().addItems(rewardItems); + getPlayer().sendPacket(new PacketBattlePassCurScheduleUpdateNotify(getPlayer())); + } + + getPlayer().sendPacket(new PacketTakeBattlePassRewardRsp(takeOptionList, rewardItems)); + } + + public int buyLevels(int buyLevel) { + int boughtLevels = Math.min(buyLevel, GameConstants.BATTLE_PASS_MAX_LEVEL - buyLevel); + + if (boughtLevels > 0) { + int price = GameConstants.BATTLE_PASS_LEVEL_PRICE * boughtLevels; + + if (getPlayer().getPrimogems() < price) { + return 0; + } + + this.level += boughtLevels; + this.save(); + + getPlayer().sendPacket(new PacketBattlePassCurScheduleUpdateNotify(getPlayer())); + } + + return boughtLevels; + } + + public void resetDailyMissions() { + var resetMissions = new ArrayList(); + + for (var mission : this.missions.values()) { + if (mission.getData().getRefreshType() == null || mission.getData().getRefreshType() == BattlePassMissionRefreshType.BATTLE_PASS_MISSION_REFRESH_DAILY) { + mission.setStatus(BattlePassMissionStatus.MISSION_STATUS_UNFINISHED); + mission.setProgress(0); + + resetMissions.add(mission); + } + } + + this.getPlayer().sendPacket(new PacketBattlePassMissionUpdateNotify(resetMissions)); + this.getPlayer().sendPacket(new PacketBattlePassCurScheduleUpdateNotify(this.getPlayer())); + } + + public void resetWeeklyMissions() { + var resetMissions = new ArrayList(); + + for (var mission : this.missions.values()) { + if (mission.getData().getRefreshType() == BattlePassMissionRefreshType.BATTLE_PASS_MISSION_REFRESH_CYCLE_CROSS_SCHEDULE) { + mission.setStatus(BattlePassMissionStatus.MISSION_STATUS_UNFINISHED); + mission.setProgress(0); + + resetMissions.add(mission); + } + } + + this.getPlayer().sendPacket(new PacketBattlePassMissionUpdateNotify(resetMissions)); + this.getPlayer().sendPacket(new PacketBattlePassCurScheduleUpdateNotify(this.getPlayer())); + } + + // + public BattlePassSchedule getScheduleProto() { + var currentDate = LocalDate.now(); + var nextSundayDate = (currentDate.getDayOfWeek() == DayOfWeek.SUNDAY) + ? currentDate + : LocalDate.now().with(TemporalAdjusters.next(DayOfWeek.SUNDAY)); + var nextSundayTime = LocalDateTime.of(nextSundayDate.getYear(), nextSundayDate.getMonthValue(), nextSundayDate.getDayOfMonth(), 23, 59, 59); + + BattlePassSchedule.Builder schedule = BattlePassSchedule.newBuilder() .setScheduleId(2700) .setLevel(this.getLevel()) .setPoint(this.getPoint()) @@ -366,21 +366,21 @@ public class BattlePassManager extends BasePlayerDataManager { .setIsViewed(this.isViewed()) .setUnlockStatus(this.isPaid() ? BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_PAID : BattlePassUnlockStatus.BATTLE_PASS_UNLOCK_STATUS_FREE) .setJPFMGBEBBBJ(2) // Not bought on Playstation. - .setCurCyclePoints(this.getCyclePoints()) + .setCurCyclePoints(this.getCyclePoints()) .setCurCycle(BattlePassCycle.newBuilder() - .setBeginTime(0) - .setEndTime((int)nextSundayTime.atZone(ZoneId.systemDefault()).toEpochSecond()) - .setCycleIdx(3) - ); - - for (BattlePassReward reward : getTakenRewards().values()) { - schedule.addRewardTakenList(reward.toProto()); - } - - return schedule.build(); - } - + .setBeginTime(0) + .setEndTime((int)nextSundayTime.atZone(ZoneId.systemDefault()).toEpochSecond()) + .setCycleIdx(3) + ); + + for (BattlePassReward reward : getTakenRewards().values()) { + schedule.addRewardTakenList(reward.toProto()); + } + + return schedule.build(); + } + public void save() { - DatabaseHelper.saveBattlePass(this); + DatabaseHelper.saveBattlePass(this); } } diff --git a/src/main/java/emu/grasscutter/game/battlepass/BattlePassSystem.java b/src/main/java/emu/grasscutter/game/battlepass/BattlePassSystem.java index 240bcb473..c89fc09fa 100644 --- a/src/main/java/emu/grasscutter/game/battlepass/BattlePassSystem.java +++ b/src/main/java/emu/grasscutter/game/battlepass/BattlePassSystem.java @@ -16,64 +16,64 @@ import emu.grasscutter.server.game.GameServer; import emu.grasscutter.server.packet.send.PacketBattlePassMissionUpdateNotify; public class BattlePassSystem extends BaseGameSystem { - private final Map> cachedTriggers; - - // BP Mission manager for the server, contains cached triggers so we dont have to load it for each player - public BattlePassSystem(GameServer server) { - super(server); - - this.cachedTriggers = new HashMap<>(); - - for (BattlePassMissionData missionData : GameData.getBattlePassMissionDataMap().values()) { - if (missionData.isValidRefreshType()) { - List triggerList = getTriggers().computeIfAbsent(missionData.getTriggerType(), e -> new ArrayList<>()); - triggerList.add(missionData); - } - } - } + private final Map> cachedTriggers; - public GameServer getServer() { - return server; - } - - private Map> getTriggers() { - return cachedTriggers; - } - - public void triggerMission(Player player, WatcherTriggerType triggerType) { - triggerMission(player, triggerType, 0, 1); - } + // BP Mission manager for the server, contains cached triggers so we dont have to load it for each player + public BattlePassSystem(GameServer server) { + super(server); - public void triggerMission(Player player, WatcherTriggerType triggerType, int param, int progress) { - List triggerList = getTriggers().get(triggerType); - - if (triggerList == null || triggerList.isEmpty()) return; - - for (BattlePassMissionData data : triggerList) { - // Skip params check if param == 0 - if (param != 0) { - if (!data.getMainParams().contains(param)) { - continue; - } - } - - // Get mission from player, if it doesnt exist, then we make one - BattlePassMission mission = player.getBattlePassManager().loadMissionById(data.getId()); - - if (mission.isFinshed()) continue; + this.cachedTriggers = new HashMap<>(); - // Add progress - mission.addProgress(progress, data.getProgress()); - - if (mission.getProgress() >= data.getProgress()) { - mission.setStatus(BattlePassMissionStatus.MISSION_STATUS_FINISHED); - } - - // Save to db - player.getBattlePassManager().save(); - - // Packet - player.sendPacket(new PacketBattlePassMissionUpdateNotify(mission)); - } - } + for (BattlePassMissionData missionData : GameData.getBattlePassMissionDataMap().values()) { + if (missionData.isValidRefreshType()) { + List triggerList = getTriggers().computeIfAbsent(missionData.getTriggerType(), e -> new ArrayList<>()); + triggerList.add(missionData); + } + } + } + + public GameServer getServer() { + return server; + } + + private Map> getTriggers() { + return cachedTriggers; + } + + public void triggerMission(Player player, WatcherTriggerType triggerType) { + triggerMission(player, triggerType, 0, 1); + } + + public void triggerMission(Player player, WatcherTriggerType triggerType, int param, int progress) { + List triggerList = getTriggers().get(triggerType); + + if (triggerList == null || triggerList.isEmpty()) return; + + for (BattlePassMissionData data : triggerList) { + // Skip params check if param == 0 + if (param != 0) { + if (!data.getMainParams().contains(param)) { + continue; + } + } + + // Get mission from player, if it doesnt exist, then we make one + BattlePassMission mission = player.getBattlePassManager().loadMissionById(data.getId()); + + if (mission.isFinshed()) continue; + + // Add progress + mission.addProgress(progress, data.getProgress()); + + if (mission.getProgress() >= data.getProgress()) { + mission.setStatus(BattlePassMissionStatus.MISSION_STATUS_FINISHED); + } + + // Save to db + player.getBattlePassManager().save(); + + // Packet + player.sendPacket(new PacketBattlePassMissionUpdateNotify(mission)); + } + } } diff --git a/src/main/java/emu/grasscutter/game/combine/CombineManger.java b/src/main/java/emu/grasscutter/game/combine/CombineManger.java index 0ec9750dc..90920abd1 100644 --- a/src/main/java/emu/grasscutter/game/combine/CombineManger.java +++ b/src/main/java/emu/grasscutter/game/combine/CombineManger.java @@ -31,59 +31,59 @@ import java.util.List; import com.google.gson.reflect.TypeToken; public class CombineManger extends BaseGameSystem { - private final static Int2ObjectMap> reliquaryDecomposeData = new Int2ObjectOpenHashMap<>(); + private final static Int2ObjectMap> reliquaryDecomposeData = new Int2ObjectOpenHashMap<>(); public CombineManger(GameServer server) { super(server); } public static void initialize() { - // Read the data we need for strongbox. - try (Reader fileReader = DataLoader.loadReader("ReliquaryDecompose.json")) { - List decomposeEntries = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, ReliquaryDecomposeEntry.class).getType()); + // Read the data we need for strongbox. + try (Reader fileReader = DataLoader.loadReader("ReliquaryDecompose.json")) { + List decomposeEntries = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, ReliquaryDecomposeEntry.class).getType()); - for (ReliquaryDecomposeEntry entry : decomposeEntries) { - reliquaryDecomposeData.put(entry.getConfigId(), entry.getItems()); - } + for (ReliquaryDecomposeEntry entry : decomposeEntries) { + reliquaryDecomposeData.put(entry.getConfigId(), entry.getItems()); + } - Grasscutter.getLogger().debug("Loaded {} reliquary decompose entries.", reliquaryDecomposeData.size()); - } - catch (Exception ex) { - Grasscutter.getLogger().error("Unable to load reliquary decompose data.", ex); - } - } + Grasscutter.getLogger().debug("Loaded {} reliquary decompose entries.", reliquaryDecomposeData.size()); + } + catch (Exception ex) { + Grasscutter.getLogger().error("Unable to load reliquary decompose data.", ex); + } + } public boolean unlockCombineDiagram(Player player, GameItem diagramItem) { - // Make sure this is actually a diagram. - if (!diagramItem.getItemData().getItemUse().get(0).getUseOp().equals("ITEM_USE_UNLOCK_COMBINE")) { - return false; - } + // Make sure this is actually a diagram. + if (!diagramItem.getItemData().getItemUse().get(0).getUseOp().equals("ITEM_USE_UNLOCK_COMBINE")) { + return false; + } - // Determine the combine item we should unlock. - int combineId = Integer.parseInt(diagramItem.getItemData().getItemUse().get(0).getUseParam().get(0)); + // Determine the combine item we should unlock. + int combineId = Integer.parseInt(diagramItem.getItemData().getItemUse().get(0).getUseParam().get(0)); - // Remove the diagram from the player's inventory. - // We need to do this here, before sending CombineFormulaDataNotify, or the the combine UI won't correctly - // update when unlocking the diagram. - player.getInventory().removeItem(diagramItem, 1); + // Remove the diagram from the player's inventory. + // We need to do this here, before sending CombineFormulaDataNotify, or the the combine UI won't correctly + // update when unlocking the diagram. + player.getInventory().removeItem(diagramItem, 1); - // Tell the client that this diagram is now unlocked and add the unlocked item to the player. - player.getUnlockedCombines().add(combineId); - player.sendPacket(new PacketCombineFormulaDataNotify(combineId)); + // Tell the client that this diagram is now unlocked and add the unlocked item to the player. + player.getUnlockedCombines().add(combineId); + player.sendPacket(new PacketCombineFormulaDataNotify(combineId)); - return true; - } + return true; + } - public CombineResult combineItem(Player player, int cid, int count){ + public CombineResult combineItem(Player player, int cid, int count) { // check config exist - if(!GameData.getCombineDataMap().containsKey(cid)){ + if (!GameData.getCombineDataMap().containsKey(cid)) { player.getWorld().getHost().sendPacket(new PacketCombineRsp()); return null; } CombineData combineData = GameData.getCombineDataMap().get(cid); - if(combineData.getPlayerLevel() > player.getLevel()){ + if (combineData.getPlayerLevel() > player.getLevel()) { return null; } @@ -120,7 +120,7 @@ public class CombineManger extends BaseGameSystem { player.sendPacket(new PacketReliquaryDecomposeRsp(Retcode.RET_RELIQUARY_DECOMPOSE_PARAM_ERROR)); return; } - + // Check if the number of input items matches the output count. if (input.size() != count * 3) { player.sendPacket(new PacketReliquaryDecomposeRsp(Retcode.RET_RELIQUARY_DECOMPOSE_PARAM_ERROR)); @@ -144,7 +144,7 @@ public class CombineManger extends BaseGameSystem { List resultItems = new ArrayList<>(); for (int i = 0; i < count; i++) { int itemId = Utils.drawRandomListElement(possibleDrops); - GameItem newReliquary = new GameItem(itemId, 1); + GameItem newReliquary = new GameItem(itemId, 1); player.getInventory().addItem(newReliquary); resultItems.add(newReliquary.getGuid()); diff --git a/src/main/java/emu/grasscutter/game/drop/DropSystem.java b/src/main/java/emu/grasscutter/game/drop/DropSystem.java index 2917df436..b2b28852a 100644 --- a/src/main/java/emu/grasscutter/game/drop/DropSystem.java +++ b/src/main/java/emu/grasscutter/game/drop/DropSystem.java @@ -32,7 +32,7 @@ public class DropSystem extends BaseGameSystem { this.dropData = new Int2ObjectOpenHashMap<>(); this.load(); } - + public Int2ObjectMap> getDropData() { return dropData; } @@ -41,7 +41,7 @@ public class DropSystem extends BaseGameSystem { try (Reader fileReader = DataLoader.loadReader("Drop.json")) { getDropData().clear(); List banners = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, DropInfo.class).getType()); - if(banners.size() > 0) { + if (banners.size() > 0) { for (DropInfo di : banners) { getDropData().put(di.getMonsterId(), di.getDropDataList()); } diff --git a/src/main/java/emu/grasscutter/game/dungeons/DungeonSystem.java b/src/main/java/emu/grasscutter/game/dungeons/DungeonSystem.java index 7ed773baa..a0b0978be 100644 --- a/src/main/java/emu/grasscutter/game/dungeons/DungeonSystem.java +++ b/src/main/java/emu/grasscutter/game/dungeons/DungeonSystem.java @@ -20,95 +20,95 @@ import emu.grasscutter.utils.Position; import java.util.List; public class DungeonSystem extends BaseGameSystem { - private static final BasicDungeonSettleListener basicDungeonSettleObserver = new BasicDungeonSettleListener(); - - public DungeonSystem(GameServer server) { - super(server); - } + private static final BasicDungeonSettleListener basicDungeonSettleObserver = new BasicDungeonSettleListener(); - public void getEntryInfo(Player player, int pointId) { - ScenePointEntry entry = GameData.getScenePointEntryById(player.getScene().getId(), pointId); - - if (entry == null) { - // Error - player.sendPacket(new PacketDungeonEntryInfoRsp()); - return; - } - - player.sendPacket(new PacketDungeonEntryInfoRsp(player, entry.getPointData())); - } + public DungeonSystem(GameServer server) { + super(server); + } - public boolean enterDungeon(Player player, int pointId, int dungeonId) { - DungeonData data = GameData.getDungeonDataMap().get(dungeonId); - - if (data == null) { - return false; - } - Grasscutter.getLogger().info("{}({}) is trying to enter dungeon {}" ,player.getNickname(),player.getUid(),dungeonId); - - int sceneId = data.getSceneId(); - player.getScene().setPrevScene(sceneId); - - if (player.getWorld().transferPlayerToScene(player, sceneId, data)) { - player.getScene().addDungeonSettleObserver(basicDungeonSettleObserver); - player.getQuestManager().triggerEvent(QuestTrigger.QUEST_CONTENT_ENTER_DUNGEON, data.getId()); - } - - player.getScene().setPrevScenePoint(pointId); - player.sendPacket(new PacketPlayerEnterDungeonRsp(pointId, dungeonId)); - return true; - } + public void getEntryInfo(Player player, int pointId) { + ScenePointEntry entry = GameData.getScenePointEntryById(player.getScene().getId(), pointId); - /** - * used in tower dungeons handoff - */ - public boolean handoffDungeon(Player player, int dungeonId, List dungeonSettleListeners) { - DungeonData data = GameData.getDungeonDataMap().get(dungeonId); + if (entry == null) { + // Error + player.sendPacket(new PacketDungeonEntryInfoRsp()); + return; + } - if (data == null) { - return false; - } - Grasscutter.getLogger().info("{}({}) is trying to enter tower dungeon {}" ,player.getNickname(),player.getUid(),dungeonId); + player.sendPacket(new PacketDungeonEntryInfoRsp(player, entry.getPointData())); + } - if(player.getWorld().transferPlayerToScene(player, data.getSceneId(), data)){ - dungeonSettleListeners.forEach(player.getScene()::addDungeonSettleObserver); - } - return true; - } + public boolean enterDungeon(Player player, int pointId, int dungeonId) { + DungeonData data = GameData.getDungeonDataMap().get(dungeonId); - public void exitDungeon(Player player) { - Scene scene = player.getScene(); - - if (scene==null || scene.getSceneType() != SceneType.SCENE_DUNGEON) { - return; - } - - // Get previous scene - int prevScene = scene.getPrevScene() > 0 ? scene.getPrevScene() : 3; - - // Get previous position - DungeonData dungeonData = scene.getDungeonData(); - Position prevPos = new Position(GameConstants.START_POSITION); - - if (dungeonData != null) { - ScenePointEntry entry = GameData.getScenePointEntryById(prevScene, scene.getPrevScenePoint()); - - if (entry != null) { - prevPos.set(entry.getPointData().getTranPos()); - } - } - // clean temp team if it has - player.getTeamManager().cleanTemporaryTeam(); - player.getTowerManager().clearEntry(); + if (data == null) { + return false; + } + Grasscutter.getLogger().info("{}({}) is trying to enter dungeon {}" ,player.getNickname(),player.getUid(),dungeonId); - // Transfer player back to world - player.getWorld().transferPlayerToScene(player, prevScene, prevPos); - player.sendPacket(new BasePacket(PacketOpcodes.PlayerQuitDungeonRsp)); - } - - public void updateDailyDungeons() { - for (ScenePointEntry entry : GameData.getScenePointEntries().values()) { - entry.getPointData().updateDailyDungeon(); - } - } + int sceneId = data.getSceneId(); + player.getScene().setPrevScene(sceneId); + + if (player.getWorld().transferPlayerToScene(player, sceneId, data)) { + player.getScene().addDungeonSettleObserver(basicDungeonSettleObserver); + player.getQuestManager().triggerEvent(QuestTrigger.QUEST_CONTENT_ENTER_DUNGEON, data.getId()); + } + + player.getScene().setPrevScenePoint(pointId); + player.sendPacket(new PacketPlayerEnterDungeonRsp(pointId, dungeonId)); + return true; + } + + /** + * used in tower dungeons handoff + */ + public boolean handoffDungeon(Player player, int dungeonId, List dungeonSettleListeners) { + DungeonData data = GameData.getDungeonDataMap().get(dungeonId); + + if (data == null) { + return false; + } + Grasscutter.getLogger().info("{}({}) is trying to enter tower dungeon {}" ,player.getNickname(),player.getUid(),dungeonId); + + if (player.getWorld().transferPlayerToScene(player, data.getSceneId(), data)) { + dungeonSettleListeners.forEach(player.getScene()::addDungeonSettleObserver); + } + return true; + } + + public void exitDungeon(Player player) { + Scene scene = player.getScene(); + + if (scene==null || scene.getSceneType() != SceneType.SCENE_DUNGEON) { + return; + } + + // Get previous scene + int prevScene = scene.getPrevScene() > 0 ? scene.getPrevScene() : 3; + + // Get previous position + DungeonData dungeonData = scene.getDungeonData(); + Position prevPos = new Position(GameConstants.START_POSITION); + + if (dungeonData != null) { + ScenePointEntry entry = GameData.getScenePointEntryById(prevScene, scene.getPrevScenePoint()); + + if (entry != null) { + prevPos.set(entry.getPointData().getTranPos()); + } + } + // clean temp team if it has + player.getTeamManager().cleanTemporaryTeam(); + player.getTowerManager().clearEntry(); + + // Transfer player back to world + player.getWorld().transferPlayerToScene(player, prevScene, prevPos); + player.sendPacket(new BasePacket(PacketOpcodes.PlayerQuitDungeonRsp)); + } + + public void updateDailyDungeons() { + for (ScenePointEntry entry : GameData.getScenePointEntries().values()) { + entry.getPointData().updateDailyDungeon(); + } + } } diff --git a/src/main/java/emu/grasscutter/game/dungeons/challenge/DungeonChallenge.java b/src/main/java/emu/grasscutter/game/dungeons/challenge/DungeonChallenge.java index 5093b8665..844f23c5c 100644 --- a/src/main/java/emu/grasscutter/game/dungeons/challenge/DungeonChallenge.java +++ b/src/main/java/emu/grasscutter/game/dungeons/challenge/DungeonChallenge.java @@ -36,180 +36,180 @@ import com.google.gson.reflect.TypeToken; public class DungeonChallenge extends WorldChallenge { - /** - * has more challenge - */ - private boolean stage; - private IntSet rewardedPlayers; + /** + * has more challenge + */ + private boolean stage; + private IntSet rewardedPlayers; - private final static Int2ObjectMap> dungeonDropData = new Int2ObjectOpenHashMap<>(); + private final static Int2ObjectMap> dungeonDropData = new Int2ObjectOpenHashMap<>(); - public static void initialize() { - // Read the data we need for dungeon rewards drops. - try (Reader fileReader = DataLoader.loadReader("DungeonDrop.json")) { - List dungeonDropList = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, DungeonDrop.class).getType()); + public static void initialize() { + // Read the data we need for dungeon rewards drops. + try (Reader fileReader = DataLoader.loadReader("DungeonDrop.json")) { + List dungeonDropList = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, DungeonDrop.class).getType()); - for (DungeonDrop entry : dungeonDropList) { - dungeonDropData.put(entry.getDungeonId(), entry.getDrops()); - } + for (DungeonDrop entry : dungeonDropList) { + dungeonDropData.put(entry.getDungeonId(), entry.getDrops()); + } - Grasscutter.getLogger().debug("Loaded {} dungeon drop data entries.", dungeonDropData.size()); - } - catch (Exception ex) { - Grasscutter.getLogger().error("Unable to load dungeon drop data.", ex); - } - } + Grasscutter.getLogger().debug("Loaded {} dungeon drop data entries.", dungeonDropData.size()); + } + catch (Exception ex) { + Grasscutter.getLogger().error("Unable to load dungeon drop data.", ex); + } + } - public DungeonChallenge(Scene scene, SceneGroup group, - int challengeId, int challengeIndex, - List paramList, - int timeLimit, int goal, - List challengeTriggers) { - super(scene, group, challengeId, challengeIndex, paramList, timeLimit, goal, challengeTriggers); - this.setRewardedPlayers(new IntOpenHashSet()); - } + public DungeonChallenge(Scene scene, SceneGroup group, + int challengeId, int challengeIndex, + List paramList, + int timeLimit, int goal, + List challengeTriggers) { + super(scene, group, challengeId, challengeIndex, paramList, timeLimit, goal, challengeTriggers); + this.setRewardedPlayers(new IntOpenHashSet()); + } - public boolean isStage() { - return stage; - } + public boolean isStage() { + return stage; + } - public void setStage(boolean stage) { - this.stage = stage; - } + public void setStage(boolean stage) { + this.stage = stage; + } - public IntSet getRewardedPlayers() { - return rewardedPlayers; - } + public IntSet getRewardedPlayers() { + return rewardedPlayers; + } - public void setRewardedPlayers(IntSet rewardedPlayers) { - this.rewardedPlayers = rewardedPlayers; - } + public void setRewardedPlayers(IntSet rewardedPlayers) { + this.rewardedPlayers = rewardedPlayers; + } - @Override - public void done() { - super.done(); - if (this.isSuccess()) { - // Settle - settle(); - } - } + @Override + public void done() { + super.done(); + if (this.isSuccess()) { + // Settle + settle(); + } + } - private void settle() { - if(!stage){ - getScene().getDungeonSettleObservers().forEach(o -> o.onDungeonSettle(getScene())); - getScene().getScriptManager().callEvent(EventType.EVENT_DUNGEON_SETTLE, - new ScriptArgs(this.isSuccess() ? 1 : 0)); - // Battle pass trigger - this.getScene().getPlayers().forEach(p -> p.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_FINISH_DUNGEON)); - } - } + private void settle() { + if (!stage) { + getScene().getDungeonSettleObservers().forEach(o -> o.onDungeonSettle(getScene())); + getScene().getScriptManager().callEvent(EventType.EVENT_DUNGEON_SETTLE, + new ScriptArgs(this.isSuccess() ? 1 : 0)); + // Battle pass trigger + this.getScene().getPlayers().forEach(p -> p.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_FINISH_DUNGEON)); + } + } - private List rollRewards(boolean useCondensed) { - List rewards = new ArrayList<>(); - int dungeonId = this.getScene().getDungeonData().getId(); - // If we have specific drop data for this dungeon, we use it. - if (dungeonDropData.containsKey(dungeonId)) { - List dropEntries = dungeonDropData.get(dungeonId); + private List rollRewards(boolean useCondensed) { + List rewards = new ArrayList<>(); + int dungeonId = this.getScene().getDungeonData().getId(); + // If we have specific drop data for this dungeon, we use it. + if (dungeonDropData.containsKey(dungeonId)) { + List dropEntries = dungeonDropData.get(dungeonId); - // Roll for each drop group. - for (var entry : dropEntries) { - // Determine the number of drops we get for this entry. - int start = entry.getCounts().get(0); - int end = entry.getCounts().get(entry.getCounts().size() - 1); - var candidateAmounts = IntStream.range(start, end + 1).boxed().collect(Collectors.toList()); + // Roll for each drop group. + for (var entry : dropEntries) { + // Determine the number of drops we get for this entry. + int start = entry.getCounts().get(0); + int end = entry.getCounts().get(entry.getCounts().size() - 1); + var candidateAmounts = IntStream.range(start, end + 1).boxed().collect(Collectors.toList()); - int amount = Utils.drawRandomListElement(candidateAmounts, entry.getProbabilities()); + int amount = Utils.drawRandomListElement(candidateAmounts, entry.getProbabilities()); - if (useCondensed) { - amount += Utils.drawRandomListElement(candidateAmounts, entry.getProbabilities()); - } + if (useCondensed) { + amount += Utils.drawRandomListElement(candidateAmounts, entry.getProbabilities()); + } - // Double rewards in multiplay mode, if specified. - if (entry.isMpDouble() && this.getScene().getPlayerCount() > 1) { - amount *= 2; - } + // Double rewards in multiplay mode, if specified. + if (entry.isMpDouble() && this.getScene().getPlayerCount() > 1) { + amount *= 2; + } - // Roll items for this group. - // Here, we have to handle stacking, or the client will not display results correctly. - // For now, we use the following logic: If the possible drop item are a list of multiple items, - // we roll them separately. If not, we stack them. This should work out in practice, at least - // for the currently existing set of dungeons. - if (entry.getItems().size() == 1) { - rewards.add(new GameItem(entry.getItems().get(0), amount)); - } - else { - for (int i = 0; i < amount; i++) { - // int itemIndex = ThreadLocalRandom.current().nextInt(0, entry.getItems().size()); - // int itemId = entry.getItems().get(itemIndex); - int itemId = Utils.drawRandomListElement(entry.getItems(), entry.getItemProbabilities()); - rewards.add(new GameItem(itemId, 1)); - } - } - } - } - // Otherwise, we fall back to the preview data. - else { - Grasscutter.getLogger().info("No drop data found or dungeon {}, falling back to preview data ...", dungeonId); - for (ItemParamData param : getScene().getDungeonData().getRewardPreview().getPreviewItems()) { - rewards.add(new GameItem(param.getId(), Math.max(param.getCount(), 1))); - } - } + // Roll items for this group. + // Here, we have to handle stacking, or the client will not display results correctly. + // For now, we use the following logic: If the possible drop item are a list of multiple items, + // we roll them separately. If not, we stack them. This should work out in practice, at least + // for the currently existing set of dungeons. + if (entry.getItems().size() == 1) { + rewards.add(new GameItem(entry.getItems().get(0), amount)); + } + else { + for (int i = 0; i < amount; i++) { + // int itemIndex = ThreadLocalRandom.current().nextInt(0, entry.getItems().size()); + // int itemId = entry.getItems().get(itemIndex); + int itemId = Utils.drawRandomListElement(entry.getItems(), entry.getItemProbabilities()); + rewards.add(new GameItem(itemId, 1)); + } + } + } + } + // Otherwise, we fall back to the preview data. + else { + Grasscutter.getLogger().info("No drop data found or dungeon {}, falling back to preview data ...", dungeonId); + for (ItemParamData param : getScene().getDungeonData().getRewardPreview().getPreviewItems()) { + rewards.add(new GameItem(param.getId(), Math.max(param.getCount(), 1))); + } + } - return rewards; - } + return rewards; + } - public void getStatueDrops(Player player, GadgetInteractReq request) { - DungeonData dungeonData = getScene().getDungeonData(); - int resinCost = dungeonData.getStatueCostCount() != 0 ? dungeonData.getStatueCostCount() : 20; + public void getStatueDrops(Player player, GadgetInteractReq request) { + DungeonData dungeonData = getScene().getDungeonData(); + int resinCost = dungeonData.getStatueCostCount() != 0 ? dungeonData.getStatueCostCount() : 20; - if (!isSuccess() || dungeonData == null || dungeonData.getRewardPreview() == null || dungeonData.getRewardPreview().getPreviewItems().length == 0) { - return; - } + if (!isSuccess() || dungeonData == null || dungeonData.getRewardPreview() == null || dungeonData.getRewardPreview().getPreviewItems().length == 0) { + return; + } - // Already rewarded - if (getRewardedPlayers().contains(player.getUid())) { - return; - } + // Already rewarded + if (getRewardedPlayers().contains(player.getUid())) { + return; + } - // Get rewards. - List rewards = new ArrayList<>(); + // Get rewards. + List rewards = new ArrayList<>(); - if (request.getIsUseCondenseResin()) { - // Check if condensed resin is usable here. - // For this, we use the following logic for now: - // The normal resin cost of the dungeon has to be 20. - if (resinCost != 20) { - return; - } + if (request.getIsUseCondenseResin()) { + // Check if condensed resin is usable here. + // For this, we use the following logic for now: + // The normal resin cost of the dungeon has to be 20. + if (resinCost != 20) { + return; + } - // Make sure the player has condensed resin. - GameItem condensedResin = player.getInventory().getInventoryTab(ItemType.ITEM_MATERIAL).getItemById(220007); - if (condensedResin == null || condensedResin.getCount() <= 0) { - return; - } + // Make sure the player has condensed resin. + GameItem condensedResin = player.getInventory().getInventoryTab(ItemType.ITEM_MATERIAL).getItemById(220007); + if (condensedResin == null || condensedResin.getCount() <= 0) { + return; + } - // Deduct. - player.getInventory().removeItem(condensedResin, 1); + // Deduct. + player.getInventory().removeItem(condensedResin, 1); - // Roll rewards. - rewards.addAll(this.rollRewards(true)); - } - else { - // If the player used regular resin, try to deduct. - // Stop if insufficient resin. - boolean success = player.getResinManager().useResin(resinCost); - if (!success) { - return; - } + // Roll rewards. + rewards.addAll(this.rollRewards(true)); + } + else { + // If the player used regular resin, try to deduct. + // Stop if insufficient resin. + boolean success = player.getResinManager().useResin(resinCost); + if (!success) { + return; + } - // Roll rewards. - rewards.addAll(this.rollRewards(false)); - } + // Roll rewards. + rewards.addAll(this.rollRewards(false)); + } - // Add rewards to player and send notification. - player.getInventory().addItems(rewards, ActionReason.DungeonStatueDrop); - player.sendPacket(new PacketGadgetAutoPickDropInfoNotify(rewards)); + // Add rewards to player and send notification. + player.getInventory().addItems(rewards, ActionReason.DungeonStatueDrop); + player.sendPacket(new PacketGadgetAutoPickDropInfoNotify(rewards)); - getRewardedPlayers().add(player.getUid()); - } + getRewardedPlayers().add(player.getUid()); + } } diff --git a/src/main/java/emu/grasscutter/game/entity/EntityAvatar.java b/src/main/java/emu/grasscutter/game/entity/EntityAvatar.java index 63d94b866..431054d14 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityAvatar.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityAvatar.java @@ -40,278 +40,278 @@ import it.unimi.dsi.fastutil.ints.Int2FloatMap; import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap; public class EntityAvatar extends GameEntity { - private final Avatar avatar; - - private PlayerDieType killedType; - private int killedBy; - - public EntityAvatar(Scene scene, Avatar avatar) { - super(scene); - this.avatar = avatar; - this.avatar.setCurrentEnergy(); - this.id = getScene().getWorld().getNextEntityId(EntityIdType.AVATAR); - - GameItem weapon = this.getAvatar().getWeapon(); - if (weapon != null) { - weapon.setWeaponEntityId(getScene().getWorld().getNextEntityId(EntityIdType.WEAPON)); - } - } - - public EntityAvatar(Avatar avatar) { - super(null); - this.avatar = avatar; - this.avatar.setCurrentEnergy(); - } + private final Avatar avatar; - public Player getPlayer() { - return avatar.getPlayer(); - } + private PlayerDieType killedType; + private int killedBy; - @Override - public Position getPosition() { - return getPlayer().getPosition(); - } - - @Override - public Position getRotation() { - return getPlayer().getRotation(); - } + public EntityAvatar(Scene scene, Avatar avatar) { + super(scene); + this.avatar = avatar; + this.avatar.setCurrentEnergy(); + this.id = getScene().getWorld().getNextEntityId(EntityIdType.AVATAR); - public Avatar getAvatar() { - return avatar; - } - - public int getKilledBy() { - return killedBy; - } - - public PlayerDieType getKilledType() { - return killedType; - } + GameItem weapon = this.getAvatar().getWeapon(); + if (weapon != null) { + weapon.setWeaponEntityId(getScene().getWorld().getNextEntityId(EntityIdType.WEAPON)); + } + } - @Override - public boolean isAlive() { - return this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) > 0f; - } - - @Override - public Int2FloatOpenHashMap getFightProperties() { - return getAvatar().getFightProperties(); - } - - public int getWeaponEntityId() { - if (getAvatar().getWeapon() != null) { - return getAvatar().getWeapon().getWeaponEntityId(); - } - return 0; - } + public EntityAvatar(Avatar avatar) { + super(null); + this.avatar = avatar; + this.avatar.setCurrentEnergy(); + } - @Override - public void onDeath(int killerId) { - this.killedType = PlayerDieType.PLAYER_DIE_TYPE_KILL_BY_MONSTER; - this.killedBy = killerId; - clearEnergy(ChangeEnergyReason.CHANGE_ENERGY_REASON_NONE); - } + public Player getPlayer() { + return avatar.getPlayer(); + } - public void onDeath(PlayerDieType dieType, int killerId) { - this.killedType = dieType; - this.killedBy = killerId; - clearEnergy(ChangeEnergyReason.CHANGE_ENERGY_REASON_NONE); - } - - @Override - public float heal(float amount) { - float healed = super.heal(amount); - - if (healed > 0f) { - getScene().broadcastPacket( - new PacketEntityFightPropChangeReasonNotify(this, FightProperty.FIGHT_PROP_CUR_HP, healed, PropChangeReason.PROP_CHANGE_REASON_ABILITY, ChangeHpReason.CHANGE_HP_REASON_ADD_ABILITY) - ); - } - - return healed; - } - - public void clearEnergy(ChangeEnergyReason reason) { - // Fight props. - FightProperty curEnergyProp = this.getAvatar().getSkillDepot().getElementType().getCurEnergyProp(); - FightProperty maxEnergyProp = this.getAvatar().getSkillDepot().getElementType().getMaxEnergyProp(); + @Override + public Position getPosition() { + return getPlayer().getPosition(); + } - // Get max energy. - float maxEnergy = this.avatar.getFightProperty(maxEnergyProp); + @Override + public Position getRotation() { + return getPlayer().getRotation(); + } - // Set energy to zero. - this.avatar.setCurrentEnergy(curEnergyProp, 0); + public Avatar getAvatar() { + return avatar; + } - // Send packets. - this.getScene().broadcastPacket(new PacketEntityFightPropUpdateNotify(this, curEnergyProp)); + public int getKilledBy() { + return killedBy; + } - if (reason == ChangeEnergyReason.CHANGE_ENERGY_REASON_SKILL_START) { - this.getScene().broadcastPacket(new PacketEntityFightPropChangeReasonNotify(this, curEnergyProp, -maxEnergy, reason)); - } - } - - public void addEnergy(float amount, PropChangeReason reason) { - this.addEnergy(amount, reason, false); - } - public void addEnergy(float amount, PropChangeReason reason, boolean isFlat) { - // Get current and maximum energy for this avatar. - FightProperty curEnergyProp = this.getAvatar().getSkillDepot().getElementType().getCurEnergyProp(); - FightProperty maxEnergyProp = this.getAvatar().getSkillDepot().getElementType().getMaxEnergyProp(); + public PlayerDieType getKilledType() { + return killedType; + } - float curEnergy = this.getFightProperty(curEnergyProp); - float maxEnergy = this.getFightProperty(maxEnergyProp); - - // Get energy recharge. - float energyRecharge = this.getFightProperty(FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY); + @Override + public boolean isAlive() { + return this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) > 0f; + } - // Scale amount by energy recharge, if the amount is not flat. - if (!isFlat) { - amount *= energyRecharge; - } + @Override + public Int2FloatOpenHashMap getFightProperties() { + return getAvatar().getFightProperties(); + } - // Determine the new energy value. - float newEnergy = Math.min(curEnergy + amount, maxEnergy); - - // Set energy and notify. - if (newEnergy != curEnergy) { - this.avatar.setCurrentEnergy(curEnergyProp, newEnergy); - - this.getScene().broadcastPacket(new PacketAvatarFightPropUpdateNotify(this.getAvatar(), curEnergyProp)); - this.getScene().broadcastPacket(new PacketEntityFightPropChangeReasonNotify(this, curEnergyProp, newEnergy, reason)); - } - } - - public SceneAvatarInfo getSceneAvatarInfo() { - SceneAvatarInfo.Builder avatarInfo = SceneAvatarInfo.newBuilder() - .setUid(this.getPlayer().getUid()) - .setAvatarId(this.getAvatar().getAvatarId()) - .setGuid(this.getAvatar().getGuid()) - .setPeerId(this.getPlayer().getPeerId()) - .addAllTalentIdList(this.getAvatar().getTalentIdList()) - .setCoreProudSkillLevel(this.getAvatar().getCoreProudSkillLevel()) - .putAllSkillLevelMap(this.getAvatar().getSkillLevelMap()) - .setSkillDepotId(this.getAvatar().getSkillDepotId()) - .addAllInherentProudSkillList(this.getAvatar().getProudSkillList()) - .putAllProudSkillExtraLevelMap(this.getAvatar().getProudSkillBonusMap()) - .addAllTeamResonanceList(this.getAvatar().getPlayer().getTeamManager().getTeamResonances()) - .setWearingFlycloakId(this.getAvatar().getFlyCloak()) - .setCostumeId(this.getAvatar().getCostume()) - .setBornTime(this.getAvatar().getBornTime()); - - for (GameItem item : avatar.getEquips().values()) { - if (item.getItemData().getEquipType() == EquipType.EQUIP_WEAPON) { - avatarInfo.setWeapon(item.createSceneWeaponInfo()); - } else { - avatarInfo.addReliquaryList(item.createSceneReliquaryInfo()); - } - avatarInfo.addEquipIdList(item.getItemId()); - } - - return avatarInfo.build(); - } + public int getWeaponEntityId() { + if (getAvatar().getWeapon() != null) { + return getAvatar().getWeapon().getWeaponEntityId(); + } + return 0; + } - @Override - public SceneEntityInfo toProto() { - EntityAuthorityInfo authority = EntityAuthorityInfo.newBuilder() - .setAbilityInfo(AbilitySyncStateInfo.newBuilder()) - .setRendererChangedInfo(EntityRendererChangedInfo.newBuilder()) - .setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(Vector.newBuilder())) - .setBornPos(Vector.newBuilder()) - .build(); - - SceneEntityInfo.Builder entityInfo = SceneEntityInfo.newBuilder() - .setEntityId(getId()) - .setEntityType(ProtEntityType.PROT_ENTITY_TYPE_AVATAR) - .addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder()) - .setEntityClientData(EntityClientData.newBuilder()) - .setEntityAuthorityInfo(authority) - .setLastMoveSceneTimeMs(this.getLastMoveSceneTimeMs()) - .setLastMoveReliableSeq(this.getLastMoveReliableSeq()) - .setLifeState(this.getLifeState().getValue()); - - if (this.getScene() != null) { - entityInfo.setMotionInfo(this.getMotionInfo()); - } - - for (Int2FloatMap.Entry entry : getFightProperties().int2FloatEntrySet()) { - if (entry.getIntKey() == 0) { - continue; - } - FightPropPair fightProp = FightPropPair.newBuilder().setPropType(entry.getIntKey()).setPropValue(entry.getFloatValue()).build(); - entityInfo.addFightPropList(fightProp); - } - - PropPair pair = PropPair.newBuilder() - .setType(PlayerProperty.PROP_LEVEL.getId()) - .setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, getAvatar().getLevel())) - .build(); - entityInfo.addPropList(pair); - - entityInfo.setAvatar(this.getSceneAvatarInfo()); - - return entityInfo.build(); - } - - public AbilityControlBlock getAbilityControlBlock() { - AvatarData data = this.getAvatar().getAvatarData(); - AbilityControlBlock.Builder abilityControlBlock = AbilityControlBlock.newBuilder(); - int embryoId = 0; - - // Add avatar abilities - if (data.getAbilities() != null) { - for (int id : data.getAbilities()) { - AbilityEmbryo emb = AbilityEmbryo.newBuilder() - .setAbilityId(++embryoId) - .setAbilityNameHash(id) - .setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME) - .build(); - abilityControlBlock.addAbilityEmbryoList(emb); - } - } - // Add default abilities - for (int id : GameConstants.DEFAULT_ABILITY_HASHES) { - AbilityEmbryo emb = AbilityEmbryo.newBuilder() - .setAbilityId(++embryoId) - .setAbilityNameHash(id) - .setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME) - .build(); - abilityControlBlock.addAbilityEmbryoList(emb); - } - // Add team resonances - for (int id : this.getPlayer().getTeamManager().getTeamResonancesConfig()) { - AbilityEmbryo emb = AbilityEmbryo.newBuilder() - .setAbilityId(++embryoId) - .setAbilityNameHash(id) - .setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME) - .build(); - abilityControlBlock.addAbilityEmbryoList(emb); - } - // Add skill depot abilities - AvatarSkillDepotData skillDepot = GameData.getAvatarSkillDepotDataMap().get(this.getAvatar().getSkillDepotId()); - if (skillDepot != null && skillDepot.getAbilities() != null) { - for (int id : skillDepot.getAbilities()) { - AbilityEmbryo emb = AbilityEmbryo.newBuilder() - .setAbilityId(++embryoId) - .setAbilityNameHash(id) - .setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME) - .build(); - abilityControlBlock.addAbilityEmbryoList(emb); - } - } - // Add equip abilities - if (this.getAvatar().getExtraAbilityEmbryos().size() > 0) { - for (String skill : this.getAvatar().getExtraAbilityEmbryos()) { - AbilityEmbryo emb = AbilityEmbryo.newBuilder() - .setAbilityId(++embryoId) - .setAbilityNameHash(Utils.abilityHash(skill)) - .setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME) - .build(); - abilityControlBlock.addAbilityEmbryoList(emb); - } - } - - // - return abilityControlBlock.build(); - } + @Override + public void onDeath(int killerId) { + this.killedType = PlayerDieType.PLAYER_DIE_TYPE_KILL_BY_MONSTER; + this.killedBy = killerId; + clearEnergy(ChangeEnergyReason.CHANGE_ENERGY_REASON_NONE); + } + + public void onDeath(PlayerDieType dieType, int killerId) { + this.killedType = dieType; + this.killedBy = killerId; + clearEnergy(ChangeEnergyReason.CHANGE_ENERGY_REASON_NONE); + } + + @Override + public float heal(float amount) { + float healed = super.heal(amount); + + if (healed > 0f) { + getScene().broadcastPacket( + new PacketEntityFightPropChangeReasonNotify(this, FightProperty.FIGHT_PROP_CUR_HP, healed, PropChangeReason.PROP_CHANGE_REASON_ABILITY, ChangeHpReason.CHANGE_HP_REASON_ADD_ABILITY) + ); + } + + return healed; + } + + public void clearEnergy(ChangeEnergyReason reason) { + // Fight props. + FightProperty curEnergyProp = this.getAvatar().getSkillDepot().getElementType().getCurEnergyProp(); + FightProperty maxEnergyProp = this.getAvatar().getSkillDepot().getElementType().getMaxEnergyProp(); + + // Get max energy. + float maxEnergy = this.avatar.getFightProperty(maxEnergyProp); + + // Set energy to zero. + this.avatar.setCurrentEnergy(curEnergyProp, 0); + + // Send packets. + this.getScene().broadcastPacket(new PacketEntityFightPropUpdateNotify(this, curEnergyProp)); + + if (reason == ChangeEnergyReason.CHANGE_ENERGY_REASON_SKILL_START) { + this.getScene().broadcastPacket(new PacketEntityFightPropChangeReasonNotify(this, curEnergyProp, -maxEnergy, reason)); + } + } + + public void addEnergy(float amount, PropChangeReason reason) { + this.addEnergy(amount, reason, false); + } + public void addEnergy(float amount, PropChangeReason reason, boolean isFlat) { + // Get current and maximum energy for this avatar. + FightProperty curEnergyProp = this.getAvatar().getSkillDepot().getElementType().getCurEnergyProp(); + FightProperty maxEnergyProp = this.getAvatar().getSkillDepot().getElementType().getMaxEnergyProp(); + + float curEnergy = this.getFightProperty(curEnergyProp); + float maxEnergy = this.getFightProperty(maxEnergyProp); + + // Get energy recharge. + float energyRecharge = this.getFightProperty(FightProperty.FIGHT_PROP_CHARGE_EFFICIENCY); + + // Scale amount by energy recharge, if the amount is not flat. + if (!isFlat) { + amount *= energyRecharge; + } + + // Determine the new energy value. + float newEnergy = Math.min(curEnergy + amount, maxEnergy); + + // Set energy and notify. + if (newEnergy != curEnergy) { + this.avatar.setCurrentEnergy(curEnergyProp, newEnergy); + + this.getScene().broadcastPacket(new PacketAvatarFightPropUpdateNotify(this.getAvatar(), curEnergyProp)); + this.getScene().broadcastPacket(new PacketEntityFightPropChangeReasonNotify(this, curEnergyProp, newEnergy, reason)); + } + } + + public SceneAvatarInfo getSceneAvatarInfo() { + SceneAvatarInfo.Builder avatarInfo = SceneAvatarInfo.newBuilder() + .setUid(this.getPlayer().getUid()) + .setAvatarId(this.getAvatar().getAvatarId()) + .setGuid(this.getAvatar().getGuid()) + .setPeerId(this.getPlayer().getPeerId()) + .addAllTalentIdList(this.getAvatar().getTalentIdList()) + .setCoreProudSkillLevel(this.getAvatar().getCoreProudSkillLevel()) + .putAllSkillLevelMap(this.getAvatar().getSkillLevelMap()) + .setSkillDepotId(this.getAvatar().getSkillDepotId()) + .addAllInherentProudSkillList(this.getAvatar().getProudSkillList()) + .putAllProudSkillExtraLevelMap(this.getAvatar().getProudSkillBonusMap()) + .addAllTeamResonanceList(this.getAvatar().getPlayer().getTeamManager().getTeamResonances()) + .setWearingFlycloakId(this.getAvatar().getFlyCloak()) + .setCostumeId(this.getAvatar().getCostume()) + .setBornTime(this.getAvatar().getBornTime()); + + for (GameItem item : avatar.getEquips().values()) { + if (item.getItemData().getEquipType() == EquipType.EQUIP_WEAPON) { + avatarInfo.setWeapon(item.createSceneWeaponInfo()); + } else { + avatarInfo.addReliquaryList(item.createSceneReliquaryInfo()); + } + avatarInfo.addEquipIdList(item.getItemId()); + } + + return avatarInfo.build(); + } + + @Override + public SceneEntityInfo toProto() { + EntityAuthorityInfo authority = EntityAuthorityInfo.newBuilder() + .setAbilityInfo(AbilitySyncStateInfo.newBuilder()) + .setRendererChangedInfo(EntityRendererChangedInfo.newBuilder()) + .setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(Vector.newBuilder())) + .setBornPos(Vector.newBuilder()) + .build(); + + SceneEntityInfo.Builder entityInfo = SceneEntityInfo.newBuilder() + .setEntityId(getId()) + .setEntityType(ProtEntityType.PROT_ENTITY_TYPE_AVATAR) + .addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder()) + .setEntityClientData(EntityClientData.newBuilder()) + .setEntityAuthorityInfo(authority) + .setLastMoveSceneTimeMs(this.getLastMoveSceneTimeMs()) + .setLastMoveReliableSeq(this.getLastMoveReliableSeq()) + .setLifeState(this.getLifeState().getValue()); + + if (this.getScene() != null) { + entityInfo.setMotionInfo(this.getMotionInfo()); + } + + for (Int2FloatMap.Entry entry : getFightProperties().int2FloatEntrySet()) { + if (entry.getIntKey() == 0) { + continue; + } + FightPropPair fightProp = FightPropPair.newBuilder().setPropType(entry.getIntKey()).setPropValue(entry.getFloatValue()).build(); + entityInfo.addFightPropList(fightProp); + } + + PropPair pair = PropPair.newBuilder() + .setType(PlayerProperty.PROP_LEVEL.getId()) + .setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, getAvatar().getLevel())) + .build(); + entityInfo.addPropList(pair); + + entityInfo.setAvatar(this.getSceneAvatarInfo()); + + return entityInfo.build(); + } + + public AbilityControlBlock getAbilityControlBlock() { + AvatarData data = this.getAvatar().getAvatarData(); + AbilityControlBlock.Builder abilityControlBlock = AbilityControlBlock.newBuilder(); + int embryoId = 0; + + // Add avatar abilities + if (data.getAbilities() != null) { + for (int id : data.getAbilities()) { + AbilityEmbryo emb = AbilityEmbryo.newBuilder() + .setAbilityId(++embryoId) + .setAbilityNameHash(id) + .setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME) + .build(); + abilityControlBlock.addAbilityEmbryoList(emb); + } + } + // Add default abilities + for (int id : GameConstants.DEFAULT_ABILITY_HASHES) { + AbilityEmbryo emb = AbilityEmbryo.newBuilder() + .setAbilityId(++embryoId) + .setAbilityNameHash(id) + .setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME) + .build(); + abilityControlBlock.addAbilityEmbryoList(emb); + } + // Add team resonances + for (int id : this.getPlayer().getTeamManager().getTeamResonancesConfig()) { + AbilityEmbryo emb = AbilityEmbryo.newBuilder() + .setAbilityId(++embryoId) + .setAbilityNameHash(id) + .setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME) + .build(); + abilityControlBlock.addAbilityEmbryoList(emb); + } + // Add skill depot abilities + AvatarSkillDepotData skillDepot = GameData.getAvatarSkillDepotDataMap().get(this.getAvatar().getSkillDepotId()); + if (skillDepot != null && skillDepot.getAbilities() != null) { + for (int id : skillDepot.getAbilities()) { + AbilityEmbryo emb = AbilityEmbryo.newBuilder() + .setAbilityId(++embryoId) + .setAbilityNameHash(id) + .setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME) + .build(); + abilityControlBlock.addAbilityEmbryoList(emb); + } + } + // Add equip abilities + if (this.getAvatar().getExtraAbilityEmbryos().size() > 0) { + for (String skill : this.getAvatar().getExtraAbilityEmbryos()) { + AbilityEmbryo emb = AbilityEmbryo.newBuilder() + .setAbilityId(++embryoId) + .setAbilityNameHash(Utils.abilityHash(skill)) + .setAbilityOverrideNameHash(GameConstants.DEFAULT_ABILITY_NAME) + .build(); + abilityControlBlock.addAbilityEmbryoList(emb); + } + } + + // + return abilityControlBlock.build(); + } } diff --git a/src/main/java/emu/grasscutter/game/entity/EntityGadget.java b/src/main/java/emu/grasscutter/game/entity/EntityGadget.java index 2d84cafa4..1f88f451a 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityGadget.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityGadget.java @@ -38,125 +38,125 @@ import lombok.ToString; @ToString(callSuper = true) public class EntityGadget extends EntityBaseGadget { - private final GadgetData data; - private final Position pos; - private final Position rot; - private int gadgetId; + private final GadgetData data; + private final Position pos; + private final Position rot; + private int gadgetId; - private int state; - private int pointType; - private GadgetContent content; - private Int2FloatOpenHashMap fightProp; - private SceneGadget metaGadget; + private int state; + private int pointType; + private GadgetContent content; + private Int2FloatOpenHashMap fightProp; + private SceneGadget metaGadget; - public EntityGadget(Scene scene, int gadgetId, Position pos, Position rot) { - super(scene); - this.data = GameData.getGadgetDataMap().get(gadgetId); - this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET); - this.gadgetId = gadgetId; - this.pos = pos.clone(); - this.rot = rot != null ? rot.clone() : new Position(); - } + public EntityGadget(Scene scene, int gadgetId, Position pos, Position rot) { + super(scene); + this.data = GameData.getGadgetDataMap().get(gadgetId); + this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET); + this.gadgetId = gadgetId; + this.pos = pos.clone(); + this.rot = rot != null ? rot.clone() : new Position(); + } - public EntityGadget(Scene scene, int gadgetId, Position pos) { - this(scene, gadgetId, pos, new Position()); - } + public EntityGadget(Scene scene, int gadgetId, Position pos) { + this(scene, gadgetId, pos, new Position()); + } - public EntityGadget(Scene scene, int gadgetId, Position pos, Position rot, GadgetContent content) { - this(scene, gadgetId, pos, rot); - this.content = content; - } + public EntityGadget(Scene scene, int gadgetId, Position pos, Position rot, GadgetContent content) { + this(scene, gadgetId, pos, rot); + this.content = content; + } - public GadgetData getGadgetData() { - return data; - } + public GadgetData getGadgetData() { + return data; + } - @Override - public Position getPosition() { - return this.pos; - } + @Override + public Position getPosition() { + return this.pos; + } - @Override - public Position getRotation() { - return this.rot; - } + @Override + public Position getRotation() { + return this.rot; + } - public int getGadgetId() { - return gadgetId; - } + public int getGadgetId() { + return gadgetId; + } - public void setGadgetId(int gadgetId) { - this.gadgetId = gadgetId; - } + public void setGadgetId(int gadgetId) { + this.gadgetId = gadgetId; + } - public int getState() { - return state; - } + public int getState() { + return state; + } - public void setState(int state) { - this.state = state; - } + public void setState(int state) { + this.state = state; + } - public void updateState(int state){ - this.setState(state); - this.getScene().broadcastPacket(new PacketGadgetStateNotify(this, state)); - getScene().getScriptManager().callEvent(EventType.EVENT_GADGET_STATE_CHANGE, new ScriptArgs(state, this.getConfigId())); - } + public void updateState(int state) { + this.setState(state); + this.getScene().broadcastPacket(new PacketGadgetStateNotify(this, state)); + getScene().getScriptManager().callEvent(EventType.EVENT_GADGET_STATE_CHANGE, new ScriptArgs(state, this.getConfigId())); + } - public int getPointType() { - return pointType; - } + public int getPointType() { + return pointType; + } - public void setPointType(int pointType) { - this.pointType = pointType; - } + public void setPointType(int pointType) { + this.pointType = pointType; + } - public GadgetContent getContent() { - return content; - } + public GadgetContent getContent() { + return content; + } - @Deprecated // Dont use! - public void setContent(GadgetContent content) { - this.content = this.content == null ? content : this.content; - } + @Deprecated // Dont use! + public void setContent(GadgetContent content) { + this.content = this.content == null ? content : this.content; + } - public SceneGadget getMetaGadget() { - return metaGadget; - } + public SceneGadget getMetaGadget() { + return metaGadget; + } - public void setMetaGadget(SceneGadget metaGadget) { - this.metaGadget = metaGadget; - } + public void setMetaGadget(SceneGadget metaGadget) { + this.metaGadget = metaGadget; + } - // TODO refactor - public void buildContent() { - if (getContent() != null || getGadgetData() == null || getGadgetData().getType() == null) { - return; - } + // TODO refactor + public void buildContent() { + if (getContent() != null || getGadgetData() == null || getGadgetData().getType() == null) { + return; + } - EntityType type = getGadgetData().getType(); - GadgetContent content = switch (type) { - case GatherPoint -> new GadgetGatherPoint(this); - case GatherObject -> new GadgetGatherObject(this); - case Worktop -> new GadgetWorktop(this); - case RewardStatue -> new GadgetRewardStatue(this); - case Chest -> new GadgetChest(this); + EntityType type = getGadgetData().getType(); + GadgetContent content = switch (type) { + case GatherPoint -> new GadgetGatherPoint(this); + case GatherObject -> new GadgetGatherObject(this); + case Worktop -> new GadgetWorktop(this); + case RewardStatue -> new GadgetRewardStatue(this); + case Chest -> new GadgetChest(this); case Gadget -> new GadgetObject(this); - default -> null; - }; + default -> null; + }; - this.content = content; - } + this.content = content; + } - @Override - public Int2FloatOpenHashMap getFightProperties() { - if (this.fightProp == null) this.fightProp = new Int2FloatOpenHashMap(); - return this.fightProp; - } - - @Override + @Override + public Int2FloatOpenHashMap getFightProperties() { + if (this.fightProp == null) this.fightProp = new Int2FloatOpenHashMap(); + return this.fightProp; + } + + @Override public void onInteract(Player player, GadgetInteractReq interactReq) { - if (this.getContent() == null) { + if (this.getContent() == null) { return; } @@ -165,68 +165,68 @@ public class EntityGadget extends EntityBaseGadget { if (shouldDelete) { this.getScene().killEntity(this); } - } + } - @Override - public void onCreate() { - // Lua event - getScene().getScriptManager().callEvent(EventType.EVENT_GADGET_CREATE, new ScriptArgs(this.getConfigId())); - } + @Override + public void onCreate() { + // Lua event + getScene().getScriptManager().callEvent(EventType.EVENT_GADGET_CREATE, new ScriptArgs(this.getConfigId())); + } - @Override - public void onDeath(int killerId) { - if (this.getSpawnEntry() != null) { - this.getScene().getDeadSpawnedEntities().add(getSpawnEntry()); - } - if (getScene().getChallenge() != null) { - getScene().getChallenge().onGadgetDeath(this); - } - getScene().getScriptManager().callEvent(EventType.EVENT_ANY_GADGET_DIE, new ScriptArgs(this.getConfigId())); - } + @Override + public void onDeath(int killerId) { + if (this.getSpawnEntry() != null) { + this.getScene().getDeadSpawnedEntities().add(getSpawnEntry()); + } + if (getScene().getChallenge() != null) { + getScene().getChallenge().onGadgetDeath(this); + } + getScene().getScriptManager().callEvent(EventType.EVENT_ANY_GADGET_DIE, new ScriptArgs(this.getConfigId())); + } - @Override - public SceneEntityInfo toProto() { - EntityAuthorityInfo authority = EntityAuthorityInfo.newBuilder() - .setAbilityInfo(AbilitySyncStateInfo.newBuilder()) - .setRendererChangedInfo(EntityRendererChangedInfo.newBuilder()) - .setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(Vector.newBuilder())) - .setBornPos(Vector.newBuilder()) - .build(); + @Override + public SceneEntityInfo toProto() { + EntityAuthorityInfo authority = EntityAuthorityInfo.newBuilder() + .setAbilityInfo(AbilitySyncStateInfo.newBuilder()) + .setRendererChangedInfo(EntityRendererChangedInfo.newBuilder()) + .setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(Vector.newBuilder())) + .setBornPos(Vector.newBuilder()) + .build(); - SceneEntityInfo.Builder entityInfo = SceneEntityInfo.newBuilder() - .setEntityId(getId()) - .setEntityType(ProtEntityType.PROT_ENTITY_TYPE_GADGET) - .setMotionInfo(MotionInfo.newBuilder().setPos(getPosition().toProto()).setRot(getRotation().toProto()).setSpeed(Vector.newBuilder())) - .addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder()) - .setEntityClientData(EntityClientData.newBuilder()) - .setEntityAuthorityInfo(authority) - .setLifeState(1); + SceneEntityInfo.Builder entityInfo = SceneEntityInfo.newBuilder() + .setEntityId(getId()) + .setEntityType(ProtEntityType.PROT_ENTITY_TYPE_GADGET) + .setMotionInfo(MotionInfo.newBuilder().setPos(getPosition().toProto()).setRot(getRotation().toProto()).setSpeed(Vector.newBuilder())) + .addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder()) + .setEntityClientData(EntityClientData.newBuilder()) + .setEntityAuthorityInfo(authority) + .setLifeState(1); - PropPair pair = PropPair.newBuilder() - .setType(PlayerProperty.PROP_LEVEL.getId()) - .setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 1)) - .build(); - entityInfo.addPropList(pair); + PropPair pair = PropPair.newBuilder() + .setType(PlayerProperty.PROP_LEVEL.getId()) + .setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 1)) + .build(); + entityInfo.addPropList(pair); - // We do not use the getter to null check because the getter will create a fight prop map if it is null - if (this.fightProp != null) { - this.addAllFightPropsToEntityInfo(entityInfo); - } + // We do not use the getter to null check because the getter will create a fight prop map if it is null + if (this.fightProp != null) { + this.addAllFightPropsToEntityInfo(entityInfo); + } - SceneGadgetInfo.Builder gadgetInfo = SceneGadgetInfo.newBuilder() - .setGadgetId(this.getGadgetId()) - .setGroupId(this.getGroupId()) - .setConfigId(this.getConfigId()) - .setGadgetState(this.getState()) - .setIsEnableInteract(true) - .setAuthorityPeerId(this.getScene().getWorld().getHostPeerId()); + SceneGadgetInfo.Builder gadgetInfo = SceneGadgetInfo.newBuilder() + .setGadgetId(this.getGadgetId()) + .setGroupId(this.getGroupId()) + .setConfigId(this.getConfigId()) + .setGadgetState(this.getState()) + .setIsEnableInteract(true) + .setAuthorityPeerId(this.getScene().getWorld().getHostPeerId()); - if (this.getContent() != null) { - this.getContent().onBuildProto(gadgetInfo); - } + if (this.getContent() != null) { + this.getContent().onBuildProto(gadgetInfo); + } - entityInfo.setGadget(gadgetInfo); + entityInfo.setGadget(gadgetInfo); - return entityInfo.build(); - } + return entityInfo.build(); + } } diff --git a/src/main/java/emu/grasscutter/game/entity/EntityItem.java b/src/main/java/emu/grasscutter/game/entity/EntityItem.java index 63817f7c1..c4befb408 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityItem.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityItem.java @@ -28,95 +28,95 @@ import emu.grasscutter.utils.ProtoHelper; import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap; public class EntityItem extends EntityBaseGadget { - private final Position pos; - private final Position rot; - - private final GameItem item; - private final long guid; + private final Position pos; + private final Position rot; - private final boolean share; + private final GameItem item; + private final long guid; - public EntityItem(Scene scene, Player player, ItemData itemData, Position pos, int count) { - super(scene); - this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET); - this.pos = new Position(pos); - this.rot = new Position(); - this.guid = player == null ? scene.getWorld().getHost().getNextGameGuid() : player.getNextGameGuid(); - this.item = new GameItem(itemData, count); - this.share = true; - } + private final boolean share; - // In official game, some drop items are shared to all players, and some other items are independent to all players - // For example, if you killed a monster in MP mode, all players could get drops but rarity and number of them are different - // but if you broke regional mine, when someone picked up the drop then it disappeared - public EntityItem(Scene scene, Player player, ItemData itemData, Position pos, int count, boolean share) { - super(scene); - this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET); - this.pos = new Position(pos); - this.rot = new Position(); - this.guid = player == null ? scene.getWorld().getHost().getNextGameGuid() : player.getNextGameGuid(); - this.item = new GameItem(itemData, count); - this.share = share; - } - - @Override - public int getId() { - return this.id; - } - - private GameItem getItem() { - return this.item; - } + public EntityItem(Scene scene, Player player, ItemData itemData, Position pos, int count) { + super(scene); + this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET); + this.pos = new Position(pos); + this.rot = new Position(); + this.guid = player == null ? scene.getWorld().getHost().getNextGameGuid() : player.getNextGameGuid(); + this.item = new GameItem(itemData, count); + this.share = true; + } - public ItemData getItemData() { - return this.getItem().getItemData(); - } + // In official game, some drop items are shared to all players, and some other items are independent to all players + // For example, if you killed a monster in MP mode, all players could get drops but rarity and number of them are different + // but if you broke regional mine, when someone picked up the drop then it disappeared + public EntityItem(Scene scene, Player player, ItemData itemData, Position pos, int count, boolean share) { + super(scene); + this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET); + this.pos = new Position(pos); + this.rot = new Position(); + this.guid = player == null ? scene.getWorld().getHost().getNextGameGuid() : player.getNextGameGuid(); + this.item = new GameItem(itemData, count); + this.share = share; + } - public long getGuid() { - return guid; - } + @Override + public int getId() { + return this.id; + } - public int getCount() { - return this.getItem().getCount(); - } - - @Override - public int getGadgetId() { - return this.getItemData().getGadgetId(); - } + private GameItem getItem() { + return this.item; + } - @Override - public Position getPosition() { - return this.pos; - } + public ItemData getItemData() { + return this.getItem().getItemData(); + } - @Override - public Position getRotation() { - return this.rot; - } - - @Override - public Int2FloatOpenHashMap getFightProperties() { - return null; - } + public long getGuid() { + return guid; + } - public boolean isShare() { - return share; - } - - @Override - public void onInteract(Player player, GadgetInteractReq interactReq) { - // check drop owner to avoid someone picked up item in others' world + public int getCount() { + return this.getItem().getCount(); + } + + @Override + public int getGadgetId() { + return this.getItemData().getGadgetId(); + } + + @Override + public Position getPosition() { + return this.pos; + } + + @Override + public Position getRotation() { + return this.rot; + } + + @Override + public Int2FloatOpenHashMap getFightProperties() { + return null; + } + + public boolean isShare() { + return share; + } + + @Override + public void onInteract(Player player, GadgetInteractReq interactReq) { + // check drop owner to avoid someone picked up item in others' world if (!this.isShare()) { int dropOwner = (int) (this.getGuid() >> 32); if (dropOwner != player.getUid()) { return; } } - + this.getScene().removeEntity(this); GameItem item = new GameItem(this.getItemData(), this.getCount()); - + // Add to inventory boolean success = player.getInventory().addItem(item, ActionReason.SubfieldDrop); if (success) { @@ -128,39 +128,39 @@ public class EntityItem extends EntityBaseGadget { } } - @Override - public SceneEntityInfo toProto() { - EntityAuthorityInfo authority = EntityAuthorityInfo.newBuilder() - .setAbilityInfo(AbilitySyncStateInfo.newBuilder()) - .setRendererChangedInfo(EntityRendererChangedInfo.newBuilder()) - .setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(Vector.newBuilder())) - .setBornPos(Vector.newBuilder()) - .build(); - - SceneEntityInfo.Builder entityInfo = SceneEntityInfo.newBuilder() - .setEntityId(getId()) - .setEntityType(ProtEntityType.PROT_ENTITY_TYPE_GADGET) - .setMotionInfo(MotionInfo.newBuilder().setPos(getPosition().toProto()).setRot(getRotation().toProto()).setSpeed(Vector.newBuilder())) - .addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder()) - .setEntityClientData(EntityClientData.newBuilder()) - .setEntityAuthorityInfo(authority) - .setLifeState(1); - - PropPair pair = PropPair.newBuilder() - .setType(PlayerProperty.PROP_LEVEL.getId()) - .setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 1)) - .build(); - entityInfo.addPropList(pair); - - SceneGadgetInfo.Builder gadgetInfo = SceneGadgetInfo.newBuilder() - .setGadgetId(this.getItemData().getGadgetId()) - .setTrifleItem(this.getItem().toProto()) - .setBornType(GadgetBornType.GADGET_BORN_TYPE_IN_AIR) - .setAuthorityPeerId(this.getWorld().getHostPeerId()) - .setIsEnableInteract(true); + @Override + public SceneEntityInfo toProto() { + EntityAuthorityInfo authority = EntityAuthorityInfo.newBuilder() + .setAbilityInfo(AbilitySyncStateInfo.newBuilder()) + .setRendererChangedInfo(EntityRendererChangedInfo.newBuilder()) + .setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(Vector.newBuilder())) + .setBornPos(Vector.newBuilder()) + .build(); - entityInfo.setGadget(gadgetInfo); - - return entityInfo.build(); - } + SceneEntityInfo.Builder entityInfo = SceneEntityInfo.newBuilder() + .setEntityId(getId()) + .setEntityType(ProtEntityType.PROT_ENTITY_TYPE_GADGET) + .setMotionInfo(MotionInfo.newBuilder().setPos(getPosition().toProto()).setRot(getRotation().toProto()).setSpeed(Vector.newBuilder())) + .addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder()) + .setEntityClientData(EntityClientData.newBuilder()) + .setEntityAuthorityInfo(authority) + .setLifeState(1); + + PropPair pair = PropPair.newBuilder() + .setType(PlayerProperty.PROP_LEVEL.getId()) + .setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 1)) + .build(); + entityInfo.addPropList(pair); + + SceneGadgetInfo.Builder gadgetInfo = SceneGadgetInfo.newBuilder() + .setGadgetId(this.getItemData().getGadgetId()) + .setTrifleItem(this.getItem().toProto()) + .setBornType(GadgetBornType.GADGET_BORN_TYPE_IN_AIR) + .setAuthorityPeerId(this.getWorld().getHostPeerId()) + .setIsEnableInteract(true); + + entityInfo.setGadget(gadgetInfo); + + return entityInfo.build(); + } } diff --git a/src/main/java/emu/grasscutter/game/entity/EntityMonster.java b/src/main/java/emu/grasscutter/game/entity/EntityMonster.java index 2ff99bef4..4c1426c02 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityMonster.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityMonster.java @@ -39,257 +39,257 @@ import it.unimi.dsi.fastutil.ints.Int2FloatMap; import it.unimi.dsi.fastutil.ints.Int2FloatOpenHashMap; public class EntityMonster extends GameEntity { - private final MonsterData monsterData; - private final Int2FloatOpenHashMap fightProp; - - private final Position pos; - private final Position rot; - private final Position bornPos; - private final int level; - private int weaponEntityId; - private int poseId; - - public EntityMonster(Scene scene, MonsterData monsterData, Position pos, int level) { - super(scene); - this.id = getWorld().getNextEntityId(EntityIdType.MONSTER); - this.monsterData = monsterData; - this.fightProp = new Int2FloatOpenHashMap(); - this.pos = new Position(pos); - this.rot = new Position(); - this.bornPos = getPosition().clone(); - this.level = level; - - // Monster weapon - if (getMonsterWeaponId() > 0) { - this.weaponEntityId = getWorld().getNextEntityId(EntityIdType.WEAPON); - } - - this.recalcStats(); - } - - @Override - public int getId() { - return this.id; - } + private final MonsterData monsterData; + private final Int2FloatOpenHashMap fightProp; - public MonsterData getMonsterData() { - return monsterData; - } - - public int getMonsterWeaponId() { - return getMonsterData().getWeaponId(); - } - - private int getMonsterId() { - return this.getMonsterData().getId(); - } + private final Position pos; + private final Position rot; + private final Position bornPos; + private final int level; + private int weaponEntityId; + private int poseId; - public int getLevel() { - return level; - } + public EntityMonster(Scene scene, MonsterData monsterData, Position pos, int level) { + super(scene); + this.id = getWorld().getNextEntityId(EntityIdType.MONSTER); + this.monsterData = monsterData; + this.fightProp = new Int2FloatOpenHashMap(); + this.pos = new Position(pos); + this.rot = new Position(); + this.bornPos = getPosition().clone(); + this.level = level; - @Override - public Position getPosition() { - return this.pos; - } + // Monster weapon + if (getMonsterWeaponId() > 0) { + this.weaponEntityId = getWorld().getNextEntityId(EntityIdType.WEAPON); + } - @Override - public Position getRotation() { - return this.rot; - } - - public Position getBornPos() { - return bornPos; - } + this.recalcStats(); + } - @Override - public Int2FloatOpenHashMap getFightProperties() { - return fightProp; - } - - @Override - public boolean isAlive() { - return this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) > 0f; - } + @Override + public int getId() { + return this.id; + } - public int getPoseId() { - return poseId; - } + public MonsterData getMonsterData() { + return monsterData; + } - public void setPoseId(int poseId) { - this.poseId = poseId; - } - - @Override + public int getMonsterWeaponId() { + return getMonsterData().getWeaponId(); + } + + private int getMonsterId() { + return this.getMonsterData().getId(); + } + + public int getLevel() { + return level; + } + + @Override + public Position getPosition() { + return this.pos; + } + + @Override + public Position getRotation() { + return this.rot; + } + + public Position getBornPos() { + return bornPos; + } + + @Override + public Int2FloatOpenHashMap getFightProperties() { + return fightProp; + } + + @Override + public boolean isAlive() { + return this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) > 0f; + } + + public int getPoseId() { + return poseId; + } + + public void setPoseId(int poseId) { + this.poseId = poseId; + } + + @Override public void onInteract(Player player, GadgetInteractReq interactReq) { - EnvAnimalGatherConfigData gatherData = GameData.getEnvAnimalGatherConfigDataMap().get(this.getMonsterData().getId()); - + EnvAnimalGatherConfigData gatherData = GameData.getEnvAnimalGatherConfigDataMap().get(this.getMonsterData().getId()); + if (gatherData == null) { return; } player.getInventory().addItem(gatherData.getGatherItem(), ActionReason.SubfieldDrop); - + this.getScene().killEntity(this); } - - @Override - public void onCreate() { - // Lua event - getScene().getScriptManager().callEvent(EventType.EVENT_ANY_MONSTER_LIVE, new ScriptArgs(this.getConfigId())); - } - @Override - public void damage(float amount, int killerId) { - // Get HP before damage. - float hpBeforeDamage = this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP); + @Override + public void onCreate() { + // Lua event + getScene().getScriptManager().callEvent(EventType.EVENT_ANY_MONSTER_LIVE, new ScriptArgs(this.getConfigId())); + } - // Apply damage. - super.damage(amount, killerId); + @Override + public void damage(float amount, int killerId) { + // Get HP before damage. + float hpBeforeDamage = this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP); - // Get HP after damage. - float hpAfterDamage = this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP); + // Apply damage. + super.damage(amount, killerId); - // Invoke energy drop logic. - for (Player player : this.getScene().getPlayers()) { - player.getEnergyManager().handleMonsterEnergyDrop(this, hpBeforeDamage, hpAfterDamage); - } - } + // Get HP after damage. + float hpAfterDamage = this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP); - @Override - public void onDeath(int killerId) { - if (this.getSpawnEntry() != null) { - this.getScene().getDeadSpawnedEntities().add(getSpawnEntry()); - } - // first set the challenge data - if (getScene().getChallenge() != null) { - getScene().getChallenge().onMonsterDeath(this); - } - if (getScene().getScriptManager().isInit() && this.getGroupId() > 0) { - if(getScene().getScriptManager().getScriptMonsterSpawnService() != null){ - getScene().getScriptManager().getScriptMonsterSpawnService().onMonsterDead(this); - } - // prevent spawn monster after success - if(getScene().getChallenge() != null && getScene().getChallenge().inProgress()){ - getScene().getScriptManager().callEvent(EventType.EVENT_ANY_MONSTER_DIE, new ScriptArgs().setParam1(this.getConfigId())); - }else if(getScene().getChallenge() == null){ - getScene().getScriptManager().callEvent(EventType.EVENT_ANY_MONSTER_DIE, new ScriptArgs().setParam1(this.getConfigId())); - } - } - // Battle Pass trigger - getScene().getPlayers().forEach(p -> p.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_MONSTER_DIE, this.getMonsterId(), 1)); - } - - public void recalcStats() { - // Monster data - MonsterData data = this.getMonsterData(); + // Invoke energy drop logic. + for (Player player : this.getScene().getPlayers()) { + player.getEnergyManager().handleMonsterEnergyDrop(this, hpBeforeDamage, hpAfterDamage); + } + } - // Get hp percent, set to 100% if none - float hpPercent = this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) <= 0 ? 1f : this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) / this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP); - - // Clear properties - this.getFightProperties().clear(); - - // Base stats - this.setFightProperty(FightProperty.FIGHT_PROP_BASE_HP, data.getBaseHp()); - this.setFightProperty(FightProperty.FIGHT_PROP_BASE_ATTACK, data.getBaseAttack()); - this.setFightProperty(FightProperty.FIGHT_PROP_BASE_DEFENSE, data.getBaseDefense()); - - this.setFightProperty(FightProperty.FIGHT_PROP_PHYSICAL_SUB_HURT, data.getPhysicalSubHurt()); - this.setFightProperty(FightProperty.FIGHT_PROP_FIRE_SUB_HURT, .1f); - this.setFightProperty(FightProperty.FIGHT_PROP_ELEC_SUB_HURT, data.getElecSubHurt()); - this.setFightProperty(FightProperty.FIGHT_PROP_WATER_SUB_HURT, data.getWaterSubHurt()); - this.setFightProperty(FightProperty.FIGHT_PROP_GRASS_SUB_HURT, data.getGrassSubHurt()); - this.setFightProperty(FightProperty.FIGHT_PROP_WIND_SUB_HURT, data.getWindSubHurt()); - this.setFightProperty(FightProperty.FIGHT_PROP_ROCK_SUB_HURT, .1f); - this.setFightProperty(FightProperty.FIGHT_PROP_ICE_SUB_HURT, data.getIceSubHurt()); - - // Level curve - MonsterCurveData curve = GameData.getMonsterCurveDataMap().get(this.getLevel()); - if (curve != null) { - for (PropGrowCurve growCurve : data.getPropGrowCurves()) { - FightProperty prop = FightProperty.getPropByName(growCurve.getType()); - this.setFightProperty(prop, this.getFightProperty(prop) * curve.getMultByProp(growCurve.getGrowCurve())); - } - } - - // Set % stats - this.setFightProperty( - FightProperty.FIGHT_PROP_MAX_HP, - (getFightProperty(FightProperty.FIGHT_PROP_BASE_HP) * (1f + getFightProperty(FightProperty.FIGHT_PROP_HP_PERCENT))) + getFightProperty(FightProperty.FIGHT_PROP_HP) - ); - this.setFightProperty( - FightProperty.FIGHT_PROP_CUR_ATTACK, - (getFightProperty(FightProperty.FIGHT_PROP_BASE_ATTACK) * (1f + getFightProperty(FightProperty.FIGHT_PROP_ATTACK_PERCENT))) + getFightProperty(FightProperty.FIGHT_PROP_ATTACK) - ); - this.setFightProperty( - FightProperty.FIGHT_PROP_CUR_DEFENSE, - (getFightProperty(FightProperty.FIGHT_PROP_BASE_DEFENSE) * (1f + getFightProperty(FightProperty.FIGHT_PROP_DEFENSE_PERCENT))) + getFightProperty(FightProperty.FIGHT_PROP_DEFENSE) - ); - - // Set current hp - this.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * hpPercent); - } + @Override + public void onDeath(int killerId) { + if (this.getSpawnEntry() != null) { + this.getScene().getDeadSpawnedEntities().add(getSpawnEntry()); + } + // first set the challenge data + if (getScene().getChallenge() != null) { + getScene().getChallenge().onMonsterDeath(this); + } + if (getScene().getScriptManager().isInit() && this.getGroupId() > 0) { + if (getScene().getScriptManager().getScriptMonsterSpawnService() != null) { + getScene().getScriptManager().getScriptMonsterSpawnService().onMonsterDead(this); + } + // prevent spawn monster after success + if (getScene().getChallenge() != null && getScene().getChallenge().inProgress()) { + getScene().getScriptManager().callEvent(EventType.EVENT_ANY_MONSTER_DIE, new ScriptArgs().setParam1(this.getConfigId())); + }else if (getScene().getChallenge() == null) { + getScene().getScriptManager().callEvent(EventType.EVENT_ANY_MONSTER_DIE, new ScriptArgs().setParam1(this.getConfigId())); + } + } + // Battle Pass trigger + getScene().getPlayers().forEach(p -> p.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_MONSTER_DIE, this.getMonsterId(), 1)); + } - @Override - public SceneEntityInfo toProto() { - EntityAuthorityInfo authority = EntityAuthorityInfo.newBuilder() - .setAbilityInfo(AbilitySyncStateInfo.newBuilder()) - .setRendererChangedInfo(EntityRendererChangedInfo.newBuilder()) - .setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(this.getBornPos().toProto())) - .setBornPos(this.getBornPos().toProto()) - .build(); - - SceneEntityInfo.Builder entityInfo = SceneEntityInfo.newBuilder() - .setEntityId(getId()) - .setEntityType(ProtEntityType.PROT_ENTITY_TYPE_MONSTER) - .setMotionInfo(this.getMotionInfo()) - .addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder()) - .setEntityClientData(EntityClientData.newBuilder()) - .setEntityAuthorityInfo(authority) - .setLifeState(this.getLifeState().getValue()); - - for (Int2FloatMap.Entry entry : getFightProperties().int2FloatEntrySet()) { - if (entry.getIntKey() == 0) { - continue; - } - FightPropPair fightProp = FightPropPair.newBuilder().setPropType(entry.getIntKey()).setPropValue(entry.getFloatValue()).build(); - entityInfo.addFightPropList(fightProp); - } - - PropPair pair = PropPair.newBuilder() - .setType(PlayerProperty.PROP_LEVEL.getId()) - .setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, getLevel())) - .build(); - entityInfo.addPropList(pair); - - SceneMonsterInfo.Builder monsterInfo = SceneMonsterInfo.newBuilder() - .setMonsterId(getMonsterId()) - .setGroupId(this.getGroupId()) - .setConfigId(this.getConfigId()) - .addAllAffixList(getMonsterData().getAffix()) - .setAuthorityPeerId(getWorld().getHostPeerId()) - .setPoseId(this.getPoseId()) - .setBlockId(3001) - .setBornType(MonsterBornType.MONSTER_BORN_TYPE_DEFAULT) - .setSpecialNameId(40); - - if (getMonsterData().getDescribeData() != null) { - monsterInfo.setTitleId(getMonsterData().getDescribeData().getTitleID()); - } - - if (this.getMonsterWeaponId() > 0) { - SceneWeaponInfo weaponInfo = SceneWeaponInfo.newBuilder() - .setEntityId(this.weaponEntityId) - .setGadgetId(this.getMonsterWeaponId()) - .setAbilityInfo(AbilitySyncStateInfo.newBuilder()) - .build(); - - monsterInfo.addWeaponList(weaponInfo); - } - - entityInfo.setMonster(monsterInfo); + public void recalcStats() { + // Monster data + MonsterData data = this.getMonsterData(); - return entityInfo.build(); - } + // Get hp percent, set to 100% if none + float hpPercent = this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) <= 0 ? 1f : this.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) / this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP); + + // Clear properties + this.getFightProperties().clear(); + + // Base stats + this.setFightProperty(FightProperty.FIGHT_PROP_BASE_HP, data.getBaseHp()); + this.setFightProperty(FightProperty.FIGHT_PROP_BASE_ATTACK, data.getBaseAttack()); + this.setFightProperty(FightProperty.FIGHT_PROP_BASE_DEFENSE, data.getBaseDefense()); + + this.setFightProperty(FightProperty.FIGHT_PROP_PHYSICAL_SUB_HURT, data.getPhysicalSubHurt()); + this.setFightProperty(FightProperty.FIGHT_PROP_FIRE_SUB_HURT, .1f); + this.setFightProperty(FightProperty.FIGHT_PROP_ELEC_SUB_HURT, data.getElecSubHurt()); + this.setFightProperty(FightProperty.FIGHT_PROP_WATER_SUB_HURT, data.getWaterSubHurt()); + this.setFightProperty(FightProperty.FIGHT_PROP_GRASS_SUB_HURT, data.getGrassSubHurt()); + this.setFightProperty(FightProperty.FIGHT_PROP_WIND_SUB_HURT, data.getWindSubHurt()); + this.setFightProperty(FightProperty.FIGHT_PROP_ROCK_SUB_HURT, .1f); + this.setFightProperty(FightProperty.FIGHT_PROP_ICE_SUB_HURT, data.getIceSubHurt()); + + // Level curve + MonsterCurveData curve = GameData.getMonsterCurveDataMap().get(this.getLevel()); + if (curve != null) { + for (PropGrowCurve growCurve : data.getPropGrowCurves()) { + FightProperty prop = FightProperty.getPropByName(growCurve.getType()); + this.setFightProperty(prop, this.getFightProperty(prop) * curve.getMultByProp(growCurve.getGrowCurve())); + } + } + + // Set % stats + this.setFightProperty( + FightProperty.FIGHT_PROP_MAX_HP, + (getFightProperty(FightProperty.FIGHT_PROP_BASE_HP) * (1f + getFightProperty(FightProperty.FIGHT_PROP_HP_PERCENT))) + getFightProperty(FightProperty.FIGHT_PROP_HP) + ); + this.setFightProperty( + FightProperty.FIGHT_PROP_CUR_ATTACK, + (getFightProperty(FightProperty.FIGHT_PROP_BASE_ATTACK) * (1f + getFightProperty(FightProperty.FIGHT_PROP_ATTACK_PERCENT))) + getFightProperty(FightProperty.FIGHT_PROP_ATTACK) + ); + this.setFightProperty( + FightProperty.FIGHT_PROP_CUR_DEFENSE, + (getFightProperty(FightProperty.FIGHT_PROP_BASE_DEFENSE) * (1f + getFightProperty(FightProperty.FIGHT_PROP_DEFENSE_PERCENT))) + getFightProperty(FightProperty.FIGHT_PROP_DEFENSE) + ); + + // Set current hp + this.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * hpPercent); + } + + @Override + public SceneEntityInfo toProto() { + EntityAuthorityInfo authority = EntityAuthorityInfo.newBuilder() + .setAbilityInfo(AbilitySyncStateInfo.newBuilder()) + .setRendererChangedInfo(EntityRendererChangedInfo.newBuilder()) + .setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(this.getBornPos().toProto())) + .setBornPos(this.getBornPos().toProto()) + .build(); + + SceneEntityInfo.Builder entityInfo = SceneEntityInfo.newBuilder() + .setEntityId(getId()) + .setEntityType(ProtEntityType.PROT_ENTITY_TYPE_MONSTER) + .setMotionInfo(this.getMotionInfo()) + .addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder()) + .setEntityClientData(EntityClientData.newBuilder()) + .setEntityAuthorityInfo(authority) + .setLifeState(this.getLifeState().getValue()); + + for (Int2FloatMap.Entry entry : getFightProperties().int2FloatEntrySet()) { + if (entry.getIntKey() == 0) { + continue; + } + FightPropPair fightProp = FightPropPair.newBuilder().setPropType(entry.getIntKey()).setPropValue(entry.getFloatValue()).build(); + entityInfo.addFightPropList(fightProp); + } + + PropPair pair = PropPair.newBuilder() + .setType(PlayerProperty.PROP_LEVEL.getId()) + .setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, getLevel())) + .build(); + entityInfo.addPropList(pair); + + SceneMonsterInfo.Builder monsterInfo = SceneMonsterInfo.newBuilder() + .setMonsterId(getMonsterId()) + .setGroupId(this.getGroupId()) + .setConfigId(this.getConfigId()) + .addAllAffixList(getMonsterData().getAffix()) + .setAuthorityPeerId(getWorld().getHostPeerId()) + .setPoseId(this.getPoseId()) + .setBlockId(3001) + .setBornType(MonsterBornType.MONSTER_BORN_TYPE_DEFAULT) + .setSpecialNameId(40); + + if (getMonsterData().getDescribeData() != null) { + monsterInfo.setTitleId(getMonsterData().getDescribeData().getTitleID()); + } + + if (this.getMonsterWeaponId() > 0) { + SceneWeaponInfo weaponInfo = SceneWeaponInfo.newBuilder() + .setEntityId(this.weaponEntityId) + .setGadgetId(this.getMonsterWeaponId()) + .setAbilityInfo(AbilitySyncStateInfo.newBuilder()) + .build(); + + monsterInfo.addWeaponList(weaponInfo); + } + + entityInfo.setMonster(monsterInfo); + + return entityInfo.build(); + } } diff --git a/src/main/java/emu/grasscutter/game/entity/EntityVehicle.java b/src/main/java/emu/grasscutter/game/entity/EntityVehicle.java index 16d8b1f6f..e862469fd 100644 --- a/src/main/java/emu/grasscutter/game/entity/EntityVehicle.java +++ b/src/main/java/emu/grasscutter/game/entity/EntityVehicle.java @@ -31,104 +31,104 @@ import java.util.ArrayList; public class EntityVehicle extends EntityBaseGadget { - private final Player owner; - private final Int2FloatOpenHashMap fightProp; + private final Player owner; + private final Int2FloatOpenHashMap fightProp; - private final Position pos; - private final Position rot; + private final Position pos; + private final Position rot; - private final int pointId; - private final int gadgetId; + private final int pointId; + private final int gadgetId; - private float curStamina; - private List vehicleMembers; + private float curStamina; + private List vehicleMembers; - public EntityVehicle(Scene scene, Player player, int gadgetId, int pointId, Position pos, Position rot) { - super(scene); - this.owner = player; - this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET); - this.fightProp = new Int2FloatOpenHashMap(); - this.pos = new Position(pos); - this.rot = new Position(rot); - this.gadgetId = gadgetId; - this.pointId = pointId; - this.curStamina = 240; - this.vehicleMembers = new ArrayList(); - } + public EntityVehicle(Scene scene, Player player, int gadgetId, int pointId, Position pos, Position rot) { + super(scene); + this.owner = player; + this.id = getScene().getWorld().getNextEntityId(EntityIdType.GADGET); + this.fightProp = new Int2FloatOpenHashMap(); + this.pos = new Position(pos); + this.rot = new Position(rot); + this.gadgetId = gadgetId; + this.pointId = pointId; + this.curStamina = 240; + this.vehicleMembers = new ArrayList(); + } - @Override - public int getGadgetId() { return gadgetId; } + @Override + public int getGadgetId() { return gadgetId; } - public Player getOwner() { - return owner; - } + public Player getOwner() { + return owner; + } - public float getCurStamina() { return curStamina; } + public float getCurStamina() { return curStamina; } - public void setCurStamina(float stamina) { this.curStamina = stamina; } + public void setCurStamina(float stamina) { this.curStamina = stamina; } - public int getPointId() { return pointId; } + public int getPointId() { return pointId; } - public List getVehicleMembers() { return vehicleMembers; } + public List getVehicleMembers() { return vehicleMembers; } - @Override - public Int2FloatOpenHashMap getFightProperties() { - return fightProp; - } + @Override + public Int2FloatOpenHashMap getFightProperties() { + return fightProp; + } - @Override - public Position getPosition() { return this.pos; } + @Override + public Position getPosition() { return this.pos; } - @Override - public Position getRotation() { - return this.rot; - } - - @Override - public SceneEntityInfo toProto() { + @Override + public Position getRotation() { + return this.rot; + } - VehicleInfo vehicle = VehicleInfo.newBuilder() - .setOwnerUid(this.owner.getUid()) - .setCurStamina(getCurStamina()) - .build(); + @Override + public SceneEntityInfo toProto() { - EntityAuthorityInfo authority = EntityAuthorityInfo.newBuilder() - .setAbilityInfo(AbilitySyncStateInfo.newBuilder()) - .setRendererChangedInfo(EntityRendererChangedInfo.newBuilder()) - .setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(getPosition().toProto())) - .setBornPos(getPosition().toProto()) - .build(); + VehicleInfo vehicle = VehicleInfo.newBuilder() + .setOwnerUid(this.owner.getUid()) + .setCurStamina(getCurStamina()) + .build(); - SceneGadgetInfo.Builder gadgetInfo = SceneGadgetInfo.newBuilder() - .setGadgetId(this.getGadgetId()) - .setAuthorityPeerId(this.getOwner().getPeerId()) - .setIsEnableInteract(true) - .setVehicleInfo(vehicle); + EntityAuthorityInfo authority = EntityAuthorityInfo.newBuilder() + .setAbilityInfo(AbilitySyncStateInfo.newBuilder()) + .setRendererChangedInfo(EntityRendererChangedInfo.newBuilder()) + .setAiInfo(SceneEntityAiInfo.newBuilder().setIsAiOpen(true).setBornPos(getPosition().toProto())) + .setBornPos(getPosition().toProto()) + .build(); - SceneEntityInfo.Builder entityInfo = SceneEntityInfo.newBuilder() - .setEntityId(getId()) - .setEntityType(ProtEntityType.PROT_ENTITY_TYPE_GADGET) - .setMotionInfo(MotionInfo.newBuilder().setPos(getPosition().toProto()).setRot(getRotation().toProto()).setSpeed(Vector.newBuilder())) - .addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder()) - .setGadget(gadgetInfo) - .setEntityAuthorityInfo(authority) - .setLifeState(1); + SceneGadgetInfo.Builder gadgetInfo = SceneGadgetInfo.newBuilder() + .setGadgetId(this.getGadgetId()) + .setAuthorityPeerId(this.getOwner().getPeerId()) + .setIsEnableInteract(true) + .setVehicleInfo(vehicle); - PropPair pair = PropPair.newBuilder() - .setType(PlayerProperty.PROP_LEVEL.getId()) - .setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 47)) - .build(); + SceneEntityInfo.Builder entityInfo = SceneEntityInfo.newBuilder() + .setEntityId(getId()) + .setEntityType(ProtEntityType.PROT_ENTITY_TYPE_GADGET) + .setMotionInfo(MotionInfo.newBuilder().setPos(getPosition().toProto()).setRot(getRotation().toProto()).setSpeed(Vector.newBuilder())) + .addAnimatorParaList(AnimatorParameterValueInfoPair.newBuilder()) + .setGadget(gadgetInfo) + .setEntityAuthorityInfo(authority) + .setLifeState(1); - for (Int2FloatMap.Entry entry : getFightProperties().int2FloatEntrySet()) { - if (entry.getIntKey() == 0) { - continue; - } - FightPropPair fightProp = FightPropPair.newBuilder().setPropType(entry.getIntKey()).setPropValue(entry.getFloatValue()).build(); - entityInfo.addFightPropList(fightProp); - } + PropPair pair = PropPair.newBuilder() + .setType(PlayerProperty.PROP_LEVEL.getId()) + .setPropValue(ProtoHelper.newPropValue(PlayerProperty.PROP_LEVEL, 47)) + .build(); - entityInfo.addPropList(pair); + for (Int2FloatMap.Entry entry : getFightProperties().int2FloatEntrySet()) { + if (entry.getIntKey() == 0) { + continue; + } + FightPropPair fightProp = FightPropPair.newBuilder().setPropType(entry.getIntKey()).setPropValue(entry.getFloatValue()).build(); + entityInfo.addFightPropList(fightProp); + } - return entityInfo.build(); - } + entityInfo.addPropList(pair); + + return entityInfo.build(); + } } diff --git a/src/main/java/emu/grasscutter/game/entity/GameEntity.java b/src/main/java/emu/grasscutter/game/entity/GameEntity.java index c571f54f0..e505969c0 100644 --- a/src/main/java/emu/grasscutter/game/entity/GameEntity.java +++ b/src/main/java/emu/grasscutter/game/entity/GameEntity.java @@ -23,236 +23,236 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; public abstract class GameEntity { - protected int id; - private final Scene scene; - private SpawnDataEntry spawnEntry; - - private int blockId; - private int configId; - private int groupId; - - private MotionState moveState; - private int lastMoveSceneTimeMs; - private int lastMoveReliableSeq; - - // Abilities - private Map metaOverrideMap; - private Int2ObjectMap metaModifiers; - - public GameEntity(Scene scene) { - this.scene = scene; - this.moveState = MotionState.MOTION_STATE_NONE; - } - - public int getId() { - return this.id; - } - - public int getEntityType() { - return getId() >> 24; - } - - public World getWorld() { - return this.getScene().getWorld(); - } + protected int id; + private final Scene scene; + private SpawnDataEntry spawnEntry; - public Scene getScene() { - return this.scene; - } - - public boolean isAlive() { - return true; - } + private int blockId; + private int configId; + private int groupId; - public LifeState getLifeState() { - return isAlive() ? LifeState.LIFE_ALIVE : LifeState.LIFE_DEAD; - } - - public Map getMetaOverrideMap() { - if (this.metaOverrideMap == null) { - this.metaOverrideMap = new HashMap<>(); - } - return this.metaOverrideMap; - } - - public Int2ObjectMap getMetaModifiers() { - if (this.metaModifiers == null) { - this.metaModifiers = new Int2ObjectOpenHashMap<>(); - } - return this.metaModifiers; - } + private MotionState moveState; + private int lastMoveSceneTimeMs; + private int lastMoveReliableSeq; - public abstract Int2FloatOpenHashMap getFightProperties(); - - public abstract Position getPosition(); - - public abstract Position getRotation(); - - public MotionState getMotionState() { - return moveState; - } + // Abilities + private Map metaOverrideMap; + private Int2ObjectMap metaModifiers; - public void setMotionState(MotionState moveState) { - this.moveState = moveState; - } + public GameEntity(Scene scene) { + this.scene = scene; + this.moveState = MotionState.MOTION_STATE_NONE; + } - public int getLastMoveSceneTimeMs() { - return lastMoveSceneTimeMs; - } + public int getId() { + return this.id; + } - public void setLastMoveSceneTimeMs(int lastMoveSceneTimeMs) { - this.lastMoveSceneTimeMs = lastMoveSceneTimeMs; - } + public int getEntityType() { + return getId() >> 24; + } - public int getLastMoveReliableSeq() { - return lastMoveReliableSeq; - } + public World getWorld() { + return this.getScene().getWorld(); + } - public void setLastMoveReliableSeq(int lastMoveReliableSeq) { - this.lastMoveReliableSeq = lastMoveReliableSeq; - } - - public void setFightProperty(FightProperty prop, float value) { - this.getFightProperties().put(prop.getId(), value); - } - - private void setFightProperty(int id, float value) { - this.getFightProperties().put(id, value); - } - - public void addFightProperty(FightProperty prop, float value) { - this.getFightProperties().put(prop.getId(), getFightProperty(prop) + value); - } - - public float getFightProperty(FightProperty prop) { - return getFightProperties().getOrDefault(prop.getId(), 0f); - } - - public void addAllFightPropsToEntityInfo(SceneEntityInfo.Builder entityInfo) { - for (Int2FloatMap.Entry entry : getFightProperties().int2FloatEntrySet()) { - if (entry.getIntKey() == 0) { - continue; - } - FightPropPair fightProp = FightPropPair.newBuilder().setPropType(entry.getIntKey()).setPropValue(entry.getFloatValue()).build(); - entityInfo.addFightPropList(fightProp); - } - } - - public int getBlockId() { - return blockId; - } + public Scene getScene() { + return this.scene; + } - public void setBlockId(int blockId) { - this.blockId = blockId; - } - - public int getConfigId() { - return configId; - } + public boolean isAlive() { + return true; + } - public void setConfigId(int configId) { - this.configId = configId; - } - - public int getGroupId() { - return groupId; - } + public LifeState getLifeState() { + return isAlive() ? LifeState.LIFE_ALIVE : LifeState.LIFE_DEAD; + } - public void setGroupId(int groupId) { - this.groupId = groupId; - } - - protected MotionInfo getMotionInfo() { - MotionInfo proto = MotionInfo.newBuilder() - .setPos(getPosition().toProto()) - .setRot(getRotation().toProto()) - .setSpeed(Vector.newBuilder()) - .setState(this.getMotionState()) - .build(); - - return proto; - } + public Map getMetaOverrideMap() { + if (this.metaOverrideMap == null) { + this.metaOverrideMap = new HashMap<>(); + } + return this.metaOverrideMap; + } - public SpawnDataEntry getSpawnEntry() { - return spawnEntry; - } + public Int2ObjectMap getMetaModifiers() { + if (this.metaModifiers == null) { + this.metaModifiers = new Int2ObjectOpenHashMap<>(); + } + return this.metaModifiers; + } - public void setSpawnEntry(SpawnDataEntry spawnEntry) { - this.spawnEntry = spawnEntry; - } - - public float heal(float amount) { - if (this.getFightProperties() == null) { - return 0f; - } + public abstract Int2FloatOpenHashMap getFightProperties(); - float curHp = getFightProperty(FightProperty.FIGHT_PROP_CUR_HP); - float maxHp = getFightProperty(FightProperty.FIGHT_PROP_MAX_HP); - - if (curHp >= maxHp) { - return 0f; - } - - float healed = Math.min(maxHp - curHp, amount); - this.addFightProperty(FightProperty.FIGHT_PROP_CUR_HP, healed); - - getScene().broadcastPacket(new PacketEntityFightPropUpdateNotify(this, FightProperty.FIGHT_PROP_CUR_HP)); - - return healed; - } - - public void damage(float amount) { - damage(amount, 0); - } - - public void damage(float amount, int killerId) { - // Sanity check - if (getFightProperties() == null) { - return; - } - - // Lose hp - addFightProperty(FightProperty.FIGHT_PROP_CUR_HP, -amount); - - // Check if dead - boolean isDead = false; - if (getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) <= 0f) { - setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, 0f); - isDead = true; - } - - // Packets - this.getScene().broadcastPacket(new PacketEntityFightPropUpdateNotify(this, FightProperty.FIGHT_PROP_CUR_HP)); - - // Check if dead - if (isDead) { - getScene().killEntity(this, killerId); - } - } - - /** + public abstract Position getPosition(); + + public abstract Position getRotation(); + + public MotionState getMotionState() { + return moveState; + } + + public void setMotionState(MotionState moveState) { + this.moveState = moveState; + } + + public int getLastMoveSceneTimeMs() { + return lastMoveSceneTimeMs; + } + + public void setLastMoveSceneTimeMs(int lastMoveSceneTimeMs) { + this.lastMoveSceneTimeMs = lastMoveSceneTimeMs; + } + + public int getLastMoveReliableSeq() { + return lastMoveReliableSeq; + } + + public void setLastMoveReliableSeq(int lastMoveReliableSeq) { + this.lastMoveReliableSeq = lastMoveReliableSeq; + } + + public void setFightProperty(FightProperty prop, float value) { + this.getFightProperties().put(prop.getId(), value); + } + + private void setFightProperty(int id, float value) { + this.getFightProperties().put(id, value); + } + + public void addFightProperty(FightProperty prop, float value) { + this.getFightProperties().put(prop.getId(), getFightProperty(prop) + value); + } + + public float getFightProperty(FightProperty prop) { + return getFightProperties().getOrDefault(prop.getId(), 0f); + } + + public void addAllFightPropsToEntityInfo(SceneEntityInfo.Builder entityInfo) { + for (Int2FloatMap.Entry entry : getFightProperties().int2FloatEntrySet()) { + if (entry.getIntKey() == 0) { + continue; + } + FightPropPair fightProp = FightPropPair.newBuilder().setPropType(entry.getIntKey()).setPropValue(entry.getFloatValue()).build(); + entityInfo.addFightPropList(fightProp); + } + } + + public int getBlockId() { + return blockId; + } + + public void setBlockId(int blockId) { + this.blockId = blockId; + } + + public int getConfigId() { + return configId; + } + + public void setConfigId(int configId) { + this.configId = configId; + } + + public int getGroupId() { + return groupId; + } + + public void setGroupId(int groupId) { + this.groupId = groupId; + } + + protected MotionInfo getMotionInfo() { + MotionInfo proto = MotionInfo.newBuilder() + .setPos(getPosition().toProto()) + .setRot(getRotation().toProto()) + .setSpeed(Vector.newBuilder()) + .setState(this.getMotionState()) + .build(); + + return proto; + } + + public SpawnDataEntry getSpawnEntry() { + return spawnEntry; + } + + public void setSpawnEntry(SpawnDataEntry spawnEntry) { + this.spawnEntry = spawnEntry; + } + + public float heal(float amount) { + if (this.getFightProperties() == null) { + return 0f; + } + + float curHp = getFightProperty(FightProperty.FIGHT_PROP_CUR_HP); + float maxHp = getFightProperty(FightProperty.FIGHT_PROP_MAX_HP); + + if (curHp >= maxHp) { + return 0f; + } + + float healed = Math.min(maxHp - curHp, amount); + this.addFightProperty(FightProperty.FIGHT_PROP_CUR_HP, healed); + + getScene().broadcastPacket(new PacketEntityFightPropUpdateNotify(this, FightProperty.FIGHT_PROP_CUR_HP)); + + return healed; + } + + public void damage(float amount) { + damage(amount, 0); + } + + public void damage(float amount, int killerId) { + // Sanity check + if (getFightProperties() == null) { + return; + } + + // Lose hp + addFightProperty(FightProperty.FIGHT_PROP_CUR_HP, -amount); + + // Check if dead + boolean isDead = false; + if (getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) <= 0f) { + setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, 0f); + isDead = true; + } + + // Packets + this.getScene().broadcastPacket(new PacketEntityFightPropUpdateNotify(this, FightProperty.FIGHT_PROP_CUR_HP)); + + // Check if dead + if (isDead) { + getScene().killEntity(this, killerId); + } + } + + /** * Called when a player interacts with this entity * @param player Player that is interacting with this entity - * @param interactReq Interact request protobuf data + * @param interactReq Interact request protobuf data */ public void onInteract(Player player, GadgetInteractReq interactReq) { - + } - + /** * Called when this entity is added to the world */ - public void onCreate() { - - } - - /** + public void onCreate() { + + } + + /** * Called when this entity dies * @param killerId Entity id of the entity that killed this entity */ - public void onDeath(int killerId) { - - } - - public abstract SceneEntityInfo toProto(); + public void onDeath(int killerId) { + + } + + public abstract SceneEntityInfo toProto(); } diff --git a/src/main/java/emu/grasscutter/game/entity/gadget/GadgetChest.java b/src/main/java/emu/grasscutter/game/entity/gadget/GadgetChest.java index 1fb146240..43e6e0b80 100644 --- a/src/main/java/emu/grasscutter/game/entity/gadget/GadgetChest.java +++ b/src/main/java/emu/grasscutter/game/entity/gadget/GadgetChest.java @@ -15,51 +15,51 @@ import emu.grasscutter.server.packet.send.PacketGadgetInteractRsp; import emu.grasscutter.server.packet.send.PacketLifeStateChangeNotify; public class GadgetChest extends GadgetContent { - - public GadgetChest(EntityGadget gadget) { - super(gadget); - } - public boolean onInteract(Player player, GadgetInteractReq req) { - var chestInteractHandlerMap = getGadget().getScene().getWorld().getServer().getWorldDataSystem().getChestInteractHandlerMap(); - var handler = chestInteractHandlerMap.get(getGadget().getGadgetData().getJsonName()); - if(handler == null){ - Grasscutter.getLogger().warn("Could not found the handler of this type of Chests {}", getGadget().getGadgetData().getJsonName()); - return false; - } + public GadgetChest(EntityGadget gadget) { + super(gadget); + } - if(req.getOpType() == InterOpType.INTER_OP_TYPE_START && handler.isTwoStep()){ - player.sendPacket(new PacketGadgetInteractRsp(getGadget(), InteractType.INTERACT_TYPE_OPEN_CHEST, InterOpType.INTER_OP_TYPE_START)); - return false; - }else{ - var success = handler.onInteract(this, player); - if (!success) { - return false; - } + public boolean onInteract(Player player, GadgetInteractReq req) { + var chestInteractHandlerMap = getGadget().getScene().getWorld().getServer().getWorldDataSystem().getChestInteractHandlerMap(); + var handler = chestInteractHandlerMap.get(getGadget().getGadgetData().getJsonName()); + if (handler == null) { + Grasscutter.getLogger().warn("Could not found the handler of this type of Chests {}", getGadget().getGadgetData().getJsonName()); + return false; + } - getGadget().updateState(ScriptGadgetState.ChestOpened); - player.sendPacket(new PacketGadgetInteractRsp(this.getGadget(), InteractTypeOuterClass.InteractType.INTERACT_TYPE_OPEN_CHEST)); - - return true; - } - } + if (req.getOpType() == InterOpType.INTER_OP_TYPE_START && handler.isTwoStep()) { + player.sendPacket(new PacketGadgetInteractRsp(getGadget(), InteractType.INTERACT_TYPE_OPEN_CHEST, InterOpType.INTER_OP_TYPE_START)); + return false; + }else { + var success = handler.onInteract(this, player); + if (!success) { + return false; + } - public void onBuildProto(SceneGadgetInfo.Builder gadgetInfo) { - if(getGadget().getMetaGadget() == null){ - return; - } + getGadget().updateState(ScriptGadgetState.ChestOpened); + player.sendPacket(new PacketGadgetInteractRsp(this.getGadget(), InteractTypeOuterClass.InteractType.INTERACT_TYPE_OPEN_CHEST)); - var bossChest = getGadget().getMetaGadget().boss_chest; - if(bossChest != null){ - var players = getGadget().getScene().getPlayers().stream().map(Player::getUid).toList(); + return true; + } + } - gadgetInfo.setBossChest(BossChestInfo.newBuilder() - .setMonsterConfigId(bossChest.monster_config_id) - .setResin(bossChest.resin) - .addAllQualifyUidList(players) - .addAllRemainUidList(players) - .build()); - } + public void onBuildProto(SceneGadgetInfo.Builder gadgetInfo) { + if (getGadget().getMetaGadget() == null) { + return; + } - } + var bossChest = getGadget().getMetaGadget().boss_chest; + if (bossChest != null) { + var players = getGadget().getScene().getPlayers().stream().map(Player::getUid).toList(); + + gadgetInfo.setBossChest(BossChestInfo.newBuilder() + .setMonsterConfigId(bossChest.monster_config_id) + .setResin(bossChest.resin) + .addAllQualifyUidList(players) + .addAllRemainUidList(players) + .build()); + } + + } } diff --git a/src/main/java/emu/grasscutter/game/entity/gadget/chest/BossChestInteractHandler.java b/src/main/java/emu/grasscutter/game/entity/gadget/chest/BossChestInteractHandler.java index 3bc62f4f9..d02a3760d 100644 --- a/src/main/java/emu/grasscutter/game/entity/gadget/chest/BossChestInteractHandler.java +++ b/src/main/java/emu/grasscutter/game/entity/gadget/chest/BossChestInteractHandler.java @@ -23,7 +23,7 @@ public class BossChestInteractHandler implements ChestInteractHandler{ var monster = chest.getGadget().getMetaGadget().group.monsters.get(chest.getGadget().getMetaGadget().boss_chest.monster_config_id); var reward = worldDataManager.getRewardByBossId(monster.monster_id); - if(reward == null){ + if (reward == null) { Grasscutter.getLogger().warn("Could not found the reward of boss monster {}", monster.monster_id); return false; } diff --git a/src/main/java/emu/grasscutter/game/expedition/ExpeditionSystem.java b/src/main/java/emu/grasscutter/game/expedition/ExpeditionSystem.java index 0faca23b7..ddc0535d5 100644 --- a/src/main/java/emu/grasscutter/game/expedition/ExpeditionSystem.java +++ b/src/main/java/emu/grasscutter/game/expedition/ExpeditionSystem.java @@ -24,16 +24,16 @@ public class ExpeditionSystem extends BaseGameSystem { this.expeditionRewardData = new Int2ObjectOpenHashMap<>(); this.load(); } - - public Int2ObjectMap> getExpeditionRewardDataList() { - return expeditionRewardData; + + public Int2ObjectMap> getExpeditionRewardDataList() { + return expeditionRewardData; } public synchronized void load() { try (Reader fileReader = DataLoader.loadReader("ExpeditionReward.json")) { getExpeditionRewardDataList().clear(); List banners = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, ExpeditionRewardInfo.class).getType()); - if(banners.size() > 0) { + if (banners.size() > 0) { for (ExpeditionRewardInfo di : banners) { getExpeditionRewardDataList().put(di.getExpId(), di.getExpeditionRewardDataList()); } diff --git a/src/main/java/emu/grasscutter/game/friends/FriendsList.java b/src/main/java/emu/grasscutter/game/friends/FriendsList.java index 399406295..1b09b6cd2 100644 --- a/src/main/java/emu/grasscutter/game/friends/FriendsList.java +++ b/src/main/java/emu/grasscutter/game/friends/FriendsList.java @@ -15,243 +15,243 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; public class FriendsList extends BasePlayerManager { - private final Int2ObjectMap friends; - private final Int2ObjectMap pendingFriends; - - private boolean loaded = false; - - public FriendsList(Player player) { - super(player); - this.friends = new Int2ObjectOpenHashMap(); - this.pendingFriends = new Int2ObjectOpenHashMap(); - } - - public boolean hasLoaded() { - return loaded; - } - - public synchronized Int2ObjectMap getFriends() { - return friends; - } - - public synchronized Int2ObjectMap getPendingFriends() { - return this.pendingFriends; - } - - public synchronized boolean isFriendsWith(int uid) { - return this.getFriends().containsKey(uid); - } - - private synchronized Friendship getFriendshipById(int id) { - Friendship friendship = this.getFriends().get(id); - if (friendship == null) { - friendship = this.getPendingFriendById(id); - } - return friendship; - } - - private synchronized Friendship getFriendById(int id) { - return this.getFriends().get(id); - } - - private synchronized Friendship getPendingFriendById(int id) { - return this.getPendingFriends().get(id); - } - - public void addFriend(Friendship friendship) { - getFriends().put(friendship.getFriendId(), friendship); - } - - public void addPendingFriend(Friendship friendship) { - getPendingFriends().put(friendship.getFriendId(), friendship); - } - - public synchronized void handleFriendRequest(int targetUid, DealAddFriendResultType result) { - // Check if player has sent friend request - Friendship myFriendship = this.getPendingFriendById(targetUid); - if (myFriendship == null) { - return; - } - - // Make sure asker cant do anything - if (myFriendship.getAskerId() == this.getPlayer().getUid()) { - return; - } + private final Int2ObjectMap friends; + private final Int2ObjectMap pendingFriends; - Player target = getPlayer().getSession().getServer().getPlayerByUid(targetUid, true); - if (target == null) { - return; // Should never happen - } + private boolean loaded = false; - // Get target's friendship - Friendship theirFriendship = null; - if (target.isOnline()) { - theirFriendship = target.getFriendsList().getPendingFriendById(this.getPlayer().getUid()); - } else { - theirFriendship = DatabaseHelper.getReverseFriendship(myFriendship); - } + public FriendsList(Player player) { + super(player); + this.friends = new Int2ObjectOpenHashMap(); + this.pendingFriends = new Int2ObjectOpenHashMap(); + } - if (theirFriendship == null) { - // They dont have us on their friends list anymore, rip - this.getPendingFriends().remove(myFriendship.getOwnerId()); - myFriendship.delete(); - return; - } + public boolean hasLoaded() { + return loaded; + } - // Handle - if (result == DealAddFriendResultType.DEAL_ADD_FRIEND_RESULT_TYPE_ACCEPT) { // Request accepted - myFriendship.setIsFriend(true); - theirFriendship.setIsFriend(true); - - this.getPendingFriends().remove(myFriendship.getOwnerId()); - this.addFriend(myFriendship); - - if (target.isOnline()) { - target.getFriendsList().getPendingFriends().remove(this.getPlayer().getUid()); - target.getFriendsList().addFriend(theirFriendship); - } - - myFriendship.save(); - theirFriendship.save(); - } else { // Request declined - // Delete from my pending friends - this.getPendingFriends().remove(myFriendship.getOwnerId()); - myFriendship.delete(); - // Delete from target uid - if (target.isOnline()) { - theirFriendship = target.getFriendsList().getPendingFriendById(this.getPlayer().getUid()); - } - theirFriendship.delete(); - } - - // Packet - this.getPlayer().sendPacket(new PacketDealAddFriendRsp(targetUid, result)); - } - - public synchronized void deleteFriend(int targetUid) { - Friendship myFriendship = this.getFriendById(targetUid); - if (myFriendship == null) { - return; - } - - this.getFriends().remove(targetUid); - myFriendship.delete(); - - Friendship theirFriendship = null; - Player friend = myFriendship.getFriendProfile().getPlayer(); - if (friend != null) { - // Friend online - theirFriendship = friend.getFriendsList().getFriendById(this.getPlayer().getUid()); - if (theirFriendship != null) { - friend.getFriendsList().getFriends().remove(theirFriendship.getFriendId()); - theirFriendship.delete(); - friend.sendPacket(new PacketDeleteFriendNotify(theirFriendship.getFriendId())); - } - } else { - // Friend offline - theirFriendship = DatabaseHelper.getReverseFriendship(myFriendship); - if (theirFriendship != null) { - theirFriendship.delete(); - } - } - - // Packet - this.getPlayer().sendPacket(new PacketDeleteFriendRsp(targetUid)); - } - - public synchronized void sendFriendRequest(int targetUid) { - Player target = getPlayer().getSession().getServer().getPlayerByUid(targetUid, true); + public synchronized Int2ObjectMap getFriends() { + return friends; + } - if (target == null || target == this.getPlayer()) { - return; - } - - // Check if friend already exists - if (this.getPendingFriends().containsKey(targetUid) || this.getFriends().containsKey(targetUid)) { - return; - } - - // Create friendships - Friendship myFriendship = new Friendship(getPlayer(), target, getPlayer()); - Friendship theirFriendship = new Friendship(target, getPlayer(), getPlayer()); - - // Add pending lists - this.addPendingFriend(myFriendship); + public synchronized Int2ObjectMap getPendingFriends() { + return this.pendingFriends; + } - if (target.isOnline() && target.getFriendsList().hasLoaded()) { - target.getFriendsList().addPendingFriend(theirFriendship); - target.sendPacket(new PacketAskAddFriendNotify(theirFriendship)); - } - - // Save - myFriendship.save(); - theirFriendship.save(); - - // Packets - this.getPlayer().sendPacket(new PacketAskAddFriendRsp(targetUid)); - } - - /** Gets total amount of potential friends - * */ - public int getFullFriendCount() { - return this.getPendingFriends().size() + this.getFriends().size(); - } + public synchronized boolean isFriendsWith(int uid) { + return this.getFriends().containsKey(uid); + } - public synchronized void loadFromDatabase() { - if (this.hasLoaded()) { - return; - } - - // Get friendships from the db - List friendships = DatabaseHelper.getFriends(player); - friendships.forEach(this::loadFriendFromDatabase); - - // Set loaded flag - this.loaded = true; - } - - private void loadFriendFromDatabase(Friendship friendship) { - // Set friendship owner - friendship.setOwner(getPlayer()); + private synchronized Friendship getFriendshipById(int id) { + Friendship friendship = this.getFriends().get(id); + if (friendship == null) { + friendship = this.getPendingFriendById(id); + } + return friendship; + } - // Check if friend is online - Player friend = getPlayer().getSession().getServer().getPlayerByUid(friendship.getFriendProfile().getUid()); - if (friend != null) { - // Set friend to online mode - friendship.setFriendProfile(friend); - - // Update our status on friend's client if theyre online - if (friend.getFriendsList().hasLoaded()) { - Friendship theirFriendship = friend.getFriendsList().getFriendshipById(getPlayer().getUid()); - if (theirFriendship != null) { - // Update friend profile - theirFriendship.setFriendProfile(getPlayer()); - } else { - // They dont have us on their friends list anymore, rip - friendship.delete(); - return; - } - } - } - - // Finally, load to our friends list - if (friendship.isFriend()) { - getFriends().put(friendship.getFriendId(), friendship); - } else { - getPendingFriends().put(friendship.getFriendId(), friendship); - // TODO - Hacky fix to force client to see a notification for a friendship - if (getPendingFriends().size() == 1) { - getPlayer().getSession().send(new PacketAskAddFriendNotify(friendship)); - } - } - } - - public void save() { - // Update all our friends - List friendships = DatabaseHelper.getReverseFriends(getPlayer()); - for (Friendship friend : friendships) { - friend.setFriendProfile(this.getPlayer()); - friend.save(); - } - } + private synchronized Friendship getFriendById(int id) { + return this.getFriends().get(id); + } + + private synchronized Friendship getPendingFriendById(int id) { + return this.getPendingFriends().get(id); + } + + public void addFriend(Friendship friendship) { + getFriends().put(friendship.getFriendId(), friendship); + } + + public void addPendingFriend(Friendship friendship) { + getPendingFriends().put(friendship.getFriendId(), friendship); + } + + public synchronized void handleFriendRequest(int targetUid, DealAddFriendResultType result) { + // Check if player has sent friend request + Friendship myFriendship = this.getPendingFriendById(targetUid); + if (myFriendship == null) { + return; + } + + // Make sure asker cant do anything + if (myFriendship.getAskerId() == this.getPlayer().getUid()) { + return; + } + + Player target = getPlayer().getSession().getServer().getPlayerByUid(targetUid, true); + if (target == null) { + return; // Should never happen + } + + // Get target's friendship + Friendship theirFriendship = null; + if (target.isOnline()) { + theirFriendship = target.getFriendsList().getPendingFriendById(this.getPlayer().getUid()); + } else { + theirFriendship = DatabaseHelper.getReverseFriendship(myFriendship); + } + + if (theirFriendship == null) { + // They dont have us on their friends list anymore, rip + this.getPendingFriends().remove(myFriendship.getOwnerId()); + myFriendship.delete(); + return; + } + + // Handle + if (result == DealAddFriendResultType.DEAL_ADD_FRIEND_RESULT_TYPE_ACCEPT) { // Request accepted + myFriendship.setIsFriend(true); + theirFriendship.setIsFriend(true); + + this.getPendingFriends().remove(myFriendship.getOwnerId()); + this.addFriend(myFriendship); + + if (target.isOnline()) { + target.getFriendsList().getPendingFriends().remove(this.getPlayer().getUid()); + target.getFriendsList().addFriend(theirFriendship); + } + + myFriendship.save(); + theirFriendship.save(); + } else { // Request declined + // Delete from my pending friends + this.getPendingFriends().remove(myFriendship.getOwnerId()); + myFriendship.delete(); + // Delete from target uid + if (target.isOnline()) { + theirFriendship = target.getFriendsList().getPendingFriendById(this.getPlayer().getUid()); + } + theirFriendship.delete(); + } + + // Packet + this.getPlayer().sendPacket(new PacketDealAddFriendRsp(targetUid, result)); + } + + public synchronized void deleteFriend(int targetUid) { + Friendship myFriendship = this.getFriendById(targetUid); + if (myFriendship == null) { + return; + } + + this.getFriends().remove(targetUid); + myFriendship.delete(); + + Friendship theirFriendship = null; + Player friend = myFriendship.getFriendProfile().getPlayer(); + if (friend != null) { + // Friend online + theirFriendship = friend.getFriendsList().getFriendById(this.getPlayer().getUid()); + if (theirFriendship != null) { + friend.getFriendsList().getFriends().remove(theirFriendship.getFriendId()); + theirFriendship.delete(); + friend.sendPacket(new PacketDeleteFriendNotify(theirFriendship.getFriendId())); + } + } else { + // Friend offline + theirFriendship = DatabaseHelper.getReverseFriendship(myFriendship); + if (theirFriendship != null) { + theirFriendship.delete(); + } + } + + // Packet + this.getPlayer().sendPacket(new PacketDeleteFriendRsp(targetUid)); + } + + public synchronized void sendFriendRequest(int targetUid) { + Player target = getPlayer().getSession().getServer().getPlayerByUid(targetUid, true); + + if (target == null || target == this.getPlayer()) { + return; + } + + // Check if friend already exists + if (this.getPendingFriends().containsKey(targetUid) || this.getFriends().containsKey(targetUid)) { + return; + } + + // Create friendships + Friendship myFriendship = new Friendship(getPlayer(), target, getPlayer()); + Friendship theirFriendship = new Friendship(target, getPlayer(), getPlayer()); + + // Add pending lists + this.addPendingFriend(myFriendship); + + if (target.isOnline() && target.getFriendsList().hasLoaded()) { + target.getFriendsList().addPendingFriend(theirFriendship); + target.sendPacket(new PacketAskAddFriendNotify(theirFriendship)); + } + + // Save + myFriendship.save(); + theirFriendship.save(); + + // Packets + this.getPlayer().sendPacket(new PacketAskAddFriendRsp(targetUid)); + } + + /** Gets total amount of potential friends + * */ + public int getFullFriendCount() { + return this.getPendingFriends().size() + this.getFriends().size(); + } + + public synchronized void loadFromDatabase() { + if (this.hasLoaded()) { + return; + } + + // Get friendships from the db + List friendships = DatabaseHelper.getFriends(player); + friendships.forEach(this::loadFriendFromDatabase); + + // Set loaded flag + this.loaded = true; + } + + private void loadFriendFromDatabase(Friendship friendship) { + // Set friendship owner + friendship.setOwner(getPlayer()); + + // Check if friend is online + Player friend = getPlayer().getSession().getServer().getPlayerByUid(friendship.getFriendProfile().getUid()); + if (friend != null) { + // Set friend to online mode + friendship.setFriendProfile(friend); + + // Update our status on friend's client if theyre online + if (friend.getFriendsList().hasLoaded()) { + Friendship theirFriendship = friend.getFriendsList().getFriendshipById(getPlayer().getUid()); + if (theirFriendship != null) { + // Update friend profile + theirFriendship.setFriendProfile(getPlayer()); + } else { + // They dont have us on their friends list anymore, rip + friendship.delete(); + return; + } + } + } + + // Finally, load to our friends list + if (friendship.isFriend()) { + getFriends().put(friendship.getFriendId(), friendship); + } else { + getPendingFriends().put(friendship.getFriendId(), friendship); + // TODO - Hacky fix to force client to see a notification for a friendship + if (getPendingFriends().size() == 1) { + getPlayer().getSession().send(new PacketAskAddFriendNotify(friendship)); + } + } + } + + public void save() { + // Update all our friends + List friendships = DatabaseHelper.getReverseFriends(getPlayer()); + for (Friendship friend : friendships) { + friend.setFriendProfile(this.getPlayer()); + friend.save(); + } + } } diff --git a/src/main/java/emu/grasscutter/game/gacha/GachaBanner.java b/src/main/java/emu/grasscutter/game/gacha/GachaBanner.java index 4b8bd95c2..17d957387 100644 --- a/src/main/java/emu/grasscutter/game/gacha/GachaBanner.java +++ b/src/main/java/emu/grasscutter/game/gacha/GachaBanner.java @@ -10,164 +10,164 @@ import emu.grasscutter.utils.Utils; import lombok.Getter; public class GachaBanner { - @Getter private int gachaType; - @Getter private int scheduleId; - @Getter private String prefabPath; - @Getter private String previewPrefabPath; - @Getter private String titlePath; - private int costItemId = 0; - private int costItemAmount = 1; - private int costItemId10 = 0; - private int costItemAmount10 = 10; - @Getter private int beginTime; - @Getter private int endTime; - @Getter private int sortId; - @Getter private int gachaTimesLimit = Integer.MAX_VALUE; - private int[] rateUpItems4 = {}; - private int[] rateUpItems5 = {}; - @Getter private int[] fallbackItems3 = {11301, 11302, 11306, 12301, 12302, 12305, 13303, 14301, 14302, 14304, 15301, 15302, 15304}; - @Getter private int[] fallbackItems4Pool1 = {1014, 1020, 1023, 1024, 1025, 1027, 1031, 1032, 1034, 1036, 1039, 1043, 1044, 1045, 1048, 1053, 1055, 1056, 1064}; - @Getter private int[] fallbackItems4Pool2 = {11401, 11402, 11403, 11405, 12401, 12402, 12403, 12405, 13401, 13407, 14401, 14402, 14403, 14409, 15401, 15402, 15403, 15405}; - @Getter private int[] fallbackItems5Pool1 = {1003, 1016, 1042, 1035, 1041}; - @Getter private int[] fallbackItems5Pool2 = {11501, 11502, 12501, 12502, 13502, 13505, 14501, 14502, 15501, 15502}; - @Getter private boolean removeC6FromPool = false; - @Getter private boolean autoStripRateUpFromFallback = true; - private int[][] weights4 = {{1,510}, {8,510}, {10,10000}}; - private int[][] weights5 = {{1,75}, {73,150}, {90,10000}}; - private int[][] poolBalanceWeights4 = {{1,255}, {17,255}, {21,10455}}; - private int[][] poolBalanceWeights5 = {{1,30}, {147,150}, {181,10230}}; - private int eventChance4 = 50; // Chance to win a featured event item - private int eventChance5 = 50; // Chance to win a featured event item - @Getter private BannerType bannerType = BannerType.STANDARD; + @Getter private int gachaType; + @Getter private int scheduleId; + @Getter private String prefabPath; + @Getter private String previewPrefabPath; + @Getter private String titlePath; + private int costItemId = 0; + private int costItemAmount = 1; + private int costItemId10 = 0; + private int costItemAmount10 = 10; + @Getter private int beginTime; + @Getter private int endTime; + @Getter private int sortId; + @Getter private int gachaTimesLimit = Integer.MAX_VALUE; + private int[] rateUpItems4 = {}; + private int[] rateUpItems5 = {}; + @Getter private int[] fallbackItems3 = {11301, 11302, 11306, 12301, 12302, 12305, 13303, 14301, 14302, 14304, 15301, 15302, 15304}; + @Getter private int[] fallbackItems4Pool1 = {1014, 1020, 1023, 1024, 1025, 1027, 1031, 1032, 1034, 1036, 1039, 1043, 1044, 1045, 1048, 1053, 1055, 1056, 1064}; + @Getter private int[] fallbackItems4Pool2 = {11401, 11402, 11403, 11405, 12401, 12402, 12403, 12405, 13401, 13407, 14401, 14402, 14403, 14409, 15401, 15402, 15403, 15405}; + @Getter private int[] fallbackItems5Pool1 = {1003, 1016, 1042, 1035, 1041}; + @Getter private int[] fallbackItems5Pool2 = {11501, 11502, 12501, 12502, 13502, 13505, 14501, 14502, 15501, 15502}; + @Getter private boolean removeC6FromPool = false; + @Getter private boolean autoStripRateUpFromFallback = true; + private int[][] weights4 = {{1,510}, {8,510}, {10,10000}}; + private int[][] weights5 = {{1,75}, {73,150}, {90,10000}}; + private int[][] poolBalanceWeights4 = {{1,255}, {17,255}, {21,10455}}; + private int[][] poolBalanceWeights5 = {{1,30}, {147,150}, {181,10230}}; + private int eventChance4 = 50; // Chance to win a featured event item + private int eventChance5 = 50; // Chance to win a featured event item + @Getter private BannerType bannerType = BannerType.STANDARD; - // Kinda wanna deprecate these but they're in people's configs - private int[] rateUpItems1 = {}; - private int[] rateUpItems2 = {}; - private int eventChance = -1; - private int costItem = 0; - @Getter private int wishMaxProgress = 2; + // Kinda wanna deprecate these but they're in people's configs + private int[] rateUpItems1 = {}; + private int[] rateUpItems2 = {}; + private int eventChance = -1; + private int costItem = 0; + @Getter private int wishMaxProgress = 2; - public ItemParamData getCost(int numRolls) { - return switch (numRolls) { - case 10 -> new ItemParamData((costItemId10 > 0) ? costItemId10 : getCostItem(), costItemAmount10); - default -> new ItemParamData(getCostItem(), costItemAmount * numRolls); - }; - } + public ItemParamData getCost(int numRolls) { + return switch (numRolls) { + case 10 -> new ItemParamData((costItemId10 > 0) ? costItemId10 : getCostItem(), costItemAmount10); + default -> new ItemParamData(getCostItem(), costItemAmount * numRolls); + }; + } - public int getCostItem() { - return (costItem > 0) ? costItem : costItemId; - } + public int getCostItem() { + return (costItem > 0) ? costItem : costItemId; + } - public int[] getRateUpItems4() { - return (rateUpItems2.length > 0) ? rateUpItems2 : rateUpItems4; - } - public int[] getRateUpItems5() { - return (rateUpItems1.length > 0) ? rateUpItems1 : rateUpItems5; - } + public int[] getRateUpItems4() { + return (rateUpItems2.length > 0) ? rateUpItems2 : rateUpItems4; + } + public int[] getRateUpItems5() { + return (rateUpItems1.length > 0) ? rateUpItems1 : rateUpItems5; + } - public boolean hasEpitomized() { - return bannerType.equals(BannerType.WEAPON); - } + public boolean hasEpitomized() { + return bannerType.equals(BannerType.WEAPON); + } - public int getWeight(int rarity, int pity) { - return switch(rarity) { - case 4 -> Utils.lerp(pity, weights4); - default -> Utils.lerp(pity, weights5); - }; - } + public int getWeight(int rarity, int pity) { + return switch (rarity) { + case 4 -> Utils.lerp(pity, weights4); + default -> Utils.lerp(pity, weights5); + }; + } - public int getPoolBalanceWeight(int rarity, int pity) { - return switch(rarity) { - case 4 -> Utils.lerp(pity, poolBalanceWeights4); - default -> Utils.lerp(pity, poolBalanceWeights5); - }; - } + public int getPoolBalanceWeight(int rarity, int pity) { + return switch (rarity) { + case 4 -> Utils.lerp(pity, poolBalanceWeights4); + default -> Utils.lerp(pity, poolBalanceWeights5); + }; + } - public int getEventChance(int rarity) { - return switch(rarity) { - case 4 -> eventChance4; - default -> (eventChance > -1) ? eventChance : eventChance5; - }; - } - - public GachaInfo toProto(Player player) { - // TODO: use other Nonce/key insteadof session key to ensure the overall security for the player - String sessionKey = player.getAccount().getSessionKey(); - - String record = "http" + (HTTP_ENCRYPTION.useInRouting ? "s" : "") + "://" - + lr(HTTP_INFO.accessAddress, HTTP_INFO.bindAddress) + ":" - + lr(HTTP_INFO.accessPort, HTTP_INFO.bindPort) - + "/gacha?s=" + sessionKey + "&gachaType=" + gachaType; - String details = "http" + (HTTP_ENCRYPTION.useInRouting ? "s" : "") + "://" - + lr(HTTP_INFO.accessAddress, HTTP_INFO.bindAddress) + ":" - + lr(HTTP_INFO.accessPort, HTTP_INFO.bindPort) - + "/gacha/details?s=" + sessionKey + "&scheduleId=" + scheduleId; + public int getEventChance(int rarity) { + return switch (rarity) { + case 4 -> eventChance4; + default -> (eventChance > -1) ? eventChance : eventChance5; + }; + } - // Grasscutter.getLogger().info("record = " + record); - ItemParamData costItem1 = this.getCost(1); - ItemParamData costItem10 = this.getCost(10); - PlayerGachaBannerInfo gachaInfo = player.getGachaInfo().getBannerInfo(this); - int leftGachaTimes = switch(gachaTimesLimit) { - case Integer.MAX_VALUE -> Integer.MAX_VALUE; - default -> Math.max(gachaTimesLimit - gachaInfo.getTotalPulls(), 0); - }; - GachaInfo.Builder info = GachaInfo.newBuilder() - .setGachaType(this.getGachaType()) - .setScheduleId(this.getScheduleId()) - .setBeginTime(this.getBeginTime()) - .setEndTime(this.getEndTime()) - .setCostItemId(costItem1.getId()) - .setCostItemNum(costItem1.getCount()) - .setTenCostItemId(costItem10.getId()) - .setTenCostItemNum(costItem10.getCount()) - .setGachaPrefabPath(this.getPrefabPath()) - .setGachaPreviewPrefabPath(this.getPreviewPrefabPath()) - .setGachaProbUrl(details) - .setGachaProbUrlOversea(details) - .setGachaRecordUrl(record) - .setGachaRecordUrlOversea(record) - .setLeftGachaTimes(leftGachaTimes) - .setGachaTimesLimit(gachaTimesLimit) - .setGachaSortId(this.getSortId()); + public GachaInfo toProto(Player player) { + // TODO: use other Nonce/key insteadof session key to ensure the overall security for the player + String sessionKey = player.getAccount().getSessionKey(); - if(hasEpitomized()) { - info.setWishItemId(gachaInfo.getWishItemId()) - .setWishProgress(gachaInfo.getFailedChosenItemPulls()) - .setWishMaxProgress(this.getWishMaxProgress()); - } + String record = "http" + (HTTP_ENCRYPTION.useInRouting ? "s" : "") + "://" + + lr(HTTP_INFO.accessAddress, HTTP_INFO.bindAddress) + ":" + + lr(HTTP_INFO.accessPort, HTTP_INFO.bindPort) + + "/gacha?s=" + sessionKey + "&gachaType=" + gachaType; + String details = "http" + (HTTP_ENCRYPTION.useInRouting ? "s" : "") + "://" + + lr(HTTP_INFO.accessAddress, HTTP_INFO.bindAddress) + ":" + + lr(HTTP_INFO.accessPort, HTTP_INFO.bindPort) + + "/gacha/details?s=" + sessionKey + "&scheduleId=" + scheduleId; - if (this.getTitlePath() != null) { - info.setTitleTextmap(this.getTitlePath()); - } - - if (this.getRateUpItems5().length > 0) { - GachaUpInfo.Builder upInfo = GachaUpInfo.newBuilder().setItemParentType(1); - - for (int id : getRateUpItems5()) { - upInfo.addItemIdList(id); - info.addDisplayUp5ItemList(id); - } - - info.addGachaUpInfoList(upInfo); - } - - if (this.getRateUpItems4().length > 0) { - GachaUpInfo.Builder upInfo = GachaUpInfo.newBuilder().setItemParentType(2); - - for (int id : getRateUpItems4()) { - upInfo.addItemIdList(id); - if (info.getDisplayUp4ItemListCount() == 0) { - info.addDisplayUp4ItemList(id); - } - } - - info.addGachaUpInfoList(upInfo); - } - - return info.build(); - } - - public enum BannerType { - STANDARD, EVENT, WEAPON; - } + // Grasscutter.getLogger().info("record = " + record); + ItemParamData costItem1 = this.getCost(1); + ItemParamData costItem10 = this.getCost(10); + PlayerGachaBannerInfo gachaInfo = player.getGachaInfo().getBannerInfo(this); + int leftGachaTimes = switch (gachaTimesLimit) { + case Integer.MAX_VALUE -> Integer.MAX_VALUE; + default -> Math.max(gachaTimesLimit - gachaInfo.getTotalPulls(), 0); + }; + GachaInfo.Builder info = GachaInfo.newBuilder() + .setGachaType(this.getGachaType()) + .setScheduleId(this.getScheduleId()) + .setBeginTime(this.getBeginTime()) + .setEndTime(this.getEndTime()) + .setCostItemId(costItem1.getId()) + .setCostItemNum(costItem1.getCount()) + .setTenCostItemId(costItem10.getId()) + .setTenCostItemNum(costItem10.getCount()) + .setGachaPrefabPath(this.getPrefabPath()) + .setGachaPreviewPrefabPath(this.getPreviewPrefabPath()) + .setGachaProbUrl(details) + .setGachaProbUrlOversea(details) + .setGachaRecordUrl(record) + .setGachaRecordUrlOversea(record) + .setLeftGachaTimes(leftGachaTimes) + .setGachaTimesLimit(gachaTimesLimit) + .setGachaSortId(this.getSortId()); + + if (hasEpitomized()) { + info.setWishItemId(gachaInfo.getWishItemId()) + .setWishProgress(gachaInfo.getFailedChosenItemPulls()) + .setWishMaxProgress(this.getWishMaxProgress()); + } + + if (this.getTitlePath() != null) { + info.setTitleTextmap(this.getTitlePath()); + } + + if (this.getRateUpItems5().length > 0) { + GachaUpInfo.Builder upInfo = GachaUpInfo.newBuilder().setItemParentType(1); + + for (int id : getRateUpItems5()) { + upInfo.addItemIdList(id); + info.addDisplayUp5ItemList(id); + } + + info.addGachaUpInfoList(upInfo); + } + + if (this.getRateUpItems4().length > 0) { + GachaUpInfo.Builder upInfo = GachaUpInfo.newBuilder().setItemParentType(2); + + for (int id : getRateUpItems4()) { + upInfo.addItemIdList(id); + if (info.getDisplayUp4ItemListCount() == 0) { + info.addDisplayUp4ItemList(id); + } + } + + info.addGachaUpInfoList(upInfo); + } + + return info.build(); + } + + public enum BannerType { + STANDARD, EVENT, WEAPON; + } } diff --git a/src/main/java/emu/grasscutter/game/gacha/GachaSystem.java b/src/main/java/emu/grasscutter/game/gacha/GachaSystem.java index c1c591584..1d24c0b79 100644 --- a/src/main/java/emu/grasscutter/game/gacha/GachaSystem.java +++ b/src/main/java/emu/grasscutter/game/gacha/GachaSystem.java @@ -48,400 +48,400 @@ import it.unimi.dsi.fastutil.ints.IntList; import org.greenrobot.eventbus.Subscribe; public class GachaSystem extends BaseGameSystem { - private final Int2ObjectMap gachaBanners; - private WatchService watchService; + private final Int2ObjectMap gachaBanners; + private WatchService watchService; - private static final int starglitterId = 221; - private static final int stardustId = 222; - private int[] fallbackItems4Pool2Default = {11401, 11402, 11403, 11405, 12401, 12402, 12403, 12405, 13401, 13407, 14401, 14402, 14403, 14409, 15401, 15402, 15403, 15405}; - private int[] fallbackItems5Pool2Default = {11501, 11502, 12501, 12502, 13502, 13505, 14501, 14502, 15501, 15502}; + private static final int starglitterId = 221; + private static final int stardustId = 222; + private int[] fallbackItems4Pool2Default = {11401, 11402, 11403, 11405, 12401, 12402, 12403, 12405, 13401, 13407, 14401, 14402, 14403, 14409, 15401, 15402, 15403, 15405}; + private int[] fallbackItems5Pool2Default = {11501, 11502, 12501, 12502, 13502, 13505, 14501, 14502, 15501, 15502}; - public GachaSystem(GameServer server) { - super(server); - this.gachaBanners = new Int2ObjectOpenHashMap<>(); - this.load(); - this.startWatcher(server); - } + public GachaSystem(GameServer server) { + super(server); + this.gachaBanners = new Int2ObjectOpenHashMap<>(); + this.load(); + this.startWatcher(server); + } - public Int2ObjectMap getGachaBanners() { - return gachaBanners; - } + public Int2ObjectMap getGachaBanners() { + return gachaBanners; + } - public int randomRange(int min, int max) { // Both are inclusive - return ThreadLocalRandom.current().nextInt(max - min + 1) + min; - } + public int randomRange(int min, int max) { // Both are inclusive + return ThreadLocalRandom.current().nextInt(max - min + 1) + min; + } - public int getRandom(int[] array) { - return array[randomRange(0, array.length - 1)]; - } + public int getRandom(int[] array) { + return array[randomRange(0, array.length - 1)]; + } - public synchronized void load() { - try (Reader fileReader = DataLoader.loadReader("Banners.json")) { - getGachaBanners().clear(); - List banners = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, GachaBanner.class).getType()); - if(banners.size() > 0) { - for (GachaBanner banner : banners) { - getGachaBanners().put(banner.getScheduleId(), banner); - } - Grasscutter.getLogger().debug("Banners successfully loaded."); - } else { - Grasscutter.getLogger().error("Unable to load banners. Banners size is 0."); - } - } catch (Exception e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } - } + public synchronized void load() { + try (Reader fileReader = DataLoader.loadReader("Banners.json")) { + getGachaBanners().clear(); + List banners = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, GachaBanner.class).getType()); + if (banners.size() > 0) { + for (GachaBanner banner : banners) { + getGachaBanners().put(banner.getScheduleId(), banner); + } + Grasscutter.getLogger().debug("Banners successfully loaded."); + } else { + Grasscutter.getLogger().error("Unable to load banners. Banners size is 0."); + } + } catch (Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } - private class BannerPools { - public int[] rateUpItems4; - public int[] rateUpItems5; - public int[] fallbackItems4Pool1; - public int[] fallbackItems4Pool2; - public int[] fallbackItems5Pool1; - public int[] fallbackItems5Pool2; + private class BannerPools { + public int[] rateUpItems4; + public int[] rateUpItems5; + public int[] fallbackItems4Pool1; + public int[] fallbackItems4Pool2; + public int[] fallbackItems5Pool1; + public int[] fallbackItems5Pool2; - public BannerPools(GachaBanner banner) { - rateUpItems4 = banner.getRateUpItems4(); - rateUpItems5 = banner.getRateUpItems5(); - fallbackItems4Pool1 = banner.getFallbackItems4Pool1(); - fallbackItems4Pool2 = banner.getFallbackItems4Pool2(); - fallbackItems5Pool1 = banner.getFallbackItems5Pool1(); - fallbackItems5Pool2 = banner.getFallbackItems5Pool2(); + public BannerPools(GachaBanner banner) { + rateUpItems4 = banner.getRateUpItems4(); + rateUpItems5 = banner.getRateUpItems5(); + fallbackItems4Pool1 = banner.getFallbackItems4Pool1(); + fallbackItems4Pool2 = banner.getFallbackItems4Pool2(); + fallbackItems5Pool1 = banner.getFallbackItems5Pool1(); + fallbackItems5Pool2 = banner.getFallbackItems5Pool2(); - if (banner.isAutoStripRateUpFromFallback()) { - fallbackItems4Pool1 = Utils.setSubtract(fallbackItems4Pool1, rateUpItems4); - fallbackItems4Pool2 = Utils.setSubtract(fallbackItems4Pool2, rateUpItems4); - fallbackItems5Pool1 = Utils.setSubtract(fallbackItems5Pool1, rateUpItems5); - fallbackItems5Pool2 = Utils.setSubtract(fallbackItems5Pool2, rateUpItems5); - } - } + if (banner.isAutoStripRateUpFromFallback()) { + fallbackItems4Pool1 = Utils.setSubtract(fallbackItems4Pool1, rateUpItems4); + fallbackItems4Pool2 = Utils.setSubtract(fallbackItems4Pool2, rateUpItems4); + fallbackItems5Pool1 = Utils.setSubtract(fallbackItems5Pool1, rateUpItems5); + fallbackItems5Pool2 = Utils.setSubtract(fallbackItems5Pool2, rateUpItems5); + } + } - public void removeFromAllPools(int[] itemIds) { - rateUpItems4 = Utils.setSubtract(rateUpItems4, itemIds); - rateUpItems5 = Utils.setSubtract(rateUpItems5, itemIds); - fallbackItems4Pool1 = Utils.setSubtract(fallbackItems4Pool1, itemIds); - fallbackItems4Pool2 = Utils.setSubtract(fallbackItems4Pool2, itemIds); - fallbackItems5Pool1 = Utils.setSubtract(fallbackItems5Pool1, itemIds); - fallbackItems5Pool2 = Utils.setSubtract(fallbackItems5Pool2, itemIds); - } - } + public void removeFromAllPools(int[] itemIds) { + rateUpItems4 = Utils.setSubtract(rateUpItems4, itemIds); + rateUpItems5 = Utils.setSubtract(rateUpItems5, itemIds); + fallbackItems4Pool1 = Utils.setSubtract(fallbackItems4Pool1, itemIds); + fallbackItems4Pool2 = Utils.setSubtract(fallbackItems4Pool2, itemIds); + fallbackItems5Pool1 = Utils.setSubtract(fallbackItems5Pool1, itemIds); + fallbackItems5Pool2 = Utils.setSubtract(fallbackItems5Pool2, itemIds); + } + } - private synchronized int checkPlayerAvatarConstellationLevel(Player player, int itemId) { // Maybe this would be useful in the Player class? - ItemData itemData = GameData.getItemDataMap().get(itemId); - if ((itemData == null) || (itemData.getMaterialType() != MaterialType.MATERIAL_AVATAR)){ - return -2; // Not an Avatar - } - Avatar avatar = player.getAvatars().getAvatarById((itemId % 1000) + 10000000); - if (avatar == null) { - return -1; // Doesn't have - } - // Constellation - int constLevel = avatar.getCoreProudSkillLevel(); - GameItem constItem = player.getInventory().getInventoryTab(ItemType.ITEM_MATERIAL).getItemById(itemId + 100); - constLevel += (constItem == null)? 0 : constItem.getCount(); - return constLevel; - } + private synchronized int checkPlayerAvatarConstellationLevel(Player player, int itemId) { // Maybe this would be useful in the Player class? + ItemData itemData = GameData.getItemDataMap().get(itemId); + if ((itemData == null) || (itemData.getMaterialType() != MaterialType.MATERIAL_AVATAR)) { + return -2; // Not an Avatar + } + Avatar avatar = player.getAvatars().getAvatarById((itemId % 1000) + 10000000); + if (avatar == null) { + return -1; // Doesn't have + } + // Constellation + int constLevel = avatar.getCoreProudSkillLevel(); + GameItem constItem = player.getInventory().getInventoryTab(ItemType.ITEM_MATERIAL).getItemById(itemId + 100); + constLevel += (constItem == null)? 0 : constItem.getCount(); + return constLevel; + } - private synchronized int[] removeC6FromPool(int[] itemPool, Player player) { - IntList temp = new IntArrayList(); - for (int itemId : itemPool) { - if (checkPlayerAvatarConstellationLevel(player, itemId) < 6) { - temp.add(itemId); - } - } - return temp.toIntArray(); - } + private synchronized int[] removeC6FromPool(int[] itemPool, Player player) { + IntList temp = new IntArrayList(); + for (int itemId : itemPool) { + if (checkPlayerAvatarConstellationLevel(player, itemId) < 6) { + temp.add(itemId); + } + } + return temp.toIntArray(); + } - private synchronized int drawRoulette(int[] weights, int cutoff) { - // This follows the logic laid out in issue #183 - // Simple weighted selection with an upper bound for the roll that cuts off trailing entries - // All weights must be >= 0 - int total = 0; - for (int weight : weights) { - if (weight < 0) { - throw new IllegalArgumentException("Weights must be non-negative!"); - } - total += weight; - } - int roll = ThreadLocalRandom.current().nextInt((total < cutoff)? total : cutoff); - int subTotal = 0; - for (int i=0; i= 0 + int total = 0; + for (int weight : weights) { + if (weight < 0) { + throw new IllegalArgumentException("Weights must be non-negative!"); + } + total += weight; + } + int roll = ThreadLocalRandom.current().nextInt((total < cutoff)? total : cutoff); + int subTotal = 0; + for (int i=0; i= pityPool2)? 1 : 0) { // Larger weight must come first for the hard cutoff to function correctly - case 1 -> 1 + drawRoulette(new int[] {pityPool1, pityPool2}, 10000); - default -> 2 - drawRoulette(new int[] {pityPool2, pityPool1}, 10000); - }; - return switch (chosenPool) { - case 1: - gachaInfo.setPityPool(rarity, 1, 0); - yield getRandom(fallback1); - default: - gachaInfo.setPityPool(rarity, 2, 0); - yield getRandom(fallback2); - }; - } - } + private synchronized int doFallbackRarePull(int[] fallback1, int[] fallback2, int rarity, GachaBanner banner, PlayerGachaBannerInfo gachaInfo) { + if (fallback1.length < 1) { + if (fallback2.length < 1) { + return getRandom((rarity==5)? fallbackItems5Pool2Default : fallbackItems4Pool2Default); + } else { + return getRandom(fallback2); + } + } else if (fallback2.length < 1) { + return getRandom(fallback1); + } else { // Both pools are possible, use the pool balancer + int pityPool1 = banner.getPoolBalanceWeight(rarity, gachaInfo.getPityPool(rarity, 1)); + int pityPool2 = banner.getPoolBalanceWeight(rarity, gachaInfo.getPityPool(rarity, 2)); + int chosenPool = switch ((pityPool1 >= pityPool2)? 1 : 0) { // Larger weight must come first for the hard cutoff to function correctly + case 1 -> 1 + drawRoulette(new int[] {pityPool1, pityPool2}, 10000); + default -> 2 - drawRoulette(new int[] {pityPool2, pityPool1}, 10000); + }; + return switch (chosenPool) { + case 1: + gachaInfo.setPityPool(rarity, 1, 0); + yield getRandom(fallback1); + default: + gachaInfo.setPityPool(rarity, 2, 0); + yield getRandom(fallback2); + }; + } + } - private synchronized int doRarePull(int[] featured, int[] fallback1, int[] fallback2, int rarity, GachaBanner banner, PlayerGachaBannerInfo gachaInfo) { - int itemId = 0; - boolean epitomized = (banner.hasEpitomized()) && (rarity == 5) && (gachaInfo.getWishItemId() != 0); - boolean pityEpitomized = (gachaInfo.getFailedChosenItemPulls() >= banner.getWishMaxProgress()); // Maximum fate points reached - boolean pityFeatured = (gachaInfo.getFailedFeaturedItemPulls(rarity) >= 1); // Lost previous coinflip - boolean rollFeatured = (this.randomRange(1, 100) <= banner.getEventChance(rarity)); // Won this coinflip - boolean pullFeatured = pityFeatured || rollFeatured; + private synchronized int doRarePull(int[] featured, int[] fallback1, int[] fallback2, int rarity, GachaBanner banner, PlayerGachaBannerInfo gachaInfo) { + int itemId = 0; + boolean epitomized = (banner.hasEpitomized()) && (rarity == 5) && (gachaInfo.getWishItemId() != 0); + boolean pityEpitomized = (gachaInfo.getFailedChosenItemPulls() >= banner.getWishMaxProgress()); // Maximum fate points reached + boolean pityFeatured = (gachaInfo.getFailedFeaturedItemPulls(rarity) >= 1); // Lost previous coinflip + boolean rollFeatured = (this.randomRange(1, 100) <= banner.getEventChance(rarity)); // Won this coinflip + boolean pullFeatured = pityFeatured || rollFeatured; - if (epitomized && pityEpitomized) { // Auto pick item when epitomized points reached - gachaInfo.setFailedFeaturedItemPulls(rarity, 0); // Epitomized item will always be a featured one - itemId = gachaInfo.getWishItemId(); - } else { - if (pullFeatured && (featured.length > 0)) { - gachaInfo.setFailedFeaturedItemPulls(rarity, 0); - itemId = getRandom(featured); - } else { - gachaInfo.addFailedFeaturedItemPulls(rarity, 1); // This could be moved into doFallbackRarePull but having it here makes it clearer - itemId = doFallbackRarePull(fallback1, fallback2, rarity, banner, gachaInfo); - } - } + if (epitomized && pityEpitomized) { // Auto pick item when epitomized points reached + gachaInfo.setFailedFeaturedItemPulls(rarity, 0); // Epitomized item will always be a featured one + itemId = gachaInfo.getWishItemId(); + } else { + if (pullFeatured && (featured.length > 0)) { + gachaInfo.setFailedFeaturedItemPulls(rarity, 0); + itemId = getRandom(featured); + } else { + gachaInfo.addFailedFeaturedItemPulls(rarity, 1); // This could be moved into doFallbackRarePull but having it here makes it clearer + itemId = doFallbackRarePull(fallback1, fallback2, rarity, banner, gachaInfo); + } + } - if (epitomized) { - if(itemId == gachaInfo.getWishItemId()) { // Reset epitomized points when got wished item - gachaInfo.setFailedChosenItemPulls(0); - } else { // Add epitomized points if not get wished item - gachaInfo.addFailedChosenItemPulls(1); - } - } - return itemId; - } + if (epitomized) { + if (itemId == gachaInfo.getWishItemId()) { // Reset epitomized points when got wished item + gachaInfo.setFailedChosenItemPulls(0); + } else { // Add epitomized points if not get wished item + gachaInfo.addFailedChosenItemPulls(1); + } + } + return itemId; + } - private synchronized int doPull(GachaBanner banner, PlayerGachaBannerInfo gachaInfo, BannerPools pools) { - // Pre-increment all pity pools (yes this makes all calculations assume 1-indexed pity) - gachaInfo.incPityAll(); + private synchronized int doPull(GachaBanner banner, PlayerGachaBannerInfo gachaInfo, BannerPools pools) { + // Pre-increment all pity pools (yes this makes all calculations assume 1-indexed pity) + gachaInfo.incPityAll(); - int[] weights = {banner.getWeight(5, gachaInfo.getPity5()), banner.getWeight(4, gachaInfo.getPity4()), 10000}; - int levelWon = 5 - drawRoulette(weights, 10000); + int[] weights = {banner.getWeight(5, gachaInfo.getPity5()), banner.getWeight(4, gachaInfo.getPity4()), 10000}; + int levelWon = 5 - drawRoulette(weights, 10000); - return switch (levelWon) { - case 5: - gachaInfo.setPity5(0); - yield doRarePull(pools.rateUpItems5, pools.fallbackItems5Pool1, pools.fallbackItems5Pool2, 5, banner, gachaInfo); - case 4: - gachaInfo.setPity4(0); - yield doRarePull(pools.rateUpItems4, pools.fallbackItems4Pool1, pools.fallbackItems4Pool2, 4, banner, gachaInfo); - default: - yield getRandom(banner.getFallbackItems3()); - }; - } + return switch (levelWon) { + case 5: + gachaInfo.setPity5(0); + yield doRarePull(pools.rateUpItems5, pools.fallbackItems5Pool1, pools.fallbackItems5Pool2, 5, banner, gachaInfo); + case 4: + gachaInfo.setPity4(0); + yield doRarePull(pools.rateUpItems4, pools.fallbackItems4Pool1, pools.fallbackItems4Pool2, 4, banner, gachaInfo); + default: + yield getRandom(banner.getFallbackItems3()); + }; + } - public synchronized void doPulls(Player player, int scheduleId, int times) { - // Sanity check - if (times != 10 && times != 1) { - player.sendPacket(new PacketDoGachaRsp(Retcode.RET_GACHA_INVALID_TIMES)); - return; - } - Inventory inventory = player.getInventory(); - if (inventory.getInventoryTab(ItemType.ITEM_WEAPON).getSize() + times > inventory.getInventoryTab(ItemType.ITEM_WEAPON).getMaxCapacity()) { - player.sendPacket(new PacketDoGachaRsp(Retcode.RET_ITEM_EXCEED_LIMIT)); - return; - } + public synchronized void doPulls(Player player, int scheduleId, int times) { + // Sanity check + if (times != 10 && times != 1) { + player.sendPacket(new PacketDoGachaRsp(Retcode.RET_GACHA_INVALID_TIMES)); + return; + } + Inventory inventory = player.getInventory(); + if (inventory.getInventoryTab(ItemType.ITEM_WEAPON).getSize() + times > inventory.getInventoryTab(ItemType.ITEM_WEAPON).getMaxCapacity()) { + player.sendPacket(new PacketDoGachaRsp(Retcode.RET_ITEM_EXCEED_LIMIT)); + return; + } - // Get banner - GachaBanner banner = this.getGachaBanners().get(scheduleId); - if (banner == null) { - player.sendPacket(new PacketDoGachaRsp()); - return; - } + // Get banner + GachaBanner banner = this.getGachaBanners().get(scheduleId); + if (banner == null) { + player.sendPacket(new PacketDoGachaRsp()); + return; + } - // Check against total limit - PlayerGachaBannerInfo gachaInfo = player.getGachaInfo().getBannerInfo(banner); - int gachaTimesLimit = banner.getGachaTimesLimit(); - if (gachaTimesLimit != Integer.MAX_VALUE && (gachaInfo.getTotalPulls() + times) > gachaTimesLimit) { - player.sendPacket(new PacketDoGachaRsp(Retcode.RET_GACHA_TIMES_LIMIT)); - return; - } + // Check against total limit + PlayerGachaBannerInfo gachaInfo = player.getGachaInfo().getBannerInfo(banner); + int gachaTimesLimit = banner.getGachaTimesLimit(); + if (gachaTimesLimit != Integer.MAX_VALUE && (gachaInfo.getTotalPulls() + times) > gachaTimesLimit) { + player.sendPacket(new PacketDoGachaRsp(Retcode.RET_GACHA_TIMES_LIMIT)); + return; + } - // Spend currency - ItemParamData cost = banner.getCost(times); - if (cost.getCount() > 0 && !inventory.payItem(cost)) { - player.sendPacket(new PacketDoGachaRsp(Retcode.RET_GACHA_COST_ITEM_NOT_ENOUGH)); - return; - } + // Spend currency + ItemParamData cost = banner.getCost(times); + if (cost.getCount() > 0 && !inventory.payItem(cost)) { + player.sendPacket(new PacketDoGachaRsp(Retcode.RET_GACHA_COST_ITEM_NOT_ENOUGH)); + return; + } - // Add to character - gachaInfo.addTotalPulls(times); - BannerPools pools = new BannerPools(banner); - List list = new ArrayList<>(); - int stardust = 0, starglitter = 0; + // Add to character + gachaInfo.addTotalPulls(times); + BannerPools pools = new BannerPools(banner); + List list = new ArrayList<>(); + int stardust = 0, starglitter = 0; - if (banner.isRemoveC6FromPool()) { // The ultimate form of pity (non-vanilla) - pools.rateUpItems4 = removeC6FromPool(pools.rateUpItems4, player); - pools.rateUpItems5 = removeC6FromPool(pools.rateUpItems5, player); - pools.fallbackItems4Pool1 = removeC6FromPool(pools.fallbackItems4Pool1, player); - pools.fallbackItems4Pool2 = removeC6FromPool(pools.fallbackItems4Pool2, player); - pools.fallbackItems5Pool1 = removeC6FromPool(pools.fallbackItems5Pool1, player); - pools.fallbackItems5Pool2 = removeC6FromPool(pools.fallbackItems5Pool2, player); - } + if (banner.isRemoveC6FromPool()) { // The ultimate form of pity (non-vanilla) + pools.rateUpItems4 = removeC6FromPool(pools.rateUpItems4, player); + pools.rateUpItems5 = removeC6FromPool(pools.rateUpItems5, player); + pools.fallbackItems4Pool1 = removeC6FromPool(pools.fallbackItems4Pool1, player); + pools.fallbackItems4Pool2 = removeC6FromPool(pools.fallbackItems4Pool2, player); + pools.fallbackItems5Pool1 = removeC6FromPool(pools.fallbackItems5Pool1, player); + pools.fallbackItems5Pool2 = removeC6FromPool(pools.fallbackItems5Pool2, player); + } - for (int i = 0; i < times; i++) { - // Roll - int itemId = doPull(banner, gachaInfo, pools); - ItemData itemData = GameData.getItemDataMap().get(itemId); - if (itemData == null) { - continue; // Maybe we should bail out if an item fails instead of rolling the rest? - } + for (int i = 0; i < times; i++) { + // Roll + int itemId = doPull(banner, gachaInfo, pools); + ItemData itemData = GameData.getItemDataMap().get(itemId); + if (itemData == null) { + continue; // Maybe we should bail out if an item fails instead of rolling the rest? + } - // Write gacha record - GachaRecord gachaRecord = new GachaRecord(itemId, player.getUid(), banner.getGachaType()); - DatabaseHelper.saveGachaRecord(gachaRecord); + // Write gacha record + GachaRecord gachaRecord = new GachaRecord(itemId, player.getUid(), banner.getGachaType()); + DatabaseHelper.saveGachaRecord(gachaRecord); - // Create gacha item - GachaItem.Builder gachaItem = GachaItem.newBuilder(); - int addStardust = 0, addStarglitter = 0; - boolean isTransferItem = false; + // Create gacha item + GachaItem.Builder gachaItem = GachaItem.newBuilder(); + int addStardust = 0, addStarglitter = 0; + boolean isTransferItem = false; - // Const check - int constellation = checkPlayerAvatarConstellationLevel(player, itemId); - switch (constellation) { - case -2: // Is weapon - switch (itemData.getRankLevel()) { - case 5 -> addStarglitter = 10; - case 4 -> addStarglitter = 2; - default -> addStardust = 15; - } - break; - case -1: // New character - gachaItem.setIsGachaItemNew(true); - break; - default: - if (constellation >= 6) { // C6, give consolation starglitter - addStarglitter = (itemData.getRankLevel()==5)? 25 : 5; - } else { // C0-C5, give constellation item - if (banner.isRemoveC6FromPool() && constellation == 5) { // New C6, remove it from the pools so we don't get C7 in a 10pull - pools.removeFromAllPools(new int[] {itemId}); - } - addStarglitter = (itemData.getRankLevel()==5)? 10 : 2; - int constItemId = itemId + 100; - GameItem constItem = inventory.getInventoryTab(ItemType.ITEM_MATERIAL).getItemById(constItemId); - gachaItem.addTransferItems(GachaTransferItem.newBuilder().setItem(ItemParam.newBuilder().setItemId(constItemId).setCount(1)).setIsTransferItemNew(constItem == null)); - inventory.addItem(constItemId, 1); - } - isTransferItem = true; - break; - } + // Const check + int constellation = checkPlayerAvatarConstellationLevel(player, itemId); + switch (constellation) { + case -2: // Is weapon + switch (itemData.getRankLevel()) { + case 5 -> addStarglitter = 10; + case 4 -> addStarglitter = 2; + default -> addStardust = 15; + } + break; + case -1: // New character + gachaItem.setIsGachaItemNew(true); + break; + default: + if (constellation >= 6) { // C6, give consolation starglitter + addStarglitter = (itemData.getRankLevel()==5)? 25 : 5; + } else { // C0-C5, give constellation item + if (banner.isRemoveC6FromPool() && constellation == 5) { // New C6, remove it from the pools so we don't get C7 in a 10pull + pools.removeFromAllPools(new int[] {itemId}); + } + addStarglitter = (itemData.getRankLevel()==5)? 10 : 2; + int constItemId = itemId + 100; + GameItem constItem = inventory.getInventoryTab(ItemType.ITEM_MATERIAL).getItemById(constItemId); + gachaItem.addTransferItems(GachaTransferItem.newBuilder().setItem(ItemParam.newBuilder().setItemId(constItemId).setCount(1)).setIsTransferItemNew(constItem == null)); + inventory.addItem(constItemId, 1); + } + isTransferItem = true; + break; + } - // Create item - GameItem item = new GameItem(itemData); - gachaItem.setGachaItem(item.toItemParam()); - inventory.addItem(item); + // Create item + GameItem item = new GameItem(itemData); + gachaItem.setGachaItem(item.toItemParam()); + inventory.addItem(item); - stardust += addStardust; - starglitter += addStarglitter; + stardust += addStardust; + starglitter += addStarglitter; - if (addStardust > 0) { - gachaItem.addTokenItemList(ItemParam.newBuilder().setItemId(stardustId).setCount(addStardust)); - } - if (addStarglitter > 0) { - ItemParam starglitterParam = ItemParam.newBuilder().setItemId(starglitterId).setCount(addStarglitter).build(); - if (isTransferItem) { - gachaItem.addTransferItems(GachaTransferItem.newBuilder().setItem(starglitterParam)); - } - gachaItem.addTokenItemList(starglitterParam); - } + if (addStardust > 0) { + gachaItem.addTokenItemList(ItemParam.newBuilder().setItemId(stardustId).setCount(addStardust)); + } + if (addStarglitter > 0) { + ItemParam starglitterParam = ItemParam.newBuilder().setItemId(starglitterId).setCount(addStarglitter).build(); + if (isTransferItem) { + gachaItem.addTransferItems(GachaTransferItem.newBuilder().setItem(starglitterParam)); + } + gachaItem.addTokenItemList(starglitterParam); + } - list.add(gachaItem.build()); - } + list.add(gachaItem.build()); + } - // Add stardust/starglitter - if (stardust > 0) { - inventory.addItem(stardustId, stardust); - } - if (starglitter > 0) { - inventory.addItem(starglitterId, starglitter); - } + // Add stardust/starglitter + if (stardust > 0) { + inventory.addItem(stardustId, stardust); + } + if (starglitter > 0) { + inventory.addItem(starglitterId, starglitter); + } - // Packets - player.sendPacket(new PacketDoGachaRsp(banner, list, gachaInfo)); + // Packets + player.sendPacket(new PacketDoGachaRsp(banner, list, gachaInfo)); - // Battle Pass trigger - player.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_GACHA_NUM, 0, times); - } + // Battle Pass trigger + player.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_GACHA_NUM, 0, times); + } - private synchronized void startWatcher(GameServer server) { - if(this.watchService == null) { - try { - this.watchService = FileSystems.getDefault().newWatchService(); - Path path = new File(DATA()).toPath(); - path.register(watchService, new WatchEvent.Kind[]{StandardWatchEventKinds.ENTRY_MODIFY}, SensitivityWatchEventModifier.HIGH); - } catch (Exception e) { - Grasscutter.getLogger().error("Unable to load the Gacha Manager Watch Service. If ServerOptions.watchGacha is true it will not auto-reload"); - e.printStackTrace(); - } - } else { - Grasscutter.getLogger().error("Cannot reinitialise watcher "); - } - } + private synchronized void startWatcher(GameServer server) { + if (this.watchService == null) { + try { + this.watchService = FileSystems.getDefault().newWatchService(); + Path path = new File(DATA()).toPath(); + path.register(watchService, new WatchEvent.Kind[]{StandardWatchEventKinds.ENTRY_MODIFY}, SensitivityWatchEventModifier.HIGH); + } catch (Exception e) { + Grasscutter.getLogger().error("Unable to load the Gacha Manager Watch Service. If ServerOptions.watchGacha is true it will not auto-reload"); + e.printStackTrace(); + } + } else { + Grasscutter.getLogger().error("Cannot reinitialise watcher "); + } + } - @Subscribe - public synchronized void watchBannerJson(GameServerTickEvent tickEvent) { - if(GAME_OPTIONS.watchGachaConfig) { - try { - WatchKey watchKey = watchService.take(); + @Subscribe + public synchronized void watchBannerJson(GameServerTickEvent tickEvent) { + if (GAME_OPTIONS.watchGachaConfig) { + try { + WatchKey watchKey = watchService.take(); - for (WatchEvent event : watchKey.pollEvents()) { - final Path changed = (Path) event.context(); - if (changed.endsWith("Banners.json")) { - Grasscutter.getLogger().info("Change detected with banners.json. Reloading gacha config"); - this.load(); - } - } + for (WatchEvent event : watchKey.pollEvents()) { + final Path changed = (Path) event.context(); + if (changed.endsWith("Banners.json")) { + Grasscutter.getLogger().info("Change detected with banners.json. Reloading gacha config"); + this.load(); + } + } - boolean valid = watchKey.reset(); - if (!valid) { - Grasscutter.getLogger().error("Unable to reset Gacha Manager Watch Key. Auto-reload of banners.json will no longer work."); - return; - } - } catch (Exception e) { - e.printStackTrace(); - } - } - } + boolean valid = watchKey.reset(); + if (!valid) { + Grasscutter.getLogger().error("Unable to reset Gacha Manager Watch Key. Auto-reload of banners.json will no longer work."); + return; + } + } catch (Exception e) { + e.printStackTrace(); + } + } + } - private synchronized GetGachaInfoRsp createProto(Player player) { - GetGachaInfoRsp.Builder proto = GetGachaInfoRsp.newBuilder().setGachaRandom(12345); + private synchronized GetGachaInfoRsp createProto(Player player) { + GetGachaInfoRsp.Builder proto = GetGachaInfoRsp.newBuilder().setGachaRandom(12345); - long currentTime = System.currentTimeMillis() / 1000L; + long currentTime = System.currentTimeMillis() / 1000L; - for (GachaBanner banner : getGachaBanners().values()) { - if ((banner.getEndTime() >= currentTime && banner.getBeginTime() <= currentTime) || (banner.getBannerType() == BannerType.STANDARD)) - { - proto.addGachaInfoList(banner.toProto(player)); - } - } + for (GachaBanner banner : getGachaBanners().values()) { + if ((banner.getEndTime() >= currentTime && banner.getBeginTime() <= currentTime) || (banner.getBannerType() == BannerType.STANDARD)) + { + proto.addGachaInfoList(banner.toProto(player)); + } + } - return proto.build(); - } + return proto.build(); + } - public GetGachaInfoRsp toProto(Player player) { - return createProto(player); - } + public GetGachaInfoRsp toProto(Player player) { + return createProto(player); + } } diff --git a/src/main/java/emu/grasscutter/game/inventory/Inventory.java b/src/main/java/emu/grasscutter/game/inventory/Inventory.java index b2ee9aebf..23a833edb 100644 --- a/src/main/java/emu/grasscutter/game/inventory/Inventory.java +++ b/src/main/java/emu/grasscutter/game/inventory/Inventory.java @@ -33,199 +33,199 @@ import it.unimi.dsi.fastutil.longs.Long2ObjectMap; import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap; public class Inventory extends BasePlayerManager implements Iterable { - private final Long2ObjectMap store; - private final Int2ObjectMap inventoryTypes; - - public Inventory(Player player) { - super(player); - - this.store = new Long2ObjectOpenHashMap<>(); - this.inventoryTypes = new Int2ObjectOpenHashMap<>(); - - this.createInventoryTab(ItemType.ITEM_WEAPON, new EquipInventoryTab(INVENTORY_LIMITS.weapons)); - this.createInventoryTab(ItemType.ITEM_RELIQUARY, new EquipInventoryTab(INVENTORY_LIMITS.relics)); - this.createInventoryTab(ItemType.ITEM_MATERIAL, new MaterialInventoryTab(INVENTORY_LIMITS.materials)); - this.createInventoryTab(ItemType.ITEM_FURNITURE, new MaterialInventoryTab(INVENTORY_LIMITS.furniture)); - } + private final Long2ObjectMap store; + private final Int2ObjectMap inventoryTypes; - public AvatarStorage getAvatarStorage() { - return this.getPlayer().getAvatars(); - } + public Inventory(Player player) { + super(player); - public Long2ObjectMap getItems() { - return store; - } - - public Int2ObjectMap getInventoryTypes() { - return inventoryTypes; - } - - public InventoryTab getInventoryTab(ItemType type) { - return getInventoryTypes().get(type.getValue()); - } - - public void createInventoryTab(ItemType type, InventoryTab tab) { - this.getInventoryTypes().put(type.getValue(), tab); - } - - public GameItem getItemByGuid(long id) { - return this.getItems().get(id); - } - - public boolean addItem(int itemId) { - return addItem(itemId, 1); - } - - public boolean addItem(int itemId, int count) { + this.store = new Long2ObjectOpenHashMap<>(); + this.inventoryTypes = new Int2ObjectOpenHashMap<>(); + + this.createInventoryTab(ItemType.ITEM_WEAPON, new EquipInventoryTab(INVENTORY_LIMITS.weapons)); + this.createInventoryTab(ItemType.ITEM_RELIQUARY, new EquipInventoryTab(INVENTORY_LIMITS.relics)); + this.createInventoryTab(ItemType.ITEM_MATERIAL, new MaterialInventoryTab(INVENTORY_LIMITS.materials)); + this.createInventoryTab(ItemType.ITEM_FURNITURE, new MaterialInventoryTab(INVENTORY_LIMITS.furniture)); + } + + public AvatarStorage getAvatarStorage() { + return this.getPlayer().getAvatars(); + } + + public Long2ObjectMap getItems() { + return store; + } + + public Int2ObjectMap getInventoryTypes() { + return inventoryTypes; + } + + public InventoryTab getInventoryTab(ItemType type) { + return getInventoryTypes().get(type.getValue()); + } + + public void createInventoryTab(ItemType type, InventoryTab tab) { + this.getInventoryTypes().put(type.getValue(), tab); + } + + public GameItem getItemByGuid(long id) { + return this.getItems().get(id); + } + + public boolean addItem(int itemId) { + return addItem(itemId, 1); + } + + public boolean addItem(int itemId, int count) { return addItem(itemId, count, null); } - - public boolean addItem(int itemId, int count, ActionReason reason) { - ItemData itemData = GameData.getItemDataMap().get(itemId); - - if (itemData == null) { - return false; - } - - GameItem item = new GameItem(itemData, count); - - return addItem(item, reason); - } - - public boolean addItem(GameItem item) { - GameItem result = putItem(item); - - if (result != null) { - getPlayer().getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_OBTAIN_MATERIAL_NUM, result.getItemId(), result.getCount()); - getPlayer().sendPacket(new PacketStoreItemChangeNotify(result)); - return true; - } - - return false; - } - - public boolean addItem(GameItem item, ActionReason reason) { - boolean result = addItem(item); - - if (result && reason != null) { - getPlayer().sendPacket(new PacketItemAddHintNotify(item, reason)); - } - - return result; - } - public boolean addItem(GameItem item, ActionReason reason, boolean forceNotify) { - boolean result = addItem(item); + public boolean addItem(int itemId, int count, ActionReason reason) { + ItemData itemData = GameData.getItemDataMap().get(itemId); - if (reason != null && (forceNotify || result)) { - getPlayer().sendPacket(new PacketItemAddHintNotify(item, reason)); - } + if (itemData == null) { + return false; + } - return result; - } - - public boolean addItem(ItemParamData itemParam) { + GameItem item = new GameItem(itemData, count); + + return addItem(item, reason); + } + + public boolean addItem(GameItem item) { + GameItem result = putItem(item); + + if (result != null) { + getPlayer().getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_OBTAIN_MATERIAL_NUM, result.getItemId(), result.getCount()); + getPlayer().sendPacket(new PacketStoreItemChangeNotify(result)); + return true; + } + + return false; + } + + public boolean addItem(GameItem item, ActionReason reason) { + boolean result = addItem(item); + + if (result && reason != null) { + getPlayer().sendPacket(new PacketItemAddHintNotify(item, reason)); + } + + return result; + } + + public boolean addItem(GameItem item, ActionReason reason, boolean forceNotify) { + boolean result = addItem(item); + + if (reason != null && (forceNotify || result)) { + getPlayer().sendPacket(new PacketItemAddHintNotify(item, reason)); + } + + return result; + } + + public boolean addItem(ItemParamData itemParam) { return addItem(itemParam, null); } - - public boolean addItem(ItemParamData itemParam, ActionReason reason) { - if (itemParam == null) return false; + + public boolean addItem(ItemParamData itemParam, ActionReason reason) { + if (itemParam == null) return false; return addItem(itemParam.getId(), itemParam.getCount(), reason); } - - public void addItems(Collection items) { - this.addItems(items, null); - } - - public void addItems(Collection items, ActionReason reason) { - List changedItems = new LinkedList<>(); - - for (GameItem item : items) { - GameItem result = putItem(item); - - if (result != null) { - getPlayer().getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_OBTAIN_MATERIAL_NUM, result.getItemId(), result.getCount()); - changedItems.add(result); - } - } - - if (changedItems.size() == 0) { - return; - } - - if (reason != null) { - getPlayer().sendPacket(new PacketItemAddHintNotify(changedItems, reason)); - } - - getPlayer().sendPacket(new PacketStoreItemChangeNotify(changedItems)); - } - - public void addItemParams(Collection items) { - addItems(items.stream().map(param -> new GameItem(param.getItemId(), param.getCount())).toList(), null); - } - - public void addItemParamDatas(Collection items) { - addItemParamDatas(items, null); - } - - public void addItemParamDatas(Collection items, ActionReason reason) { - addItems(items.stream().map(param -> new GameItem(param.getItemId(), param.getCount())).toList(), reason); - } - - private synchronized GameItem putItem(GameItem item) { - // Dont add items that dont have a valid item definition. - if (item.getItemData() == null) { - return null; - } - - // Add item to inventory store - ItemType type = item.getItemData().getItemType(); - InventoryTab tab = getInventoryTab(type); - - // Add - switch (type) { - case ITEM_WEAPON: - case ITEM_RELIQUARY: - if (tab.getSize() >= tab.getMaxCapacity()) { - return null; - } - // Duplicates cause problems - item.setCount(Math.max(item.getCount(), 1)); - // Adds to inventory + + public void addItems(Collection items) { + this.addItems(items, null); + } + + public void addItems(Collection items, ActionReason reason) { + List changedItems = new LinkedList<>(); + + for (GameItem item : items) { + GameItem result = putItem(item); + + if (result != null) { + getPlayer().getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_OBTAIN_MATERIAL_NUM, result.getItemId(), result.getCount()); + changedItems.add(result); + } + } + + if (changedItems.size() == 0) { + return; + } + + if (reason != null) { + getPlayer().sendPacket(new PacketItemAddHintNotify(changedItems, reason)); + } + + getPlayer().sendPacket(new PacketStoreItemChangeNotify(changedItems)); + } + + public void addItemParams(Collection items) { + addItems(items.stream().map(param -> new GameItem(param.getItemId(), param.getCount())).toList(), null); + } + + public void addItemParamDatas(Collection items) { + addItemParamDatas(items, null); + } + + public void addItemParamDatas(Collection items, ActionReason reason) { + addItems(items.stream().map(param -> new GameItem(param.getItemId(), param.getCount())).toList(), reason); + } + + private synchronized GameItem putItem(GameItem item) { + // Dont add items that dont have a valid item definition. + if (item.getItemData() == null) { + return null; + } + + // Add item to inventory store + ItemType type = item.getItemData().getItemType(); + InventoryTab tab = getInventoryTab(type); + + // Add + switch (type) { + case ITEM_WEAPON: + case ITEM_RELIQUARY: + if (tab.getSize() >= tab.getMaxCapacity()) { + return null; + } + // Duplicates cause problems + item.setCount(Math.max(item.getCount(), 1)); + // Adds to inventory this.putItem(item, tab); - // Set ownership and save to db - item.save(); - return item; - case ITEM_VIRTUAL: - // Handle - this.addVirtualItem(item.getItemId(), item.getCount()); - return item; + // Set ownership and save to db + item.save(); + return item; + case ITEM_VIRTUAL: + // Handle + this.addVirtualItem(item.getItemId(), item.getCount()); + return item; default: switch (item.getItemData().getMaterialType()) { case MATERIAL_ADSORBATE: - this.player.getEnergyManager().handlePickupElemBall(item); - return null; - case MATERIAL_AVATAR: - // Get avatar id - int avatarId = (item.getItemId() % 1000) + 10000000; - // Dont let people give themselves extra main characters - if (avatarId == GameConstants.MAIN_CHARACTER_MALE || avatarId == GameConstants.MAIN_CHARACTER_FEMALE) { - return null; - } - // Add avatar - AvatarData avatarData = GameData.getAvatarDataMap().get(avatarId); - if (avatarData != null && !this.player.getAvatars().hasAvatar(avatarId)) { - this.player.addAvatar(new Avatar(avatarData)); - } - return null; - case MATERIAL_FLYCLOAK: - AvatarFlycloakData flycloakData = GameData.getAvatarFlycloakDataMap().get(item.getItemId()); - if (flycloakData != null && !this.player.getFlyCloakList().contains(item.getItemId())) { - this.player.addFlycloak(item.getItemId()); - } - return null; - case MATERIAL_COSTUME: - AvatarCostumeData costumeData = GameData.getAvatarCostumeDataItemIdMap().get(item.getItemId()); + this.player.getEnergyManager().handlePickupElemBall(item); + return null; + case MATERIAL_AVATAR: + // Get avatar id + int avatarId = (item.getItemId() % 1000) + 10000000; + // Dont let people give themselves extra main characters + if (avatarId == GameConstants.MAIN_CHARACTER_MALE || avatarId == GameConstants.MAIN_CHARACTER_FEMALE) { + return null; + } + // Add avatar + AvatarData avatarData = GameData.getAvatarDataMap().get(avatarId); + if (avatarData != null && !this.player.getAvatars().hasAvatar(avatarId)) { + this.player.addAvatar(new Avatar(avatarData)); + } + return null; + case MATERIAL_FLYCLOAK: + AvatarFlycloakData flycloakData = GameData.getAvatarFlycloakDataMap().get(item.getItemId()); + if (flycloakData != null && !this.player.getFlyCloakList().contains(item.getItemId())) { + this.player.addFlycloak(item.getItemId()); + } + return null; + case MATERIAL_COSTUME: + AvatarCostumeData costumeData = GameData.getAvatarCostumeDataItemIdMap().get(item.getItemId()); if (costumeData != null && !this.player.getCostumeList().contains(costumeData.getId())) { this.player.addCostume(costumeData.getId()); } @@ -233,46 +233,46 @@ public class Inventory extends BasePlayerManager implements Iterable { case MATERIAL_NAMECARD: if (!this.player.getNameCardList().contains(item.getItemId())) { this.player.addNameCard(item.getItemId()); - } - return null; + } + return null; default: if (tab == null) { return null; } - GameItem existingItem = tab.getItemById(item.getItemId()); - if (existingItem == null) { - // Item type didnt exist before, we will add it to main inventory map if there is enough space - if (tab.getSize() >= tab.getMaxCapacity()) { - return null; - } - this.putItem(item, tab); - // Set ownership and save to db - item.save(); - return item; - } else { - // Add count - existingItem.setCount(Math.min(existingItem.getCount() + item.getCount(), item.getItemData().getStackLimit())); - existingItem.save(); - return existingItem; - } - } + GameItem existingItem = tab.getItemById(item.getItemId()); + if (existingItem == null) { + // Item type didnt exist before, we will add it to main inventory map if there is enough space + if (tab.getSize() >= tab.getMaxCapacity()) { + return null; + } + this.putItem(item, tab); + // Set ownership and save to db + item.save(); + return item; + } else { + // Add count + existingItem.setCount(Math.min(existingItem.getCount() + item.getCount(), item.getItemData().getStackLimit())); + existingItem.save(); + return existingItem; + } + } } - } - - private synchronized void putItem(GameItem item, InventoryTab tab) { + } + + private synchronized void putItem(GameItem item, InventoryTab tab) { this.player.getCodex().checkAddedItem(item); // Set owner and guid FIRST! item.setOwner(this.player); - // Put in item store - getItems().put(item.getGuid(), item); - if (tab != null) { - tab.onAddItem(item); - } - } - - private void addVirtualItem(int itemId, int count) { - switch (itemId) { - case 101 -> // Character exp + // Put in item store + getItems().put(item.getGuid(), item); + if (tab != null) { + tab.onAddItem(item); + } + } + + private void addVirtualItem(int itemId, int count) { + switch (itemId) { + case 101 -> // Character exp this.player.getServer().getInventorySystem().upgradeAvatar(this.player, this.player.getTeamManager().getCurrentAvatarEntity().getAvatar(), count); case 102 -> // Adventure exp this.player.addExpDirectly(count); @@ -290,216 +290,216 @@ public class Inventory extends BasePlayerManager implements Iterable { this.player.setCrystals(this.player.getCrystals() + count); case 204 -> // Home Coin this.player.setHomeCoin(this.player.getHomeCoin() + count); - } - } + } + } - private int getVirtualItemCount(int itemId) { - switch (itemId) { - case 201: // Primogem - return this.player.getPrimogems(); - case 202: // Mora - return this.player.getMora(); - case 203: // Genesis Crystals - return this.player.getCrystals(); - case 106: // Resin - return this.player.getProperty(PlayerProperty.PROP_PLAYER_RESIN); + private int getVirtualItemCount(int itemId) { + switch (itemId) { + case 201: // Primogem + return this.player.getPrimogems(); + case 202: // Mora + return this.player.getMora(); + case 203: // Genesis Crystals + return this.player.getCrystals(); + case 106: // Resin + return this.player.getProperty(PlayerProperty.PROP_PLAYER_RESIN); case 107: // Legendary Key return this.player.getProperty(PlayerProperty.PROP_PLAYER_LEGENDARY_KEY); - case 204: // Home Coin - return this.player.getHomeCoin(); - default: - GameItem item = getInventoryTab(ItemType.ITEM_MATERIAL).getItemById(itemId); // What if we ever want to operate on weapons/relics/furniture? :S - return (item == null) ? 0 : item.getCount(); - } - } + case 204: // Home Coin + return this.player.getHomeCoin(); + default: + GameItem item = getInventoryTab(ItemType.ITEM_MATERIAL).getItemById(itemId); // What if we ever want to operate on weapons/relics/furniture? :S + return (item == null) ? 0 : item.getCount(); + } + } - public boolean payItem(int id, int count) { - return payItem(new ItemParamData(id, count)); - } + public boolean payItem(int id, int count) { + return payItem(new ItemParamData(id, count)); + } - public boolean payItem(ItemParamData costItem) { - return payItems(new ItemParamData[] {costItem}, 1, null); - } + public boolean payItem(ItemParamData costItem) { + return payItems(new ItemParamData[] {costItem}, 1, null); + } - public boolean payItems(ItemParamData[] costItems) { - return payItems(costItems, 1, null); - } + public boolean payItems(ItemParamData[] costItems) { + return payItems(costItems, 1, null); + } - public boolean payItems(ItemParamData[] costItems, int quantity) { - return payItems(costItems, quantity, null); - } - - public synchronized boolean payItems(ItemParamData[] costItems, int quantity, ActionReason reason) { - // Make sure player has requisite items - for (ItemParamData cost : costItems) { - if (getVirtualItemCount(cost.getId()) < (cost.getCount() * quantity)) { - return false; - } - } - // All costs are satisfied, now remove them all - for (ItemParamData cost : costItems) { - switch (cost.getId()) { - case 201 -> // Primogem - player.setPrimogems(player.getPrimogems() - (cost.getCount() * quantity)); - case 202 -> // Mora - player.setMora(player.getMora() - (cost.getCount() * quantity)); - case 203 -> // Genesis Crystals - player.setCrystals(player.getCrystals() - (cost.getCount() * quantity)); - case 106 -> // Resin - player.getResinManager().useResin(cost.getCount() * quantity); + public boolean payItems(ItemParamData[] costItems, int quantity) { + return payItems(costItems, quantity, null); + } + + public synchronized boolean payItems(ItemParamData[] costItems, int quantity, ActionReason reason) { + // Make sure player has requisite items + for (ItemParamData cost : costItems) { + if (getVirtualItemCount(cost.getId()) < (cost.getCount() * quantity)) { + return false; + } + } + // All costs are satisfied, now remove them all + for (ItemParamData cost : costItems) { + switch (cost.getId()) { + case 201 -> // Primogem + player.setPrimogems(player.getPrimogems() - (cost.getCount() * quantity)); + case 202 -> // Mora + player.setMora(player.getMora() - (cost.getCount() * quantity)); + case 203 -> // Genesis Crystals + player.setCrystals(player.getCrystals() - (cost.getCount() * quantity)); + case 106 -> // Resin + player.getResinManager().useResin(cost.getCount() * quantity); case 107 -> // LegendaryKey player.useLegendaryKey(cost.getCount() * quantity); - case 204 -> // Home Coin - player.setHomeCoin(player.getHomeCoin() - (cost.getCount() * quantity)); - default -> - removeItem(getInventoryTab(ItemType.ITEM_MATERIAL).getItemById(cost.getId()), cost.getCount() * quantity); - } - } + case 204 -> // Home Coin + player.setHomeCoin(player.getHomeCoin() - (cost.getCount() * quantity)); + default -> + removeItem(getInventoryTab(ItemType.ITEM_MATERIAL).getItemById(cost.getId()), cost.getCount() * quantity); + } + } - if (reason != null) { // Do we need these? - // getPlayer().sendPacket(new PacketItemAddHintNotify(changedItems, reason)); - } - // getPlayer().sendPacket(new PacketStoreItemChangeNotify(changedItems)); - return true; - } - - public void removeItems(List items) { - // TODO Bulk delete - for (GameItem item : items) { - this.removeItem(item, item.getCount()); - } - } - - public boolean removeItem(long guid) { - return removeItem(guid, 1); - } - - public synchronized boolean removeItem(long guid, int count) { - GameItem item = this.getItemByGuid(guid); - - if (item == null) { - return false; - } - - return removeItem(item, count); - } - - public synchronized boolean removeItem(GameItem item) { - return removeItem(item, item.getCount()); - } - - public synchronized boolean removeItem(GameItem item, int count) { - // Sanity check - if (count <= 0 || item == null) { - return false; - } + if (reason != null) { // Do we need these? + // getPlayer().sendPacket(new PacketItemAddHintNotify(changedItems, reason)); + } + // getPlayer().sendPacket(new PacketStoreItemChangeNotify(changedItems)); + return true; + } - if (item.getItemData().isEquip()) { - item.setCount(0); - } else { - item.setCount(item.getCount() - count); - } - - if (item.getCount() <= 0) { - // Remove from inventory tab too - InventoryTab tab = null; - if (item.getItemData() != null) { - tab = getInventoryTab(item.getItemData().getItemType()); - } - // Remove if less than 0 - deleteItem(item, tab); - // - getPlayer().sendPacket(new PacketStoreItemDelNotify(item)); - } else { - getPlayer().sendPacket(new PacketStoreItemChangeNotify(item)); - } - - // Battle pass trigger - int removeCount = Math.min(count, item.getCount()); - getPlayer().getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_COST_MATERIAL, item.getItemId(), removeCount); - - // Update in db - item.save(); - - // Returns true on success - return true; - } - - private void deleteItem(GameItem item, InventoryTab tab) { - getItems().remove(item.getGuid()); - if (tab != null) { - tab.onRemoveItem(item); - } - } - - public boolean equipItem(long avatarGuid, long equipGuid) { - Avatar avatar = getPlayer().getAvatars().getAvatarByGuid(avatarGuid); - GameItem item = this.getItemByGuid(equipGuid); - - if (avatar != null && item != null) { - return avatar.equipItem(item, true); - } - - return false; - } - - public boolean unequipItem(long avatarGuid, int slot) { - Avatar avatar = getPlayer().getAvatars().getAvatarByGuid(avatarGuid); - EquipType equipType = EquipType.getTypeByValue(slot); - - if (avatar != null && equipType != EquipType.EQUIP_WEAPON) { - if (avatar.unequipItem(equipType)) { - getPlayer().sendPacket(new PacketAvatarEquipChangeNotify(avatar, equipType)); - avatar.recalcStats(); - return true; - } - } - - return false; - } - - public void loadFromDatabase() { - List items = DatabaseHelper.getInventoryItems(getPlayer()); - - for (GameItem item : items) { - // Should never happen - if (item.getObjectId() == null) { - continue; - } - - ItemData itemData = GameData.getItemDataMap().get(item.getItemId()); - if (itemData == null) { - continue; - } - - item.setItemData(itemData); - - InventoryTab tab = null; - if (item.getItemData() != null) { - tab = getInventoryTab(item.getItemData().getItemType()); - } - - putItem(item, tab); - - // Equip to a character if possible - if (item.isEquipped()) { - Avatar avatar = getPlayer().getAvatars().getAvatarById(item.getEquipCharacter()); - boolean hasEquipped = false; - - if (avatar != null) { - hasEquipped = avatar.equipItem(item, false); - } - - if (!hasEquipped) { - item.setEquipCharacter(0); - item.save(); - } - } - } - } + public void removeItems(List items) { + // TODO Bulk delete + for (GameItem item : items) { + this.removeItem(item, item.getCount()); + } + } - @Override - public Iterator iterator() { - return this.getItems().values().iterator(); - } + public boolean removeItem(long guid) { + return removeItem(guid, 1); + } + + public synchronized boolean removeItem(long guid, int count) { + GameItem item = this.getItemByGuid(guid); + + if (item == null) { + return false; + } + + return removeItem(item, count); + } + + public synchronized boolean removeItem(GameItem item) { + return removeItem(item, item.getCount()); + } + + public synchronized boolean removeItem(GameItem item, int count) { + // Sanity check + if (count <= 0 || item == null) { + return false; + } + + if (item.getItemData().isEquip()) { + item.setCount(0); + } else { + item.setCount(item.getCount() - count); + } + + if (item.getCount() <= 0) { + // Remove from inventory tab too + InventoryTab tab = null; + if (item.getItemData() != null) { + tab = getInventoryTab(item.getItemData().getItemType()); + } + // Remove if less than 0 + deleteItem(item, tab); + // + getPlayer().sendPacket(new PacketStoreItemDelNotify(item)); + } else { + getPlayer().sendPacket(new PacketStoreItemChangeNotify(item)); + } + + // Battle pass trigger + int removeCount = Math.min(count, item.getCount()); + getPlayer().getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_COST_MATERIAL, item.getItemId(), removeCount); + + // Update in db + item.save(); + + // Returns true on success + return true; + } + + private void deleteItem(GameItem item, InventoryTab tab) { + getItems().remove(item.getGuid()); + if (tab != null) { + tab.onRemoveItem(item); + } + } + + public boolean equipItem(long avatarGuid, long equipGuid) { + Avatar avatar = getPlayer().getAvatars().getAvatarByGuid(avatarGuid); + GameItem item = this.getItemByGuid(equipGuid); + + if (avatar != null && item != null) { + return avatar.equipItem(item, true); + } + + return false; + } + + public boolean unequipItem(long avatarGuid, int slot) { + Avatar avatar = getPlayer().getAvatars().getAvatarByGuid(avatarGuid); + EquipType equipType = EquipType.getTypeByValue(slot); + + if (avatar != null && equipType != EquipType.EQUIP_WEAPON) { + if (avatar.unequipItem(equipType)) { + getPlayer().sendPacket(new PacketAvatarEquipChangeNotify(avatar, equipType)); + avatar.recalcStats(); + return true; + } + } + + return false; + } + + public void loadFromDatabase() { + List items = DatabaseHelper.getInventoryItems(getPlayer()); + + for (GameItem item : items) { + // Should never happen + if (item.getObjectId() == null) { + continue; + } + + ItemData itemData = GameData.getItemDataMap().get(item.getItemId()); + if (itemData == null) { + continue; + } + + item.setItemData(itemData); + + InventoryTab tab = null; + if (item.getItemData() != null) { + tab = getInventoryTab(item.getItemData().getItemType()); + } + + putItem(item, tab); + + // Equip to a character if possible + if (item.isEquipped()) { + Avatar avatar = getPlayer().getAvatars().getAvatarById(item.getEquipCharacter()); + boolean hasEquipped = false; + + if (avatar != null) { + hasEquipped = avatar.equipItem(item, false); + } + + if (!hasEquipped) { + item.setEquipCharacter(0); + item.save(); + } + } + } + } + + @Override + public Iterator iterator() { + return this.getItems().values().iterator(); + } } diff --git a/src/main/java/emu/grasscutter/game/mail/MailHandler.java b/src/main/java/emu/grasscutter/game/mail/MailHandler.java index 12e741816..7d0880c27 100644 --- a/src/main/java/emu/grasscutter/game/mail/MailHandler.java +++ b/src/main/java/emu/grasscutter/game/mail/MailHandler.java @@ -13,89 +13,89 @@ import emu.grasscutter.server.packet.send.PacketDelMailRsp; import emu.grasscutter.server.packet.send.PacketMailChangeNotify; public class MailHandler extends BasePlayerManager { - private final List mail; - - public MailHandler(Player player) { - super(player); - - this.mail = new ArrayList<>(); - } + private final List mail; - public List getMail() { - return mail; - } - - // ---------------------MAIL------------------------ + public MailHandler(Player player) { + super(player); - public void sendMail(Mail message) { - // Call mail receive event. - PlayerReceiveMailEvent event = new PlayerReceiveMailEvent(this.getPlayer(), message); event.call(); - if(event.isCanceled()) return; message = event.getMessage(); - - message.setOwnerUid(this.getPlayer().getUid()); - message.save(); - - this.mail.add(message); - - Grasscutter.getLogger().debug("Mail sent to user [" + this.getPlayer().getUid() + ":" + this.getPlayer().getNickname() + "]!"); - - if (this.getPlayer().isOnline()) { - this.getPlayer().sendPacket(new PacketMailChangeNotify(this.getPlayer(), message)); - } // TODO: setup a way for the mail notification to show up when someone receives mail when they were offline - } + this.mail = new ArrayList<>(); + } - public boolean deleteMail(int mailId) { - Mail message = getMailById(mailId); + public List getMail() { + return mail; + } - if (message != null) { - this.getMail().remove(mailId); - message.expireTime = 0; - message.save(); - - return true; - } + // ---------------------MAIL------------------------ - return false; - } - - public void deleteMail(List mailList) { - List sortedMailList = new ArrayList<>(); - sortedMailList.addAll(mailList); - Collections.sort(sortedMailList, Collections.reverseOrder()); - - List deleted = new ArrayList<>(); - - for (int id : sortedMailList) { - if (this.deleteMail(id)) { - deleted.add(id); - } - } - - player.getSession().send(new PacketDelMailRsp(player, deleted)); - player.getSession().send(new PacketMailChangeNotify(player, null, deleted)); - } + public void sendMail(Mail message) { + // Call mail receive event. + PlayerReceiveMailEvent event = new PlayerReceiveMailEvent(this.getPlayer(), message); event.call(); + if (event.isCanceled()) return; message = event.getMessage(); - public Mail getMailById(int index) { return this.mail.get(index); } - - public int getMailIndex(Mail message) { - return this.mail.indexOf(message); - } + message.setOwnerUid(this.getPlayer().getUid()); + message.save(); - public boolean replaceMailByIndex(int index, Mail message) { - if(getMailById(index) != null) { - this.mail.set(index, message); - message.save(); - return true; - } else { - return false; - } - } + this.mail.add(message); - public void loadFromDatabase() { - List mailList = DatabaseHelper.getAllMail(this.getPlayer()); - - for (Mail mail : mailList) { - this.getMail().add(mail); - } - } + Grasscutter.getLogger().debug("Mail sent to user [" + this.getPlayer().getUid() + ":" + this.getPlayer().getNickname() + "]!"); + + if (this.getPlayer().isOnline()) { + this.getPlayer().sendPacket(new PacketMailChangeNotify(this.getPlayer(), message)); + } // TODO: setup a way for the mail notification to show up when someone receives mail when they were offline + } + + public boolean deleteMail(int mailId) { + Mail message = getMailById(mailId); + + if (message != null) { + this.getMail().remove(mailId); + message.expireTime = 0; + message.save(); + + return true; + } + + return false; + } + + public void deleteMail(List mailList) { + List sortedMailList = new ArrayList<>(); + sortedMailList.addAll(mailList); + Collections.sort(sortedMailList, Collections.reverseOrder()); + + List deleted = new ArrayList<>(); + + for (int id : sortedMailList) { + if (this.deleteMail(id)) { + deleted.add(id); + } + } + + player.getSession().send(new PacketDelMailRsp(player, deleted)); + player.getSession().send(new PacketMailChangeNotify(player, null, deleted)); + } + + public Mail getMailById(int index) { return this.mail.get(index); } + + public int getMailIndex(Mail message) { + return this.mail.indexOf(message); + } + + public boolean replaceMailByIndex(int index, Mail message) { + if (getMailById(index) != null) { + this.mail.set(index, message); + message.save(); + return true; + } else { + return false; + } + } + + public void loadFromDatabase() { + List mailList = DatabaseHelper.getAllMail(this.getPlayer()); + + for (Mail mail : mailList) { + this.getMail().add(mail); + } + } } diff --git a/src/main/java/emu/grasscutter/game/managers/CookingManager.java b/src/main/java/emu/grasscutter/game/managers/CookingManager.java index 5964d4f19..4ede72403 100644 --- a/src/main/java/emu/grasscutter/game/managers/CookingManager.java +++ b/src/main/java/emu/grasscutter/game/managers/CookingManager.java @@ -102,9 +102,9 @@ public class CookingManager extends BasePlayerManager { } // Get result item information. - int qualityIndex = - quality == 0 - ? 2 + int qualityIndex = + quality == 0 + ? 2 : quality - 1; ItemParamData resultParam = recipeData.getQualityOutputVec().get(qualityIndex); diff --git a/src/main/java/emu/grasscutter/game/managers/FurnitureManager.java b/src/main/java/emu/grasscutter/game/managers/FurnitureManager.java index d18119405..38e2dcd7e 100644 --- a/src/main/java/emu/grasscutter/game/managers/FurnitureManager.java +++ b/src/main/java/emu/grasscutter/game/managers/FurnitureManager.java @@ -15,25 +15,25 @@ import java.util.ArrayList; import java.util.List; public class FurnitureManager extends BasePlayerManager { - + public FurnitureManager(Player player) { super(player); } - public void onLogin(){ + public void onLogin() { notifyUnlockFurniture(); notifyUnlockFurnitureSuite(); } - public void notifyUnlockFurniture(){ + public void notifyUnlockFurniture() { player.getSession().send(new PacketUnlockedFurnitureFormulaDataNotify(player.getUnlockedFurniture())); } - public void notifyUnlockFurnitureSuite(){ + public void notifyUnlockFurnitureSuite() { player.getSession().send(new PacketUnlockedFurnitureSuiteDataNotify(player.getUnlockedFurnitureSuite())); } - public synchronized boolean unlockFurnitureOrSuite(GameItem useItem){ + public synchronized boolean unlockFurnitureOrSuite(GameItem useItem) { // Check if (!List.of("ITEM_USE_UNLOCK_FURNITURE_FORMULA", "ITEM_USE_UNLOCK_FURNITURE_SUITE") .contains(useItem.getItemData().getItemUse().get(0).getUseOp())) { @@ -45,10 +45,10 @@ public class FurnitureManager extends BasePlayerManager { // Remove first player.getInventory().removeItem(useItem, 1); - if("ITEM_USE_UNLOCK_FURNITURE_FORMULA".equals(useItem.getItemData().getItemUse().get(0).getUseOp())){ + if ("ITEM_USE_UNLOCK_FURNITURE_FORMULA".equals(useItem.getItemData().getItemUse().get(0).getUseOp())) { player.getUnlockedFurniture().add(furnitureIdOrSuiteId); notifyUnlockFurniture(); - }else{ + }else { player.getUnlockedFurnitureSuite().add(furnitureIdOrSuiteId); notifyUnlockFurnitureSuite(); } @@ -57,19 +57,19 @@ public class FurnitureManager extends BasePlayerManager { public void startMake(int makeId, int avatarId) { var makeData = GameData.getFurnitureMakeConfigDataMap().get(makeId); - if(makeData == null){ + if (makeData == null) { player.getSession().send(new PacketFurnitureMakeStartRsp(Retcode.RET_FURNITURE_MAKE_CONFIG_ERROR_VALUE, null)); return; } // check slot count - if (player.getHome().getLevelData().getFurnitureMakeSlotCount() <= player.getHome().getFurnitureMakeSlotItemList().size()){ + if (player.getHome().getLevelData().getFurnitureMakeSlotCount() <= player.getHome().getFurnitureMakeSlotItemList().size()) { player.getSession().send(new PacketFurnitureMakeStartRsp(Retcode.RET_FURNITURE_MAKE_SLOT_FULL_VALUE, null)); return; } // pay items first - if(!player.getInventory().payItems(makeData.getMaterialItems().toArray(new ItemParamData[0]))){ + if (!player.getInventory().payItems(makeData.getMaterialItems().toArray(new ItemParamData[0]))) { player.getSession().send(new PacketFurnitureMakeStartRsp(Retcode.RET_HOME_FURNITURE_COUNT_NOT_ENOUGH_VALUE, null)); return; } @@ -93,7 +93,7 @@ public class FurnitureManager extends BasePlayerManager { } public void queryStatus() { - if (player.getHome().getFurnitureMakeSlotItemList() == null){ + if (player.getHome().getFurnitureMakeSlotItemList() == null) { player.getHome().setFurnitureMakeSlotItemList(new ArrayList<>()); } @@ -103,7 +103,7 @@ public class FurnitureManager extends BasePlayerManager { public void take(int index, int makeId, boolean isFastFinish) { var makeData = GameData.getFurnitureMakeConfigDataMap().get(makeId); - if(makeData == null){ + if (makeData == null) { player.getSession().send(new PacketTakeFurnitureMakeRsp(Retcode.RET_FURNITURE_MAKE_CONFIG_ERROR_VALUE, makeId, null, null)); return; } @@ -112,19 +112,19 @@ public class FurnitureManager extends BasePlayerManager { .filter(x -> x.getIndex() == index && x.getMakeId() == makeId) .findFirst(); - if(slotItem.isEmpty()){ + if (slotItem.isEmpty()) { player.getSession().send(new PacketTakeFurnitureMakeRsp(Retcode.RET_FURNITURE_MAKE_NO_MAKE_DATA_VALUE, makeId, null, null)); return; } // pay the speedup item - if(isFastFinish && !player.getInventory().payItem(107013,1)){ + if (isFastFinish && !player.getInventory().payItem(107013,1)) { player.getSession().send(new PacketTakeFurnitureMakeRsp(Retcode.RET_FURNITURE_MAKE_UNFINISH_VALUE, makeId, null, null)); return; } // check if player can take -// if(slotItem.get().getBeginTime() + slotItem.get().getDurTime() >= Utils.getCurrentSeconds() && !isFastFinish){ +// if (slotItem.get().getBeginTime() + slotItem.get().getDurTime() >= Utils.getCurrentSeconds() && !isFastFinish) { // player.getSession().send(new PacketTakeFurnitureMakeRsp(Retcode.RET_FURNITURE_MAKE_UNFINISH_VALUE, makeId, null, null)); // return; // } diff --git a/src/main/java/emu/grasscutter/game/managers/ResinManager.java b/src/main/java/emu/grasscutter/game/managers/ResinManager.java index 78f4b09fd..aa85f61ac 100644 --- a/src/main/java/emu/grasscutter/game/managers/ResinManager.java +++ b/src/main/java/emu/grasscutter/game/managers/ResinManager.java @@ -26,7 +26,7 @@ public class ResinManager extends BasePlayerManager { } int currentResin = this.player.getProperty(PlayerProperty.PROP_PLAYER_RESIN); - + // Check if the player has sufficient resin. if (currentResin < amount) { return false; @@ -39,16 +39,16 @@ public class ResinManager extends BasePlayerManager { // Check if this has taken the player under the recharge cap, // starting the recharging process. if (this.player.getNextResinRefresh() == 0 && newResin < GAME_OPTIONS.resinOptions.cap) { - int currentTime = Utils.getCurrentSeconds(); + int currentTime = Utils.getCurrentSeconds(); this.player.setNextResinRefresh(currentTime + GAME_OPTIONS.resinOptions.rechargeTime); } // Send packets. this.player.sendPacket(new PacketResinChangeNotify(this.player)); - + // Battle Pass trigger this.player.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_COST_MATERIAL, 106, amount); // Resin item id = 106 - + return true; } @@ -122,7 +122,7 @@ public class ResinManager extends BasePlayerManager { * Player login. ********************/ public synchronized void onPlayerLogin() { - // If resin usage is disabled, set resin to cap. + // If resin usage is disabled, set resin to cap. if (!GAME_OPTIONS.resinOptions.resinUsage) { this.player.setProperty(PlayerProperty.PROP_PLAYER_RESIN, GAME_OPTIONS.resinOptions.cap); this.player.setNextResinRefresh(0); @@ -132,7 +132,7 @@ public class ResinManager extends BasePlayerManager { // we need to restart recharging here. int currentResin = this.player.getProperty(PlayerProperty.PROP_PLAYER_RESIN); int currentTime = Utils.getCurrentSeconds(); - + if (currentResin < GAME_OPTIONS.resinOptions.cap && this.player.getNextResinRefresh() == 0) { this.player.setNextResinRefresh(currentTime + GAME_OPTIONS.resinOptions.rechargeTime); } diff --git a/src/main/java/emu/grasscutter/game/managers/SotSManager.java b/src/main/java/emu/grasscutter/game/managers/SotSManager.java index 8002fafa8..4ecb30ff2 100644 --- a/src/main/java/emu/grasscutter/game/managers/SotSManager.java +++ b/src/main/java/emu/grasscutter/game/managers/SotSManager.java @@ -1,191 +1,191 @@ -package emu.grasscutter.game.managers; - -import ch.qos.logback.classic.Logger; -import emu.grasscutter.Grasscutter; -import emu.grasscutter.game.entity.EntityAvatar; -import emu.grasscutter.game.player.BasePlayerManager; -import emu.grasscutter.game.player.Player; -import emu.grasscutter.game.props.FightProperty; -import emu.grasscutter.game.props.PlayerProperty; -import emu.grasscutter.net.proto.ChangeHpReasonOuterClass.ChangeHpReason; -import emu.grasscutter.net.proto.PropChangeReasonOuterClass.PropChangeReason; -import emu.grasscutter.server.packet.send.PacketEntityFightPropChangeReasonNotify; -import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify; - -import java.util.List; -import java.util.Timer; -import java.util.TimerTask; - -// Statue of the Seven Manager -public class SotSManager extends BasePlayerManager { - - // NOTE: Spring volume balance *1 = fight prop HP *100 - - private final Logger logger = Grasscutter.getLogger(); - private Timer autoRecoverTimer; - private final boolean enablePriorityHealing = false; - - public final static int GlobalMaximumSpringVolume = PlayerProperty.PROP_MAX_SPRING_VOLUME.getMax(); - - public SotSManager(Player player) { - super(player); - } - - public boolean getIsAutoRecoveryEnabled() { - return player.getProperty(PlayerProperty.PROP_IS_SPRING_AUTO_USE) == 1; - } - - public void setIsAutoRecoveryEnabled(boolean enabled) { - player.setProperty(PlayerProperty.PROP_IS_SPRING_AUTO_USE, enabled ? 1 : 0); - player.save(); - } - - public int getAutoRecoveryPercentage() { - return player.getProperty(PlayerProperty.PROP_SPRING_AUTO_USE_PERCENT); - } - - public void setAutoRecoveryPercentage(int percentage) { - player.setProperty(PlayerProperty.PROP_SPRING_AUTO_USE_PERCENT, percentage); - player.save(); - } - - public long getLastUsed() { - return player.getSpringLastUsed(); - } - - public void setLastUsed() { - player.setSpringLastUsed(System.currentTimeMillis() / 1000); - player.save(); - } - - public int getMaxVolume() { - return player.getProperty(PlayerProperty.PROP_MAX_SPRING_VOLUME); - } - - public void setMaxVolume(int volume) { - player.setProperty(PlayerProperty.PROP_MAX_SPRING_VOLUME, volume); - player.save(); - } - - public int getCurrentVolume() { - return player.getProperty(PlayerProperty.PROP_CUR_SPRING_VOLUME); - } - - public void setCurrentVolume(int volume) { - player.setProperty(PlayerProperty.PROP_CUR_SPRING_VOLUME, volume); - setLastUsed(); - player.save(); - } - - public void handleEnterTransPointRegionNotify() { - logger.trace("Player entered statue region"); - autoRevive(); - if (autoRecoverTimer == null) { - autoRecoverTimer = new Timer(); - autoRecoverTimer.schedule(new AutoRecoverTimerTick(), 2500, 15000); - } - } - - public void handleExitTransPointRegionNotify() { - logger.trace("Player left statue region"); - if (autoRecoverTimer != null) { - autoRecoverTimer.cancel(); - autoRecoverTimer = null; - } - } - - // autoRevive automatically revives all team members. - public void autoRevive() { - player.getTeamManager().getActiveTeam().forEach(entity -> { - boolean isAlive = entity.isAlive(); - if (isAlive) { - return; - } - logger.trace("Reviving avatar " + entity.getAvatar().getAvatarData().getName()); - player.getTeamManager().reviveAvatar(entity.getAvatar()); - player.getTeamManager().healAvatar(entity.getAvatar(), 30, 0); - }); - } - - private class AutoRecoverTimerTick extends TimerTask { - // autoRecover checks player setting to see if auto recover is enabled, and refill HP to the predefined level. - public void run() { - refillSpringVolume(); - - logger.trace("isAutoRecoveryEnabled: " + getIsAutoRecoveryEnabled() + "\tautoRecoverPercentage: " + getAutoRecoveryPercentage()); - - if (getIsAutoRecoveryEnabled()) { - List activeTeam = player.getTeamManager().getActiveTeam(); - // When the statue does not have enough remaining volume: - // Enhanced experience: Enable priority healing - // The current active character will get healed first, then sequential. - // Vanilla experience: Disable priority healing - // Sequential healing based on character index. - int priorityIndex = enablePriorityHealing ? player.getTeamManager().getCurrentCharacterIndex() : -1; - if (priorityIndex >= 0) { - checkAndHealAvatar(activeTeam.get(priorityIndex)); - } - for (int i = 0; i < activeTeam.size(); i++) { - if (i != priorityIndex) { - checkAndHealAvatar(activeTeam.get(i)); - } - } - } - } - } - - public void checkAndHealAvatar(EntityAvatar entity) { - int maxHP = (int) (entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * 100); - int currentHP = (int) (entity.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) * 100); - if (currentHP == maxHP) { - return; - } - int targetHP = maxHP * getAutoRecoveryPercentage() / 100; - - if (targetHP > currentHP) { - int needHP = targetHP - currentHP; - int currentVolume = getCurrentVolume(); - if (currentVolume >= needHP) { - // sufficient - setCurrentVolume(currentVolume - needHP); - } else { - // insufficient balance - needHP = currentVolume; - setCurrentVolume(0); - } - if (needHP > 0) { - logger.trace("Healing avatar " + entity.getAvatar().getAvatarData().getName() + " +" + needHP); - player.getTeamManager().healAvatar(entity.getAvatar(), 0, needHP); - player.getSession().send(new PacketEntityFightPropChangeReasonNotify(entity, FightProperty.FIGHT_PROP_CUR_HP, - ((float) needHP / 100), List.of(3), PropChangeReason.PROP_CHANGE_REASON_STATUE_RECOVER, - ChangeHpReason.CHANGE_HP_REASON_ADD_STATUE)); - player.getSession().send(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CUR_HP)); - - } - } - } - - public void refillSpringVolume() { - // Temporary: Max spring volume depends on level of the statues in Mondstadt and Liyue. Override until we have statue level. - // TODO: remove - // https://genshin-impact.fandom.com/wiki/Statue_of_The_Seven#:~:text=region%20of%20Inazuma.-,Statue%20Levels,-Upon%20first%20unlocking - setMaxVolume(8500000); - // Temporary: Auto enable 100% statue recovery until we can adjust statue settings in game - // TODO: remove - setAutoRecoveryPercentage(100); - setIsAutoRecoveryEnabled(true); - - int maxVolume = getMaxVolume(); - int currentVolume = getCurrentVolume(); - if (currentVolume < maxVolume) { - long now = System.currentTimeMillis() / 1000; - int secondsSinceLastUsed = (int) (now - getLastUsed()); - // 15s = 1% max volume - int volumeRefilled = secondsSinceLastUsed * maxVolume / 15 / 100; - logger.trace("Statue has refilled HP volume: " + volumeRefilled); - currentVolume = Math.min(currentVolume + volumeRefilled, maxVolume); - logger.trace("Statue remaining HP volume: " + currentVolume); - setCurrentVolume(currentVolume); - } - } -} +package emu.grasscutter.game.managers; + +import ch.qos.logback.classic.Logger; +import emu.grasscutter.Grasscutter; +import emu.grasscutter.game.entity.EntityAvatar; +import emu.grasscutter.game.player.BasePlayerManager; +import emu.grasscutter.game.player.Player; +import emu.grasscutter.game.props.FightProperty; +import emu.grasscutter.game.props.PlayerProperty; +import emu.grasscutter.net.proto.ChangeHpReasonOuterClass.ChangeHpReason; +import emu.grasscutter.net.proto.PropChangeReasonOuterClass.PropChangeReason; +import emu.grasscutter.server.packet.send.PacketEntityFightPropChangeReasonNotify; +import emu.grasscutter.server.packet.send.PacketEntityFightPropUpdateNotify; + +import java.util.List; +import java.util.Timer; +import java.util.TimerTask; + +// Statue of the Seven Manager +public class SotSManager extends BasePlayerManager { + + // NOTE: Spring volume balance *1 = fight prop HP *100 + + private final Logger logger = Grasscutter.getLogger(); + private Timer autoRecoverTimer; + private final boolean enablePriorityHealing = false; + + public final static int GlobalMaximumSpringVolume = PlayerProperty.PROP_MAX_SPRING_VOLUME.getMax(); + + public SotSManager(Player player) { + super(player); + } + + public boolean getIsAutoRecoveryEnabled() { + return player.getProperty(PlayerProperty.PROP_IS_SPRING_AUTO_USE) == 1; + } + + public void setIsAutoRecoveryEnabled(boolean enabled) { + player.setProperty(PlayerProperty.PROP_IS_SPRING_AUTO_USE, enabled ? 1 : 0); + player.save(); + } + + public int getAutoRecoveryPercentage() { + return player.getProperty(PlayerProperty.PROP_SPRING_AUTO_USE_PERCENT); + } + + public void setAutoRecoveryPercentage(int percentage) { + player.setProperty(PlayerProperty.PROP_SPRING_AUTO_USE_PERCENT, percentage); + player.save(); + } + + public long getLastUsed() { + return player.getSpringLastUsed(); + } + + public void setLastUsed() { + player.setSpringLastUsed(System.currentTimeMillis() / 1000); + player.save(); + } + + public int getMaxVolume() { + return player.getProperty(PlayerProperty.PROP_MAX_SPRING_VOLUME); + } + + public void setMaxVolume(int volume) { + player.setProperty(PlayerProperty.PROP_MAX_SPRING_VOLUME, volume); + player.save(); + } + + public int getCurrentVolume() { + return player.getProperty(PlayerProperty.PROP_CUR_SPRING_VOLUME); + } + + public void setCurrentVolume(int volume) { + player.setProperty(PlayerProperty.PROP_CUR_SPRING_VOLUME, volume); + setLastUsed(); + player.save(); + } + + public void handleEnterTransPointRegionNotify() { + logger.trace("Player entered statue region"); + autoRevive(); + if (autoRecoverTimer == null) { + autoRecoverTimer = new Timer(); + autoRecoverTimer.schedule(new AutoRecoverTimerTick(), 2500, 15000); + } + } + + public void handleExitTransPointRegionNotify() { + logger.trace("Player left statue region"); + if (autoRecoverTimer != null) { + autoRecoverTimer.cancel(); + autoRecoverTimer = null; + } + } + + // autoRevive automatically revives all team members. + public void autoRevive() { + player.getTeamManager().getActiveTeam().forEach(entity -> { + boolean isAlive = entity.isAlive(); + if (isAlive) { + return; + } + logger.trace("Reviving avatar " + entity.getAvatar().getAvatarData().getName()); + player.getTeamManager().reviveAvatar(entity.getAvatar()); + player.getTeamManager().healAvatar(entity.getAvatar(), 30, 0); + }); + } + + private class AutoRecoverTimerTick extends TimerTask { + // autoRecover checks player setting to see if auto recover is enabled, and refill HP to the predefined level. + public void run() { + refillSpringVolume(); + + logger.trace("isAutoRecoveryEnabled: " + getIsAutoRecoveryEnabled() + "\tautoRecoverPercentage: " + getAutoRecoveryPercentage()); + + if (getIsAutoRecoveryEnabled()) { + List activeTeam = player.getTeamManager().getActiveTeam(); + // When the statue does not have enough remaining volume: + // Enhanced experience: Enable priority healing + // The current active character will get healed first, then sequential. + // Vanilla experience: Disable priority healing + // Sequential healing based on character index. + int priorityIndex = enablePriorityHealing ? player.getTeamManager().getCurrentCharacterIndex() : -1; + if (priorityIndex >= 0) { + checkAndHealAvatar(activeTeam.get(priorityIndex)); + } + for (int i = 0; i < activeTeam.size(); i++) { + if (i != priorityIndex) { + checkAndHealAvatar(activeTeam.get(i)); + } + } + } + } + } + + public void checkAndHealAvatar(EntityAvatar entity) { + int maxHP = (int) (entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * 100); + int currentHP = (int) (entity.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) * 100); + if (currentHP == maxHP) { + return; + } + int targetHP = maxHP * getAutoRecoveryPercentage() / 100; + + if (targetHP > currentHP) { + int needHP = targetHP - currentHP; + int currentVolume = getCurrentVolume(); + if (currentVolume >= needHP) { + // sufficient + setCurrentVolume(currentVolume - needHP); + } else { + // insufficient balance + needHP = currentVolume; + setCurrentVolume(0); + } + if (needHP > 0) { + logger.trace("Healing avatar " + entity.getAvatar().getAvatarData().getName() + " +" + needHP); + player.getTeamManager().healAvatar(entity.getAvatar(), 0, needHP); + player.getSession().send(new PacketEntityFightPropChangeReasonNotify(entity, FightProperty.FIGHT_PROP_CUR_HP, + ((float) needHP / 100), List.of(3), PropChangeReason.PROP_CHANGE_REASON_STATUE_RECOVER, + ChangeHpReason.CHANGE_HP_REASON_ADD_STATUE)); + player.getSession().send(new PacketEntityFightPropUpdateNotify(entity, FightProperty.FIGHT_PROP_CUR_HP)); + + } + } + } + + public void refillSpringVolume() { + // Temporary: Max spring volume depends on level of the statues in Mondstadt and Liyue. Override until we have statue level. + // TODO: remove + // https://genshin-impact.fandom.com/wiki/Statue_of_The_Seven#:~:text=region%20of%20Inazuma.-,Statue%20Levels,-Upon%20first%20unlocking + setMaxVolume(8500000); + // Temporary: Auto enable 100% statue recovery until we can adjust statue settings in game + // TODO: remove + setAutoRecoveryPercentage(100); + setIsAutoRecoveryEnabled(true); + + int maxVolume = getMaxVolume(); + int currentVolume = getCurrentVolume(); + if (currentVolume < maxVolume) { + long now = System.currentTimeMillis() / 1000; + int secondsSinceLastUsed = (int) (now - getLastUsed()); + // 15s = 1% max volume + int volumeRefilled = secondsSinceLastUsed * maxVolume / 15 / 100; + logger.trace("Statue has refilled HP volume: " + volumeRefilled); + currentVolume = Math.min(currentVolume + volumeRefilled, maxVolume); + logger.trace("Statue remaining HP volume: " + currentVolume); + setCurrentVolume(currentVolume); + } + } +} diff --git a/src/main/java/emu/grasscutter/game/managers/chat/ChatManager.java b/src/main/java/emu/grasscutter/game/managers/chat/ChatManager.java index 66acd2e9a..3bf46e03a 100644 --- a/src/main/java/emu/grasscutter/game/managers/chat/ChatManager.java +++ b/src/main/java/emu/grasscutter/game/managers/chat/ChatManager.java @@ -21,197 +21,197 @@ import java.util.List; import java.util.Map; public class ChatManager implements ChatManagerHandler { - static final String PREFIXES = "[/!]"; - static final Pattern RE_PREFIXES = Pattern.compile(PREFIXES); - static final Pattern RE_COMMANDS = Pattern.compile("\n" + PREFIXES); + static final String PREFIXES = "[/!]"; + static final Pattern RE_PREFIXES = Pattern.compile(PREFIXES); + static final Pattern RE_COMMANDS = Pattern.compile("\n" + PREFIXES); - // We store the chat history for ongoing sessions in the form - // user id -> chat partner id -> [messages] - private final Map>> history = new HashMap<>(); + // We store the chat history for ongoing sessions in the form + // user id -> chat partner id -> [messages] + private final Map>> history = new HashMap<>(); - private final GameServer server; + private final GameServer server; - public ChatManager(GameServer server) { - this.server = server; - } + public ChatManager(GameServer server) { + this.server = server; + } - public GameServer getServer() { - return server; - } + public GameServer getServer() { + return server; + } - private boolean tryInvokeCommand(Player sender, Player target, String rawMessage) { - if (!RE_PREFIXES.matcher(rawMessage.substring(0, 1)).matches()) - return false; - for (String line : rawMessage.substring(1).split("\n[/!]")) - CommandMap.getInstance().invoke(sender, target, line); - return true; - } + private boolean tryInvokeCommand(Player sender, Player target, String rawMessage) { + if (!RE_PREFIXES.matcher(rawMessage.substring(0, 1)).matches()) + return false; + for (String line : rawMessage.substring(1).split("\n[/!]")) + CommandMap.getInstance().invoke(sender, target, line); + return true; + } - /******************** - * Chat history handling - ********************/ - private void putInHistory(int uid, int targetId, ChatInfo info) { - if (!this.history.containsKey(uid)) { - this.history.put(uid, new HashMap<>()); - } - if (!this.history.get(uid).containsKey(targetId)) { - this.history.get(uid).put(targetId, new ArrayList<>()); - } + /******************** + * Chat history handling + ********************/ + private void putInHistory(int uid, int targetId, ChatInfo info) { + if (!this.history.containsKey(uid)) { + this.history.put(uid, new HashMap<>()); + } + if (!this.history.get(uid).containsKey(targetId)) { + this.history.get(uid).put(targetId, new ArrayList<>()); + } - this.history.get(uid).get(targetId).add(info); - } + this.history.get(uid).get(targetId).add(info); + } - public void clearHistoryOnLogout(Player player) { - if (this.history.containsKey(player.getUid())) { - this.history.remove(player.getUid()); - } - } + public void clearHistoryOnLogout(Player player) { + if (this.history.containsKey(player.getUid())) { + this.history.remove(player.getUid()); + } + } - public void handlePullPrivateChatReq(Player player, int targetUid) { - if (this.history.containsKey(player.getUid()) && this.history.get(player.getUid()).containsKey(targetUid)) { - player.sendPacket(new PacketPullPrivateChatRsp(this.history.get(player.getUid()).get(targetUid))); - } - else { - player.sendPacket(new PacketPullPrivateChatRsp(List.of())); - } - } + public void handlePullPrivateChatReq(Player player, int targetUid) { + if (this.history.containsKey(player.getUid()) && this.history.get(player.getUid()).containsKey(targetUid)) { + player.sendPacket(new PacketPullPrivateChatRsp(this.history.get(player.getUid()).get(targetUid))); + } + else { + player.sendPacket(new PacketPullPrivateChatRsp(List.of())); + } + } - public void handlePullRecentChatReq(Player player) { - // For now, we send the list three messages from the server for the recent chat history. - // This matches the previous behavior, but ultimately, we should probably keep track of the last chat partner - // for every given player and return the last messages exchanged with that partner. - if (this.history.containsKey(player.getUid()) && this.history.get(player.getUid()).containsKey(GameConstants.SERVER_CONSOLE_UID)) { - int historyLength = this.history.get(player.getUid()).get(GameConstants.SERVER_CONSOLE_UID).size(); - var messages = this.history.get(player.getUid()).get(GameConstants.SERVER_CONSOLE_UID).subList(Math.max(historyLength - 3, 0), historyLength); - player.sendPacket(new PacketPullRecentChatRsp(messages)); - } - else { - player.sendPacket(new PacketPullRecentChatRsp(List.of())); - } - } + public void handlePullRecentChatReq(Player player) { + // For now, we send the list three messages from the server for the recent chat history. + // This matches the previous behavior, but ultimately, we should probably keep track of the last chat partner + // for every given player and return the last messages exchanged with that partner. + if (this.history.containsKey(player.getUid()) && this.history.get(player.getUid()).containsKey(GameConstants.SERVER_CONSOLE_UID)) { + int historyLength = this.history.get(player.getUid()).get(GameConstants.SERVER_CONSOLE_UID).size(); + var messages = this.history.get(player.getUid()).get(GameConstants.SERVER_CONSOLE_UID).subList(Math.max(historyLength - 3, 0), historyLength); + player.sendPacket(new PacketPullRecentChatRsp(messages)); + } + else { + player.sendPacket(new PacketPullRecentChatRsp(List.of())); + } + } - /******************** - * Sending messages - ********************/ - public void sendPrivateMessageFromServer(int targetUid, String message) { - // Sanity checks. - if (message == null || message.length() == 0) { - return; - } - - // Get target. - Player target = getServer().getPlayerByUid(targetUid); - if (target == null) { - return; - } + /******************** + * Sending messages + ********************/ + public void sendPrivateMessageFromServer(int targetUid, String message) { + // Sanity checks. + if (message == null || message.length() == 0) { + return; + } - // Create chat packet and put in history. - var packet = new PacketPrivateChatNotify(GameConstants.SERVER_CONSOLE_UID, targetUid, message); - putInHistory(targetUid, GameConstants.SERVER_CONSOLE_UID, packet.getChatInfo()); + // Get target. + Player target = getServer().getPlayerByUid(targetUid); + if (target == null) { + return; + } - // Send. - target.sendPacket(packet); - } - public void sendPrivateMessageFromServer(int targetUid, int emote) { - // Get target. - Player target = getServer().getPlayerByUid(targetUid); - if (target == null) { - return; - } + // Create chat packet and put in history. + var packet = new PacketPrivateChatNotify(GameConstants.SERVER_CONSOLE_UID, targetUid, message); + putInHistory(targetUid, GameConstants.SERVER_CONSOLE_UID, packet.getChatInfo()); - // Create chat packet and put in history. - var packet = new PacketPrivateChatNotify(GameConstants.SERVER_CONSOLE_UID, targetUid, emote); - putInHistory(targetUid, GameConstants.SERVER_CONSOLE_UID, packet.getChatInfo()); + // Send. + target.sendPacket(packet); + } + public void sendPrivateMessageFromServer(int targetUid, int emote) { + // Get target. + Player target = getServer().getPlayerByUid(targetUid); + if (target == null) { + return; + } - // Send. - target.sendPacket(packet); - } + // Create chat packet and put in history. + var packet = new PacketPrivateChatNotify(GameConstants.SERVER_CONSOLE_UID, targetUid, emote); + putInHistory(targetUid, GameConstants.SERVER_CONSOLE_UID, packet.getChatInfo()); - public void sendPrivateMessage(Player player, int targetUid, String message) { - // Sanity checks. - if (message == null || message.length() == 0) { - return; - } - - // Get target. - Player target = getServer().getPlayerByUid(targetUid); + // Send. + target.sendPacket(packet); + } - // Check if command - if (tryInvokeCommand(player, target, message)) { - return; - } + public void sendPrivateMessage(Player player, int targetUid, String message) { + // Sanity checks. + if (message == null || message.length() == 0) { + return; + } - if (target == null && targetUid != GameConstants.SERVER_CONSOLE_UID) { - return; - } + // Get target. + Player target = getServer().getPlayerByUid(targetUid); - // Create chat packet. - var packet = new PacketPrivateChatNotify(player.getUid(), targetUid, message); + // Check if command + if (tryInvokeCommand(player, target, message)) { + return; + } - // Send and put in history. - player.sendPacket(packet); - putInHistory(player.getUid(), targetUid, packet.getChatInfo()); + if (target == null && targetUid != GameConstants.SERVER_CONSOLE_UID) { + return; + } - if (target != null) { - target.sendPacket(packet); - putInHistory(targetUid, player.getUid(), packet.getChatInfo()); - } - } + // Create chat packet. + var packet = new PacketPrivateChatNotify(player.getUid(), targetUid, message); - public void sendPrivateMessage(Player player, int targetUid, int emote) { - // Get target. - Player target = getServer().getPlayerByUid(targetUid); - - if (target == null && targetUid != GameConstants.SERVER_CONSOLE_UID) { - return; - } - - // Create chat packet. - var packet = new PacketPrivateChatNotify(player.getUid(), target.getUid(), emote); + // Send and put in history. + player.sendPacket(packet); + putInHistory(player.getUid(), targetUid, packet.getChatInfo()); - // Send and put is history. - player.sendPacket(packet); - putInHistory(player.getUid(), targetUid, packet.getChatInfo()); + if (target != null) { + target.sendPacket(packet); + putInHistory(targetUid, player.getUid(), packet.getChatInfo()); + } + } - if (target != null) { - target.sendPacket(packet); - putInHistory(targetUid, player.getUid(), packet.getChatInfo()); - } - } + public void sendPrivateMessage(Player player, int targetUid, int emote) { + // Get target. + Player target = getServer().getPlayerByUid(targetUid); - public void sendTeamMessage(Player player, int channel, String message) { - // Sanity checks - if (message == null || message.length() == 0) { - return; - } + if (target == null && targetUid != GameConstants.SERVER_CONSOLE_UID) { + return; + } - // Check if command - if (tryInvokeCommand(player, null, message)) { - return; - } + // Create chat packet. + var packet = new PacketPrivateChatNotify(player.getUid(), target.getUid(), emote); - // Create and send chat packet - player.getWorld().broadcastPacket(new PacketPlayerChatNotify(player, channel, message)); - } - public void sendTeamMessage(Player player, int channel, int icon) { - // Create and send chat packet - player.getWorld().broadcastPacket(new PacketPlayerChatNotify(player, channel, icon)); - } + // Send and put is history. + player.sendPacket(packet); + putInHistory(player.getUid(), targetUid, packet.getChatInfo()); - /******************** - * Welcome messages - ********************/ - public void sendServerWelcomeMessages(Player player) { - var joinOptions = GAME_INFO.joinOptions; - - if (joinOptions.welcomeEmotes != null && joinOptions.welcomeEmotes.length > 0) { - this.sendPrivateMessageFromServer(player.getUid(), joinOptions.welcomeEmotes[Utils.randomRange(0, joinOptions.welcomeEmotes.length - 1)]); - } - - if (joinOptions.welcomeMessage != null && joinOptions.welcomeMessage.length() > 0) { - this.sendPrivateMessageFromServer(player.getUid(), joinOptions.welcomeMessage); - } + if (target != null) { + target.sendPacket(packet); + putInHistory(targetUid, player.getUid(), packet.getChatInfo()); + } + } - this.sendPrivateMessageFromServer(player.getUid(), "THIS IS AN EXPERIMENTAL BUILD OF GRASSCUTTER FOR 2.7.50/2.8\nDON'T LEAK <3"); - } + public void sendTeamMessage(Player player, int channel, String message) { + // Sanity checks + if (message == null || message.length() == 0) { + return; + } + + // Check if command + if (tryInvokeCommand(player, null, message)) { + return; + } + + // Create and send chat packet + player.getWorld().broadcastPacket(new PacketPlayerChatNotify(player, channel, message)); + } + public void sendTeamMessage(Player player, int channel, int icon) { + // Create and send chat packet + player.getWorld().broadcastPacket(new PacketPlayerChatNotify(player, channel, icon)); + } + + /******************** + * Welcome messages + ********************/ + public void sendServerWelcomeMessages(Player player) { + var joinOptions = GAME_INFO.joinOptions; + + if (joinOptions.welcomeEmotes != null && joinOptions.welcomeEmotes.length > 0) { + this.sendPrivateMessageFromServer(player.getUid(), joinOptions.welcomeEmotes[Utils.randomRange(0, joinOptions.welcomeEmotes.length - 1)]); + } + + if (joinOptions.welcomeMessage != null && joinOptions.welcomeMessage.length() > 0) { + this.sendPrivateMessageFromServer(player.getUid(), joinOptions.welcomeMessage); + } + + this.sendPrivateMessageFromServer(player.getUid(), "THIS IS AN EXPERIMENTAL BUILD OF GRASSCUTTER FOR 2.7.50/2.8\nDON'T LEAK <3"); + } } diff --git a/src/main/java/emu/grasscutter/game/managers/deforestation/DeforestationManager.java b/src/main/java/emu/grasscutter/game/managers/deforestation/DeforestationManager.java index a0fb46588..e49cad486 100644 --- a/src/main/java/emu/grasscutter/game/managers/deforestation/DeforestationManager.java +++ b/src/main/java/emu/grasscutter/game/managers/deforestation/DeforestationManager.java @@ -21,7 +21,7 @@ public class DeforestationManager extends BasePlayerManager { private final ArrayList currentRecord; private final static HashMap ColliderTypeToWoodItemID = new HashMap<>(); - + static { /* define wood types which reflected to item id*/ ColliderTypeToWoodItemID.put(1,101301); @@ -37,17 +37,17 @@ public class DeforestationManager extends BasePlayerManager { ColliderTypeToWoodItemID.put(11,101311); ColliderTypeToWoodItemID.put(12,101312); } - - public DeforestationManager(Player player){ + + public DeforestationManager(Player player) { super(player); this.currentRecord = new ArrayList<>(); } - public void resetWood(){ + public void resetWood() { synchronized (currentRecord) { currentRecord.clear(); } } - public void onDeforestationInvoke(HitTreeNotifyOuterClass.HitTreeNotify hit){ + public void onDeforestationInvoke(HitTreeNotifyOuterClass.HitTreeNotify hit) { synchronized (currentRecord) { //Grasscutter.getLogger().info("onDeforestationInvoke! Wood records {}", currentRecord); VectorOuterClass.Vector hitPosition = hit.getTreePos(); @@ -59,14 +59,14 @@ public class DeforestationManager extends BasePlayerManager { HitTreeRecord record = searchRecord(positionHash); if (record == null) { record = new HitTreeRecord(positionHash); - }else{ + }else { currentRecord.remove(record);// move it to last position } currentRecord.add(record); - if(currentRecord.size()>RECORD_MAX_TIMES_OTHER_HIT_TREE){ + if (currentRecord.size()>RECORD_MAX_TIMES_OTHER_HIT_TREE) { currentRecord.remove(0); } - if(record.record()) { + if (record.record()) { EntityItem entity = new EntityItem(scene, null, GameData.getItemDataMap().get(itemId), @@ -82,7 +82,7 @@ public class DeforestationManager extends BasePlayerManager { } // unknown wood type } - private HitTreeRecord searchRecord(int id){ + private HitTreeRecord searchRecord(int id) { for (HitTreeRecord record : currentRecord) { if (record.getUnique() == id) { return record; diff --git a/src/main/java/emu/grasscutter/game/managers/energy/EnergyManager.java b/src/main/java/emu/grasscutter/game/managers/energy/EnergyManager.java index 710ec31a4..e94a219fc 100644 --- a/src/main/java/emu/grasscutter/game/managers/energy/EnergyManager.java +++ b/src/main/java/emu/grasscutter/game/managers/energy/EnergyManager.java @@ -448,4 +448,4 @@ public class EnergyManager extends BasePlayerManager { } } } -} \ No newline at end of file +} diff --git a/src/main/java/emu/grasscutter/game/managers/forging/ForgingManager.java b/src/main/java/emu/grasscutter/game/managers/forging/ForgingManager.java index 9cd3dc63b..50aeb94a8 100644 --- a/src/main/java/emu/grasscutter/game/managers/forging/ForgingManager.java +++ b/src/main/java/emu/grasscutter/game/managers/forging/ForgingManager.java @@ -30,298 +30,298 @@ import emu.grasscutter.utils.Utils; public class ForgingManager extends BasePlayerManager { - public ForgingManager(Player player) { - super(player); - } + public ForgingManager(Player player) { + super(player); + } - /********** - Blueprint unlocking. - **********/ - public synchronized boolean unlockForgingBlueprint(GameItem blueprintItem) { - // Make sure this is actually a forging blueprint. - if (!blueprintItem.getItemData().getItemUse().get(0).getUseOp().equals("ITEM_USE_UNLOCK_FORGE")) { - return false; - } + /********** + Blueprint unlocking. + **********/ + public synchronized boolean unlockForgingBlueprint(GameItem blueprintItem) { + // Make sure this is actually a forging blueprint. + if (!blueprintItem.getItemData().getItemUse().get(0).getUseOp().equals("ITEM_USE_UNLOCK_FORGE")) { + return false; + } - // Determine the forging item we should unlock. - int forgeId = Integer.parseInt(blueprintItem.getItemData().getItemUse().get(0).getUseParam().get(0)); + // Determine the forging item we should unlock. + int forgeId = Integer.parseInt(blueprintItem.getItemData().getItemUse().get(0).getUseParam().get(0)); - // Remove the blueprint from the player's inventory. - // We need to do this here, before sending ForgeFormulaDataNotify, or the the forging UI won't correctly - // update when unlocking the blueprint. - player.getInventory().removeItem(blueprintItem, 1); + // Remove the blueprint from the player's inventory. + // We need to do this here, before sending ForgeFormulaDataNotify, or the the forging UI won't correctly + // update when unlocking the blueprint. + player.getInventory().removeItem(blueprintItem, 1); - // Tell the client that this blueprint is now unlocked and add the unlocked item to the player. - this.player.getUnlockedForgingBlueprints().add(forgeId); - this.player.sendPacket(new PacketForgeFormulaDataNotify(forgeId)); + // Tell the client that this blueprint is now unlocked and add the unlocked item to the player. + this.player.getUnlockedForgingBlueprints().add(forgeId); + this.player.sendPacket(new PacketForgeFormulaDataNotify(forgeId)); - return true; - } + return true; + } - /********** - Communicate forging information to the client. - **********/ - private synchronized int determineNumberOfQueues() { - int adventureRank = player.getLevel(); - return - (adventureRank >= 15) ? 4 - : (adventureRank >= 10) ? 3 - : (adventureRank >= 5) ? 2 - : 1; - } + /********** + Communicate forging information to the client. + **********/ + private synchronized int determineNumberOfQueues() { + int adventureRank = player.getLevel(); + return + (adventureRank >= 15) ? 4 + : (adventureRank >= 10) ? 3 + : (adventureRank >= 5) ? 2 + : 1; + } - private synchronized Map determineCurrentForgeQueueData() { - Map res = new HashMap<>(); - int currentTime = Utils.getCurrentSeconds(); + private synchronized Map determineCurrentForgeQueueData() { + Map res = new HashMap<>(); + int currentTime = Utils.getCurrentSeconds(); - // Create queue information for all active forges. - for (int i = 0; i < this.player.getActiveForges().size(); i++) { - ActiveForgeData activeForge = this.player.getActiveForges().get(i); + // Create queue information for all active forges. + for (int i = 0; i < this.player.getActiveForges().size(); i++) { + ActiveForgeData activeForge = this.player.getActiveForges().get(i); - ForgeQueueData data = ForgeQueueData.newBuilder() - .setQueueId(i + 1) - .setForgeId(activeForge.getForgeId()) - .setFinishCount(activeForge.getFinishedCount(currentTime)) - .setUnfinishCount(activeForge.getUnfinishedCount(currentTime)) - .setTotalFinishTimestamp(activeForge.getTotalFinishTimestamp()) - .setNextFinishTimestamp(activeForge.getNextFinishTimestamp(currentTime)) - .setAvatarId(activeForge.getAvatarId()) - .build(); + ForgeQueueData data = ForgeQueueData.newBuilder() + .setQueueId(i + 1) + .setForgeId(activeForge.getForgeId()) + .setFinishCount(activeForge.getFinishedCount(currentTime)) + .setUnfinishCount(activeForge.getUnfinishedCount(currentTime)) + .setTotalFinishTimestamp(activeForge.getTotalFinishTimestamp()) + .setNextFinishTimestamp(activeForge.getNextFinishTimestamp(currentTime)) + .setAvatarId(activeForge.getAvatarId()) + .build(); - res.put(i + 1, data); - } + res.put(i + 1, data); + } - return res; - } + return res; + } - public synchronized void sendForgeDataNotify() { - // Determine the number of queues and unlocked items. - int numQueues = this.determineNumberOfQueues(); - var unlockedItems = this.player.getUnlockedForgingBlueprints(); - var queueData = this.determineCurrentForgeQueueData(); + public synchronized void sendForgeDataNotify() { + // Determine the number of queues and unlocked items. + int numQueues = this.determineNumberOfQueues(); + var unlockedItems = this.player.getUnlockedForgingBlueprints(); + var queueData = this.determineCurrentForgeQueueData(); - // Send notification. - this.player.sendPacket(new PacketForgeDataNotify(unlockedItems, numQueues, queueData)); - } - - public synchronized void handleForgeGetQueueDataReq() { - // Determine the number of queues. - int numQueues = this.determineNumberOfQueues(); - var queueData = this.determineCurrentForgeQueueData(); + // Send notification. + this.player.sendPacket(new PacketForgeDataNotify(unlockedItems, numQueues, queueData)); + } - // Reply. - this.player.sendPacket(new PacketForgeGetQueueDataRsp(Retcode.RET_SUCC, numQueues, queueData)); - } + public synchronized void handleForgeGetQueueDataReq() { + // Determine the number of queues. + int numQueues = this.determineNumberOfQueues(); + var queueData = this.determineCurrentForgeQueueData(); - /********** - Initiate forging process. - **********/ - private synchronized void sendForgeQueueDataNotify() { - var queueData = this.determineCurrentForgeQueueData(); - this.player.sendPacket(new PacketForgeQueueDataNotify(queueData, List.of())); - } - private synchronized void sendForgeQueueDataNotify(boolean hasRemoved) { - var queueData = this.determineCurrentForgeQueueData(); + // Reply. + this.player.sendPacket(new PacketForgeGetQueueDataRsp(Retcode.RET_SUCC, numQueues, queueData)); + } - if (hasRemoved) { - this.player.sendPacket(new PacketForgeQueueDataNotify(Map.of(), List.of(1, 2, 3, 4))); - } + /********** + Initiate forging process. + **********/ + private synchronized void sendForgeQueueDataNotify() { + var queueData = this.determineCurrentForgeQueueData(); + this.player.sendPacket(new PacketForgeQueueDataNotify(queueData, List.of())); + } + private synchronized void sendForgeQueueDataNotify(boolean hasRemoved) { + var queueData = this.determineCurrentForgeQueueData(); - this.player.sendPacket(new PacketForgeQueueDataNotify(queueData, List.of())); - } + if (hasRemoved) { + this.player.sendPacket(new PacketForgeQueueDataNotify(Map.of(), List.of(1, 2, 3, 4))); + } - public synchronized void handleForgeStartReq(ForgeStartReq req) { - // Refuse if all queues are already full. - if (this.player.getActiveForges().size() >= this.determineNumberOfQueues()) { - this.player.sendPacket(new PacketForgeStartRsp(Retcode.RET_FORGE_QUEUE_FULL)); - return; - } + this.player.sendPacket(new PacketForgeQueueDataNotify(queueData, List.of())); + } - // Get the required forging information for the target item. - if (!GameData.getForgeDataMap().containsKey(req.getForgeId())) { - this.player.sendPacket(new PacketForgeStartRsp(Retcode.RET_FAIL)); //ToDo: Probably the wrong return code. - return; - } + public synchronized void handleForgeStartReq(ForgeStartReq req) { + // Refuse if all queues are already full. + if (this.player.getActiveForges().size() >= this.determineNumberOfQueues()) { + this.player.sendPacket(new PacketForgeStartRsp(Retcode.RET_FORGE_QUEUE_FULL)); + return; + } - ForgeData forgeData = GameData.getForgeDataMap().get(req.getForgeId()); + // Get the required forging information for the target item. + if (!GameData.getForgeDataMap().containsKey(req.getForgeId())) { + this.player.sendPacket(new PacketForgeStartRsp(Retcode.RET_FAIL)); //ToDo: Probably the wrong return code. + return; + } - //Check if the player has sufficient forge points. - int requiredPoints = forgeData.getForgePoint() * req.getForgeCount(); - if (requiredPoints > this.player.getForgePoints()) { - this.player.sendPacket(new PacketForgeStartRsp(Retcode.RET_FORGE_POINT_NOT_ENOUGH)); - return; - } - - // Check if we have enough of each material and consume. - List material = new ArrayList<>(forgeData.getMaterialItems()); - material.add(new ItemParamData(202, forgeData.getScoinCost())); + ForgeData forgeData = GameData.getForgeDataMap().get(req.getForgeId()); - boolean success = player.getInventory().payItems(material.toArray(new ItemParamData[0]), req.getForgeCount(), ActionReason.ForgeCost); + //Check if the player has sufficient forge points. + int requiredPoints = forgeData.getForgePoint() * req.getForgeCount(); + if (requiredPoints > this.player.getForgePoints()) { + this.player.sendPacket(new PacketForgeStartRsp(Retcode.RET_FORGE_POINT_NOT_ENOUGH)); + return; + } - if (!success) { - this.player.sendPacket(new PacketForgeStartRsp(Retcode.RET_FORGE_POINT_NOT_ENOUGH)); //ToDo: Probably the wrong return code. - } + // Check if we have enough of each material and consume. + List material = new ArrayList<>(forgeData.getMaterialItems()); + material.add(new ItemParamData(202, forgeData.getScoinCost())); - // Consume forge points. - this.player.setForgePoints(this.player.getForgePoints() - requiredPoints); + boolean success = player.getInventory().payItems(material.toArray(new ItemParamData[0]), req.getForgeCount(), ActionReason.ForgeCost); - // Create and add active forge. - ActiveForgeData activeForge = new ActiveForgeData(); - activeForge.setForgeId(req.getForgeId()); - activeForge.setAvatarId(req.getAvatarId()); - activeForge.setCount(req.getForgeCount()); - activeForge.setStartTime(Utils.getCurrentSeconds()); - activeForge.setForgeTime(forgeData.getForgeTime()); + if (!success) { + this.player.sendPacket(new PacketForgeStartRsp(Retcode.RET_FORGE_POINT_NOT_ENOUGH)); //ToDo: Probably the wrong return code. + } - this.player.getActiveForges().add(activeForge); + // Consume forge points. + this.player.setForgePoints(this.player.getForgePoints() - requiredPoints); - // Done. - this.sendForgeQueueDataNotify(); - this.player.sendPacket(new PacketForgeStartRsp(Retcode.RET_SUCC)); - } + // Create and add active forge. + ActiveForgeData activeForge = new ActiveForgeData(); + activeForge.setForgeId(req.getForgeId()); + activeForge.setAvatarId(req.getAvatarId()); + activeForge.setCount(req.getForgeCount()); + activeForge.setStartTime(Utils.getCurrentSeconds()); + activeForge.setForgeTime(forgeData.getForgeTime()); - /********** - Forge queue manipulation (obtaining results and cancelling forges). - **********/ - private synchronized void obtainItems(int queueId) { - // Determin how many items are finished. - int currentTime = Utils.getCurrentSeconds(); - ActiveForgeData forge = this.player.getActiveForges().get(queueId - 1); + this.player.getActiveForges().add(activeForge); - int finished = forge.getFinishedCount(currentTime); - int unfinished = forge.getUnfinishedCount(currentTime); + // Done. + this.sendForgeQueueDataNotify(); + this.player.sendPacket(new PacketForgeStartRsp(Retcode.RET_SUCC)); + } - // Sanity check: Are any items finished? - if (finished <= 0) { - return; - } + /********** + Forge queue manipulation (obtaining results and cancelling forges). + **********/ + private synchronized void obtainItems(int queueId) { + // Determin how many items are finished. + int currentTime = Utils.getCurrentSeconds(); + ActiveForgeData forge = this.player.getActiveForges().get(queueId - 1); - // Give finished items to the player. - ForgeData data = GameData.getForgeDataMap().get(forge.getForgeId()); + int finished = forge.getFinishedCount(currentTime); + int unfinished = forge.getUnfinishedCount(currentTime); - int resultId = data.getResultItemId() > 0 ? data.getResultItemId() : data.getShowItemId(); - ItemData resultItemData = GameData.getItemDataMap().get(resultId); - GameItem addItem = new GameItem(resultItemData, data.getResultItemCount() * finished); - this.player.getInventory().addItem(addItem); - - // Battle pass trigger handler - this.player.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_DO_FORGE, 0, finished); + // Sanity check: Are any items finished? + if (finished <= 0) { + return; + } - // Replace active forge with a new one for the unfinished items, if there are any. - if (unfinished > 0) { - ActiveForgeData remainingForge = new ActiveForgeData(); + // Give finished items to the player. + ForgeData data = GameData.getForgeDataMap().get(forge.getForgeId()); - remainingForge.setForgeId(forge.getForgeId()); - remainingForge.setAvatarId(forge.getAvatarId()); - remainingForge.setCount(unfinished); - remainingForge.setForgeTime(forge.getForgeTime()); - remainingForge.setStartTime(forge.getStartTime() + finished * forge.getForgeTime()); + int resultId = data.getResultItemId() > 0 ? data.getResultItemId() : data.getShowItemId(); + ItemData resultItemData = GameData.getItemDataMap().get(resultId); + GameItem addItem = new GameItem(resultItemData, data.getResultItemCount() * finished); + this.player.getInventory().addItem(addItem); - this.player.getActiveForges().set(queueId - 1, remainingForge); - this.sendForgeQueueDataNotify(); - } - // Otherwise, completely remove it. - else { - this.player.getActiveForges().remove(queueId - 1); - // this.sendForgeQueueDataNotify(queueId); - this.sendForgeQueueDataNotify(true); - } + // Battle pass trigger handler + this.player.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_DO_FORGE, 0, finished); - // Send response. - this.player.sendPacket(new PacketForgeQueueManipulateRsp(Retcode.RET_SUCC, ForgeQueueManipulateType.FORGE_QUEUE_MANIPULATE_TYPE_RECEIVE_OUTPUT, List.of(addItem), List.of(), List.of())); - } + // Replace active forge with a new one for the unfinished items, if there are any. + if (unfinished > 0) { + ActiveForgeData remainingForge = new ActiveForgeData(); - private synchronized void cancelForge(int queueId) { - // Make sure there are no unfinished items. - int currentTime = Utils.getCurrentSeconds(); - ActiveForgeData forge = this.player.getActiveForges().get(queueId - 1); + remainingForge.setForgeId(forge.getForgeId()); + remainingForge.setAvatarId(forge.getAvatarId()); + remainingForge.setCount(unfinished); + remainingForge.setForgeTime(forge.getForgeTime()); + remainingForge.setStartTime(forge.getStartTime() + finished * forge.getForgeTime()); - if (forge.getFinishedCount(currentTime) > 0) { - return; - } - - // Return material items to the player. - ForgeData data = GameData.getForgeDataMap().get(forge.getForgeId()); + this.player.getActiveForges().set(queueId - 1, remainingForge); + this.sendForgeQueueDataNotify(); + } + // Otherwise, completely remove it. + else { + this.player.getActiveForges().remove(queueId - 1); + // this.sendForgeQueueDataNotify(queueId); + this.sendForgeQueueDataNotify(true); + } - var returnItems = new ArrayList(); - for (var material : data.getMaterialItems()) { - if (material.getItemId() == 0) { - continue; - } + // Send response. + this.player.sendPacket(new PacketForgeQueueManipulateRsp(Retcode.RET_SUCC, ForgeQueueManipulateType.FORGE_QUEUE_MANIPULATE_TYPE_RECEIVE_OUTPUT, List.of(addItem), List.of(), List.of())); + } - ItemData resultItemData = GameData.getItemDataMap().get(material.getItemId()); - GameItem returnItem = new GameItem(resultItemData, material.getItemCount() * forge.getCount()); + private synchronized void cancelForge(int queueId) { + // Make sure there are no unfinished items. + int currentTime = Utils.getCurrentSeconds(); + ActiveForgeData forge = this.player.getActiveForges().get(queueId - 1); - this.player.getInventory().addItem(returnItem); - returnItems.add(returnItem); - } + if (forge.getFinishedCount(currentTime) > 0) { + return; + } - // Return Mora to the player. - this.player.setMora(this.player.getMora() + data.getScoinCost() * forge.getCount()); + // Return material items to the player. + ForgeData data = GameData.getForgeDataMap().get(forge.getForgeId()); - ItemData moraItem = GameData.getItemDataMap().get(202); - GameItem returnMora = new GameItem(moraItem, data.getScoinCost() * forge.getCount()); - returnItems.add(returnMora); + var returnItems = new ArrayList(); + for (var material : data.getMaterialItems()) { + if (material.getItemId() == 0) { + continue; + } - // Return forge points to the player. - int requiredPoints = data.getForgePoint() * forge.getCount(); - int newPoints = Math.min(this.player.getForgePoints() + requiredPoints, 300_000); + ItemData resultItemData = GameData.getItemDataMap().get(material.getItemId()); + GameItem returnItem = new GameItem(resultItemData, material.getItemCount() * forge.getCount()); - this.player.setForgePoints(newPoints); + this.player.getInventory().addItem(returnItem); + returnItems.add(returnItem); + } - // Remove the forge queue. - this.player.getActiveForges().remove(queueId - 1); - this.sendForgeQueueDataNotify(true); + // Return Mora to the player. + this.player.setMora(this.player.getMora() + data.getScoinCost() * forge.getCount()); - // Send response. - this.player.sendPacket(new PacketForgeQueueManipulateRsp(Retcode.RET_SUCC, ForgeQueueManipulateType.FORGE_QUEUE_MANIPULATE_TYPE_STOP_FORGE, List.of(), returnItems, List.of())); - } + ItemData moraItem = GameData.getItemDataMap().get(202); + GameItem returnMora = new GameItem(moraItem, data.getScoinCost() * forge.getCount()); + returnItems.add(returnMora); - public synchronized void handleForgeQueueManipulateReq(ForgeQueueManipulateReq req) { - // Get info from the request. - int queueId = req.getForgeQueueId(); - var manipulateType = req.getManipulateType(); - - // Handle according to the manipulation type. - switch (manipulateType) { - case FORGE_QUEUE_MANIPULATE_TYPE_RECEIVE_OUTPUT: - this.obtainItems(queueId); - break; - case FORGE_QUEUE_MANIPULATE_TYPE_STOP_FORGE: - this.cancelForge(queueId); - break; - default: - break; //Should never happen. - } - } + // Return forge points to the player. + int requiredPoints = data.getForgePoint() * forge.getCount(); + int newPoints = Math.min(this.player.getForgePoints() + requiredPoints, 300_000); - /********** - Periodic forging updates. - **********/ - public synchronized void sendPlayerForgingUpdate() { - int currentTime = Utils.getCurrentSeconds(); + this.player.setForgePoints(newPoints); - // Determine if sending an update is necessary. - // We only send an update if there are forges in the forge queue - // that have changed since the last notification. - if (this.player.getActiveForges().size() <= 0) { - return; - } + // Remove the forge queue. + this.player.getActiveForges().remove(queueId - 1); + this.sendForgeQueueDataNotify(true); - boolean hasChanges = this.player.getActiveForges().stream() - .filter(forge -> forge.updateChanged(currentTime)) - .findAny() - .isPresent(); + // Send response. + this.player.sendPacket(new PacketForgeQueueManipulateRsp(Retcode.RET_SUCC, ForgeQueueManipulateType.FORGE_QUEUE_MANIPULATE_TYPE_STOP_FORGE, List.of(), returnItems, List.of())); + } - if (!hasChanges) { - return; - } + public synchronized void handleForgeQueueManipulateReq(ForgeQueueManipulateReq req) { + // Get info from the request. + int queueId = req.getForgeQueueId(); + var manipulateType = req.getManipulateType(); - // Send notification. - this.sendForgeQueueDataNotify(); + // Handle according to the manipulation type. + switch (manipulateType) { + case FORGE_QUEUE_MANIPULATE_TYPE_RECEIVE_OUTPUT: + this.obtainItems(queueId); + break; + case FORGE_QUEUE_MANIPULATE_TYPE_STOP_FORGE: + this.cancelForge(queueId); + break; + default: + break; //Should never happen. + } + } - // Reset changed flags. - this.player.getActiveForges().stream() - .forEach(forge -> forge.setChanged(false)); - } + /********** + Periodic forging updates. + **********/ + public synchronized void sendPlayerForgingUpdate() { + int currentTime = Utils.getCurrentSeconds(); + + // Determine if sending an update is necessary. + // We only send an update if there are forges in the forge queue + // that have changed since the last notification. + if (this.player.getActiveForges().size() <= 0) { + return; + } + + boolean hasChanges = this.player.getActiveForges().stream() + .filter(forge -> forge.updateChanged(currentTime)) + .findAny() + .isPresent(); + + if (!hasChanges) { + return; + } + + // Send notification. + this.sendForgeQueueDataNotify(); + + // Reset changed flags. + this.player.getActiveForges().stream() + .forEach(forge -> forge.setChanged(false)); + } } diff --git a/src/main/java/emu/grasscutter/game/managers/mapmark/MapMarksManager.java b/src/main/java/emu/grasscutter/game/managers/mapmark/MapMarksManager.java index 703385bc6..713cd69c0 100644 --- a/src/main/java/emu/grasscutter/game/managers/mapmark/MapMarksManager.java +++ b/src/main/java/emu/grasscutter/game/managers/mapmark/MapMarksManager.java @@ -18,7 +18,7 @@ public class MapMarksManager extends BasePlayerManager { public MapMarksManager(Player player) { super(player); } - + public Map getMapMarks() { return getPlayer().getMapMarks(); } @@ -51,7 +51,7 @@ public class MapMarksManager extends BasePlayerManager { } player.getSession().send(new PacketMarkMapRsp(getMapMarks())); } - + public String getMapMarkKey(Position position) { return "x" + (int)position.getX()+ "z" + (int)position.getZ(); } diff --git a/src/main/java/emu/grasscutter/game/managers/stamina/StaminaManager.java b/src/main/java/emu/grasscutter/game/managers/stamina/StaminaManager.java index b45fdac1f..b23ae0c28 100644 --- a/src/main/java/emu/grasscutter/game/managers/stamina/StaminaManager.java +++ b/src/main/java/emu/grasscutter/game/managers/stamina/StaminaManager.java @@ -159,7 +159,7 @@ public class StaminaManager extends BasePlayerManager { }}; public static void initialize() { - // TODO: Initialize foods etc. + // TODO: Initialize foods etc. } public StaminaManager(Player player) { @@ -529,20 +529,20 @@ public class StaminaManager extends BasePlayerManager { } // Bow avatar charged attack Avatar currentAvatar = player.getTeamManager().getCurrentAvatarEntity().getAvatar(); - + switch (currentAvatar.getAvatarData().getWeaponType()) { - case WEAPON_BOW: - return getBowSustainedCost(skillCasting); - case WEAPON_CLAYMORE: - return getClaymoreSustainedCost(skillCasting); - case WEAPON_CATALYST: - return getCatalystCost(skillCasting); - case WEAPON_POLE: - return getPolearmCost(skillCasting); - case WEAPON_SWORD_ONE_HAND: - return getSwordCost(skillCasting); + case WEAPON_BOW: + return getBowSustainedCost(skillCasting); + case WEAPON_CLAYMORE: + return getClaymoreSustainedCost(skillCasting); + case WEAPON_CATALYST: + return getCatalystCost(skillCasting); + case WEAPON_POLE: + return getPolearmCost(skillCasting); + case WEAPON_SWORD_ONE_HAND: + return getSwordCost(skillCasting); } - + return new Consumption(); } diff --git a/src/main/java/emu/grasscutter/game/player/BasePlayerDataManager.java b/src/main/java/emu/grasscutter/game/player/BasePlayerDataManager.java index 68447e892..a8f70bfb4 100644 --- a/src/main/java/emu/grasscutter/game/player/BasePlayerDataManager.java +++ b/src/main/java/emu/grasscutter/game/player/BasePlayerDataManager.java @@ -4,17 +4,17 @@ import lombok.NonNull; public abstract class BasePlayerDataManager { protected transient Player player; - + public BasePlayerDataManager() {} - + public BasePlayerDataManager(@NonNull Player player) { this.player = player; } - + public Player getPlayer() { return this.player; } - + public void setPlayer(Player player) { if (this.player == null) { this.player = player; diff --git a/src/main/java/emu/grasscutter/game/player/BasePlayerManager.java b/src/main/java/emu/grasscutter/game/player/BasePlayerManager.java index 7508995c0..d3cbf9f90 100644 --- a/src/main/java/emu/grasscutter/game/player/BasePlayerManager.java +++ b/src/main/java/emu/grasscutter/game/player/BasePlayerManager.java @@ -4,15 +4,15 @@ import lombok.NonNull; public abstract class BasePlayerManager { protected transient final Player player; - + public BasePlayerManager(@NonNull Player player) { this.player = player; } - + public Player getPlayer() { return this.player; } - + /** * Saves the player to the database */ diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index df4bad584..769e79012 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -86,30 +86,30 @@ import java.util.concurrent.LinkedBlockingQueue; @Entity(value = "players", useDiscriminator = false) public class Player { - @Id private int id; - @Indexed(options = @IndexOptions(unique = true)) private String accountId; - private transient Account account; - private transient GameSession session; - - private String nickname; - private String signature; - private int headImage; - private int nameCardId = 210001; - private Position position; - private Position rotation; - private PlayerBirthday birthday; - private PlayerCodex codex; - private boolean showAvatars; - private List showAvatarList; - private Map properties; - private int currentRealmId; - private int widgetId; - private int sceneId; + @Id private int id; + @Indexed(options = @IndexOptions(unique = true)) private String accountId; + private transient Account account; + private transient GameSession session; + + private String nickname; + private String signature; + private int headImage; + private int nameCardId = 210001; + private Position position; + private Position rotation; + private PlayerBirthday birthday; + private PlayerCodex codex; + private boolean showAvatars; + private List showAvatarList; + private Map properties; + private int currentRealmId; + private int widgetId; + private int sceneId; private int regionId; private int mainCharacterId; private boolean godmode; private boolean stamina; - + @Getter private Set nameCardList; @Getter private Set flyCloakList; @Getter private Set costumeList; @@ -123,23 +123,23 @@ public class Player { @Getter private Map unlockedRecipies; @Getter private List activeForges; - @Transient private long nextGuid = 0; - @Transient private int peerId; - @Transient private World world; - @Transient private Scene scene; - @Transient @Getter private int weatherId = 0; - @Transient @Getter private ClimateType climate = ClimateType.CLIMATE_SUNNY; - - // Player managers go here - @Getter private transient AvatarStorage avatars; - @Getter private transient Inventory inventory; - @Getter private transient FriendsList friendsList; - @Getter private transient MailHandler mailHandler; - @Getter private transient MessageHandler messageHandler; - @Getter private transient AbilityManager abilityManager; - @Getter private transient QuestManager questManager; - @Getter private transient TowerManager towerManager; - @Getter private transient SotSManager sotsManager; + @Transient private long nextGuid = 0; + @Transient private int peerId; + @Transient private World world; + @Transient private Scene scene; + @Transient @Getter private int weatherId = 0; + @Transient @Getter private ClimateType climate = ClimateType.CLIMATE_SUNNY; + + // Player managers go here + @Getter private transient AvatarStorage avatars; + @Getter private transient Inventory inventory; + @Getter private transient FriendsList friendsList; + @Getter private transient MailHandler mailHandler; + @Getter private transient MessageHandler messageHandler; + @Getter private transient AbilityManager abilityManager; + @Getter private transient QuestManager questManager; + @Getter private transient TowerManager towerManager; + @Getter private transient SotSManager sotsManager; @Getter private transient MapMarksManager mapMarksManager; @Getter private transient StaminaManager staminaManager; @Getter private transient EnergyManager energyManager; @@ -154,1276 +154,1276 @@ public class Player { // Manager data (Save-able to the database) private PlayerProfile playerProfile; private TeamManager teamManager; - private TowerData towerData; - private PlayerGachaInfo gachaInfo; - private PlayerOpenStateManager openStateManager; - private PlayerCollectionRecords collectionRecordStore; - private ArrayList shopLimit; - - @Getter private transient GameHome home; + private TowerData towerData; + private PlayerGachaInfo gachaInfo; + private PlayerOpenStateManager openStateManager; + private PlayerCollectionRecords collectionRecordStore; + private ArrayList shopLimit; - private boolean moonCard; - private Date moonCardStartTime; - private int moonCardDuration; - private Set moonCardGetTimes; + @Getter private transient GameHome home; - @Transient private boolean paused; - @Transient private int enterSceneToken; - @Transient private SceneLoadState sceneState; - @Transient private boolean hasSentAvatarDataNotify; - @Transient private long nextSendPlayerLocTime = 0; + private boolean moonCard; + private Date moonCardStartTime; + private int moonCardDuration; + private Set moonCardGetTimes; - private transient final Int2ObjectMap coopRequests; - private transient final Queue attackResults; - @Getter private transient final InvokeHandler combatInvokeHandler; - @Getter private transient final InvokeHandler abilityInvokeHandler; - @Getter private transient final InvokeHandler clientAbilityInitFinishHandler; + @Transient private boolean paused; + @Transient private int enterSceneToken; + @Transient private SceneLoadState sceneState; + @Transient private boolean hasSentAvatarDataNotify; + @Transient private long nextSendPlayerLocTime = 0; - private long springLastUsed; - private HashMap mapMarks; - private int nextResinRefresh; - private int lastDailyReset; + private transient final Int2ObjectMap coopRequests; + private transient final Queue attackResults; + @Getter private transient final InvokeHandler combatInvokeHandler; + @Getter private transient final InvokeHandler abilityInvokeHandler; + @Getter private transient final InvokeHandler clientAbilityInitFinishHandler; - @Deprecated - @SuppressWarnings({"rawtypes", "unchecked"}) // Morphia only! - public Player() { - this.inventory = new Inventory(this); - this.avatars = new AvatarStorage(this); - this.friendsList = new FriendsList(this); - this.mailHandler = new MailHandler(this); - this.towerManager = new TowerManager(this); - this.abilityManager = new AbilityManager(this); - this.deforestationManager = new DeforestationManager(this); - this.questManager = new QuestManager(this); - this.position = new Position(GameConstants.START_POSITION); - this.rotation = new Position(0, 307, 0); - this.sceneId = 3; + private long springLastUsed; + private HashMap mapMarks; + private int nextResinRefresh; + private int lastDailyReset; + + @Deprecated + @SuppressWarnings({"rawtypes", "unchecked"}) // Morphia only! + public Player() { + this.inventory = new Inventory(this); + this.avatars = new AvatarStorage(this); + this.friendsList = new FriendsList(this); + this.mailHandler = new MailHandler(this); + this.towerManager = new TowerManager(this); + this.abilityManager = new AbilityManager(this); + this.deforestationManager = new DeforestationManager(this); + this.questManager = new QuestManager(this); + this.position = new Position(GameConstants.START_POSITION); + this.rotation = new Position(0, 307, 0); + this.sceneId = 3; this.regionId = 1; - this.properties = new HashMap<>(); - for (PlayerProperty prop : PlayerProperty.values()) { - if (prop.getId() < 10000) { - continue; - } - this.properties.put(prop.getId(), 0); - } + this.properties = new HashMap<>(); + for (PlayerProperty prop : PlayerProperty.values()) { + if (prop.getId() < 10000) { + continue; + } + this.properties.put(prop.getId(), 0); + } - this.gachaInfo = new PlayerGachaInfo(); - this.nameCardList = new HashSet<>(); - this.flyCloakList = new HashSet<>(); - this.costumeList = new HashSet<>(); - this.towerData = new TowerData(); - this.collectionRecordStore = new PlayerCollectionRecords(); - this.unlockedForgingBlueprints = new HashSet<>(); - this.unlockedCombines = new HashSet<>(); - this.unlockedFurniture = new HashSet<>(); - this.unlockedFurnitureSuite = new HashSet<>(); - this.activeForges = new ArrayList<>(); - this.unlockedRecipies = new HashMap<>(); - this.sceneState = SceneLoadState.NONE; + this.gachaInfo = new PlayerGachaInfo(); + this.nameCardList = new HashSet<>(); + this.flyCloakList = new HashSet<>(); + this.costumeList = new HashSet<>(); + this.towerData = new TowerData(); + this.collectionRecordStore = new PlayerCollectionRecords(); + this.unlockedForgingBlueprints = new HashSet<>(); + this.unlockedCombines = new HashSet<>(); + this.unlockedFurniture = new HashSet<>(); + this.unlockedFurnitureSuite = new HashSet<>(); + this.activeForges = new ArrayList<>(); + this.unlockedRecipies = new HashMap<>(); + this.sceneState = SceneLoadState.NONE; - this.attackResults = new LinkedBlockingQueue<>(); - this.coopRequests = new Int2ObjectOpenHashMap<>(); - this.combatInvokeHandler = new InvokeHandler(PacketCombatInvocationsNotify.class); - this.abilityInvokeHandler = new InvokeHandler(PacketAbilityInvocationsNotify.class); - this.clientAbilityInitFinishHandler = new InvokeHandler(PacketClientAbilityInitFinishNotify.class); + this.attackResults = new LinkedBlockingQueue<>(); + this.coopRequests = new Int2ObjectOpenHashMap<>(); + this.combatInvokeHandler = new InvokeHandler(PacketCombatInvocationsNotify.class); + this.abilityInvokeHandler = new InvokeHandler(PacketAbilityInvocationsNotify.class); + this.clientAbilityInitFinishHandler = new InvokeHandler(PacketClientAbilityInitFinishNotify.class); - this.birthday = new PlayerBirthday(); - this.rewardedLevels = new HashSet<>(); - this.moonCardGetTimes = new HashSet<>(); - this.codex = new PlayerCodex(this); + this.birthday = new PlayerBirthday(); + this.rewardedLevels = new HashSet<>(); + this.moonCardGetTimes = new HashSet<>(); + this.codex = new PlayerCodex(this); this.openStateManager = new PlayerOpenStateManager(this); - this.shopLimit = new ArrayList<>(); - this.expeditionInfo = new HashMap<>(); - this.messageHandler = null; - this.mapMarksManager = new MapMarksManager(this); - this.staminaManager = new StaminaManager(this); - this.sotsManager = new SotSManager(this); - this.energyManager = new EnergyManager(this); - this.resinManager = new ResinManager(this); - this.forgingManager = new ForgingManager(this); - this.furnitureManager = new FurnitureManager(this); - this.cookingManager = new CookingManager(this); - } - - // On player creation - public Player(GameSession session) { - this(); - this.account = session.getAccount(); - this.accountId = this.getAccount().getId(); - this.session = session; - this.nickname = "Traveler"; - this.signature = ""; - this.teamManager = new TeamManager(this); - this.birthday = new PlayerBirthday(); - this.codex = new PlayerCodex(this); - this.setProperty(PlayerProperty.PROP_PLAYER_LEVEL, 1, false); - this.setProperty(PlayerProperty.PROP_IS_SPRING_AUTO_USE, 1, false); - this.setProperty(PlayerProperty.PROP_SPRING_AUTO_USE_PERCENT, 50, false); - this.setProperty(PlayerProperty.PROP_IS_FLYABLE, 1, false); - this.setProperty(PlayerProperty.PROP_IS_TRANSFERABLE, 1, false); - this.setProperty(PlayerProperty.PROP_MAX_STAMINA, 24000, false); - this.setProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA, 24000, false); - this.setProperty(PlayerProperty.PROP_PLAYER_RESIN, 160, false); - this.getFlyCloakList().add(140001); - this.getNameCardList().add(210001); - this.messageHandler = null; - this.mapMarksManager = new MapMarksManager(this); - this.staminaManager = new StaminaManager(this); - this.sotsManager = new SotSManager(this); - this.energyManager = new EnergyManager(this); - this.resinManager = new ResinManager(this); - this.deforestationManager = new DeforestationManager(this); - this.forgingManager = new ForgingManager(this); - this.furnitureManager = new FurnitureManager(this); - this.cookingManager = new CookingManager(this); - } - - public int getUid() { - return id; - } - - public void setUid(int id) { - this.id = id; - } - - public long getNextGameGuid() { - long nextId = ++this.nextGuid; - return ((long) this.getUid() << 32) + nextId; - } - - public Account getAccount() { - if (this.account == null) - this.account = DatabaseHelper.getAccountById(Integer.toString(this.id)); - return this.account; - } - - public void setAccount(Account account) { - this.account = account; - } - - public GameSession getSession() { - return session; - } - - public void setSession(GameSession session) { - this.session = session; - } - - public boolean isOnline() { - return this.getSession() != null && this.getSession().isActive(); - } - - public GameServer getServer() { - return this.getSession().getServer(); - } - - public synchronized World getWorld() { - return this.world; - } - - public synchronized void setWorld(World world) { - this.world = world; - } - - public synchronized Scene getScene() { - return scene; - } - - public synchronized void setScene(Scene scene) { - this.scene = scene; - } - - synchronized public void setClimate(ClimateType climate) { - this.climate = climate; - this.session.send(new PacketSceneAreaWeatherNotify(this)); - } - - synchronized public void setWeather(int weather) { - this.setWeather(weather, ClimateType.CLIMATE_NONE); - } - - synchronized public void setWeather(int weatherId, ClimateType climate) { - // Lookup default climate for this weather - if (climate == ClimateType.CLIMATE_NONE) { - WeatherData w = GameData.getWeatherDataMap().get(weatherId); - if (w != null) { - climate = w.getDefaultClimate(); - } - } - this.weatherId = weatherId; - this.climate = climate; - this.session.send(new PacketSceneAreaWeatherNotify(this)); - } - - public String getNickname() { - return nickname; - } - - public void setNickname(String nickName) { - this.nickname = nickName; - this.updateProfile(); - } - - public int getHeadImage() { - return headImage; - } - - public void setHeadImage(int picture) { - this.headImage = picture; - this.updateProfile(); - } - - public String getSignature() { - return signature; - } - - public void setSignature(String signature) { - this.signature = signature; - this.updateProfile(); - } - - public Integer getWidgetId() { - return widgetId; - } - - public void setWidgetId(Integer widgetId) { - this.widgetId = widgetId; - } - - public void setRealmList(Set realmList) { - this.realmList = realmList; - } - - public void addRealmList(int realmId) { - if (this.realmList == null) { - this.realmList = new HashSet<>(); - } else if (this.realmList.contains(realmId)) { - return; - } - this.realmList.add(realmId); - } - - public int getCurrentRealmId() { - return currentRealmId; - } - - public void setCurrentRealmId(int currentRealmId) { - this.currentRealmId = currentRealmId; - } - - public Position getPosition() { - return position; - } - - public Position getRotation() { - return rotation; - } - - public int getLevel() { - return this.getProperty(PlayerProperty.PROP_PLAYER_LEVEL); - } - - public boolean setLevel(int level) { - if (this.getLevel() == level) { - return true; - } - - if (this.setProperty(PlayerProperty.PROP_PLAYER_LEVEL, level)) { - // Update world level and profile. - this.updateWorldLevel(); - this.updateProfile(); - - // Handle OpenState unlocks from level-up. - this.getOpenStateManager().unlockLevelDependentStates(); - - return true; - } - return false; - } - - public int getExp() { - return this.getProperty(PlayerProperty.PROP_PLAYER_EXP); - } - - public int getWorldLevel() { - return this.getProperty(PlayerProperty.PROP_PLAYER_WORLD_LEVEL); - } - - public boolean setWorldLevel(int level) { - if (this.setProperty(PlayerProperty.PROP_PLAYER_WORLD_LEVEL, level)) { - if (this.world.getHost() == this) // Don't update World's WL if we are in someone else's world - this.world.setWorldLevel(level); - this.updateProfile(); - return true; - } - return false; - } - - public int getForgePoints() { - return this.getProperty(PlayerProperty.PROP_PLAYER_FORGE_POINT); - } - - public boolean setForgePoints(int value) { - if (value == this.getForgePoints()) { - return true; - } - - return this.setProperty(PlayerProperty.PROP_PLAYER_FORGE_POINT, value); - } - - public int getPrimogems() { - return this.getProperty(PlayerProperty.PROP_PLAYER_HCOIN); - } - - public boolean setPrimogems(int primogem) { - return this.setProperty(PlayerProperty.PROP_PLAYER_HCOIN, primogem); - } - - public int getMora() { - return this.getProperty(PlayerProperty.PROP_PLAYER_SCOIN); - } - - public boolean setMora(int mora) { - return this.setProperty(PlayerProperty.PROP_PLAYER_SCOIN, mora); - } - - public int getCrystals() { - return this.getProperty(PlayerProperty.PROP_PLAYER_MCOIN); - } - - public boolean setCrystals(int crystals) { - return this.setProperty(PlayerProperty.PROP_PLAYER_MCOIN, crystals); - } - - public int getHomeCoin() { - return this.getProperty(PlayerProperty.PROP_PLAYER_HOME_COIN); - } - - public boolean setHomeCoin(int coin) { - return this.setProperty(PlayerProperty.PROP_PLAYER_HOME_COIN, coin); - } - private int getExpRequired(int level) { - PlayerLevelData levelData = GameData.getPlayerLevelDataMap().get(level); - return levelData != null ? levelData.getExp() : 0; - } - - private float getExpModifier() { - return GAME_OPTIONS.rates.adventureExp; - } - - // Affected by exp rate - public void earnExp(int exp) { - addExpDirectly((int) (exp * getExpModifier())); - } - - // Directly give player exp - public void addExpDirectly(int gain) { - int level = getLevel(); - int exp = getExp(); - int reqExp = getExpRequired(level); - - exp += gain; - - while (exp >= reqExp && reqExp > 0) { - exp -= reqExp; - level += 1; - reqExp = getExpRequired(level); - - // Set level each time to allow level-up specific logic to run. - this.setLevel(level); - } - - // Set exp - this.setProperty(PlayerProperty.PROP_PLAYER_EXP, exp); - } - - private void updateWorldLevel() { - int currentWorldLevel = this.getWorldLevel(); - int currentLevel = this.getLevel(); - - int newWorldLevel = - (currentLevel >= 55) ? 8 : - (currentLevel >= 50) ? 7 : - (currentLevel >= 45) ? 6 : - (currentLevel >= 40) ? 5 : - (currentLevel >= 35) ? 4 : - (currentLevel >= 30) ? 3 : - (currentLevel >= 25) ? 2 : - (currentLevel >= 20) ? 1 : - 0; - - if (newWorldLevel != currentWorldLevel) { - this.setWorldLevel(newWorldLevel); - } - } - - private void updateProfile() { - getProfile().syncWithCharacter(this); - } - - public boolean isFirstLoginEnterScene() { - return !this.hasSentAvatarDataNotify; - } - - public TeamManager getTeamManager() { - return this.teamManager; - } - - public TowerData getTowerData() { - if (towerData == null) { - // because of mistake, null may be saved as storage at some machine, this if can be removed in future - towerData = new TowerData(); - } - return towerData; - } - - public PlayerGachaInfo getGachaInfo() { - return gachaInfo; - } - - public PlayerProfile getProfile() { - if (this.playerProfile == null) { - this.playerProfile = new PlayerProfile(this); - } - return playerProfile; - } - - // TODO: Based on the proto, property value could be int or float. - // Although there's no float value at this moment, our code should be prepared for float values. - public Map getProperties() { - return properties; - } - - public boolean setProperty(PlayerProperty prop, int value) { - return setPropertyWithSanityCheck(prop, value, true); - } - - public boolean setProperty(PlayerProperty prop, int value, boolean sendPacket) { - return setPropertyWithSanityCheck(prop, value, sendPacket); - } - - public int getProperty(PlayerProperty prop) { - return getProperties().get(prop.getId()); - } - - public MpSettingType getMpSetting() { - return MpSettingType.MP_SETTING_TYPE_ENTER_AFTER_APPLY; // TEMP - } - - public Queue getAttackResults() { - return this.attackResults; - } - - public synchronized Int2ObjectMap getCoopRequests() { - return coopRequests; - } - - public int getEnterSceneToken() { - return enterSceneToken; - } - - public void setEnterSceneToken(int enterSceneToken) { - this.enterSceneToken = enterSceneToken; - } - - public int getNameCardId() { - return nameCardId; - } - - public void setNameCardId(int nameCardId) { - this.nameCardId = nameCardId; - this.updateProfile(); - } - - public int getMainCharacterId() { - return mainCharacterId; - } - - public void setMainCharacterId(int mainCharacterId) { - this.mainCharacterId = mainCharacterId; - } - - public int getPeerId() { - return peerId; - } - - public void setPeerId(int peerId) { - this.peerId = peerId; - } - - public int getClientTime() { - return session.getClientTime(); - } - - public long getLastPingTime() { - return session.getLastPingTime(); - } - - public boolean isPaused() { - return paused; - } - - public void setPaused(boolean newPauseState) { - boolean oldPauseState = this.paused; - this.paused = newPauseState; - - if (newPauseState && !oldPauseState) { - this.onPause(); - } else if (oldPauseState && !newPauseState) { - this.onUnpause(); - } - } - - public long getSpringLastUsed() { - return springLastUsed; - } - - public void setSpringLastUsed(long val) { - springLastUsed = val; - } - - public int getNextResinRefresh() { - return nextResinRefresh; - } - - public void setNextResinRefresh(int value) { - this.nextResinRefresh = value; - } - - public SceneLoadState getSceneLoadState() { - return sceneState; - } - - public void setSceneLoadState(SceneLoadState sceneState) { - this.sceneState = sceneState; - } - - public boolean isInMultiplayer() { - return this.getWorld() != null && this.getWorld().isMultiplayer(); - } - - public int getSceneId() { - return sceneId; - } - - public void setSceneId(int sceneId) { - this.sceneId = sceneId; - } - - public int getRegionId() { - return regionId; - } - - public void setRegionId(int regionId) { - this.regionId = regionId; - } - - public void setShowAvatars(boolean showAvatars) { - this.showAvatars = showAvatars; - } - - public boolean isShowAvatars() { - return showAvatars; - } - - public void setShowAvatarList(List showAvatarList) { - this.showAvatarList = showAvatarList; - } - - public List getShowAvatarList() { - return showAvatarList; - } - - public int getLastDailyReset() { - return this.lastDailyReset; - } - - public void setLastDailyReset(int value) { - this.lastDailyReset = value; - } - - public boolean inMoonCard() { - return moonCard; - } - - public void setMoonCard(boolean moonCard) { - this.moonCard = moonCard; - } - - public void addMoonCardDays(int days) { - this.moonCardDuration += days; - } - - public int getMoonCardDuration() { - return moonCardDuration; - } - - public void setMoonCardDuration(int moonCardDuration) { - this.moonCardDuration = moonCardDuration; - } - - public Date getMoonCardStartTime() { - return moonCardStartTime; - } - - public void setMoonCardStartTime(Date moonCardStartTime) { - this.moonCardStartTime = moonCardStartTime; - } - - public Set getMoonCardGetTimes() { - return moonCardGetTimes; - } - - public void setMoonCardGetTimes(Set moonCardGetTimes) { - this.moonCardGetTimes = moonCardGetTimes; - } - - public int getMoonCardRemainDays() { - Calendar remainCalendar = Calendar.getInstance(); - remainCalendar.setTime(moonCardStartTime); - remainCalendar.add(Calendar.DATE, moonCardDuration); - Date theLastDay = remainCalendar.getTime(); - Date now = DateHelper.onlyYearMonthDay(new Date()); - return (int) ((theLastDay.getTime() - now.getTime()) / (24 * 60 * 60 * 1000)); // By copilot - } - - public void rechargeMoonCard() { - inventory.addItem(new GameItem(203, 300)); - if (!moonCard) { - moonCard = true; - Date now = new Date(); - moonCardStartTime = DateHelper.onlyYearMonthDay(now); - moonCardDuration = 30; - } else { - moonCardDuration += 30; - } - if (!moonCardGetTimes.contains(moonCardStartTime)) { - moonCardGetTimes.add(moonCardStartTime); - } - } - - public void getTodayMoonCard() { - if (!moonCard) { - return; - } - Date now = DateHelper.onlyYearMonthDay(new Date()); - if (moonCardGetTimes.contains(now)) { - return; - } - Date stopTime = new Date(); - Calendar stopCalendar = Calendar.getInstance(); - stopCalendar.setTime(stopTime); - stopCalendar.add(Calendar.DATE, moonCardDuration); - stopTime = stopCalendar.getTime(); - if (now.after(stopTime)) { - moonCard = false; - return; - } - moonCardGetTimes.add(now); - addMoonCardDays(1); - GameItem item = new GameItem(201, 90); - getInventory().addItem(item, ActionReason.BlessingRedeemReward); - session.send(new PacketCardProductRewardNotify(getMoonCardRemainDays())); - } - - public void addExpeditionInfo(long avaterGuid, int expId, int hourTime, int startTime){ - ExpeditionInfo exp = new ExpeditionInfo(); - exp.setExpId(expId); - exp.setHourTime(hourTime); - exp.setState(1); - exp.setStartTime(startTime); - expeditionInfo.put(avaterGuid, exp); - } - - public void removeExpeditionInfo(long avaterGuid){ - expeditionInfo.remove(avaterGuid); - } - - public ExpeditionInfo getExpeditionInfo(long avaterGuid){ - return expeditionInfo.get(avaterGuid); - } - - public List getShopLimit() { - return shopLimit; - } - - public ShopLimit getGoodsLimit(int goodsId) { - Optional shopLimit = this.shopLimit.stream().filter(x -> x.getShopGoodId() == goodsId).findFirst(); - if (shopLimit.isEmpty()) - return null; - return shopLimit.get(); - } - - public void addShopLimit(int goodsId, int boughtCount, int nextRefreshTime) { - ShopLimit target = getGoodsLimit(goodsId); - if (target != null) { - target.setHasBought(target.getHasBought() + boughtCount); - target.setHasBoughtInPeriod(target.getHasBoughtInPeriod() + boughtCount); - target.setNextRefreshTime(nextRefreshTime); - } else { - ShopLimit sl = new ShopLimit(); - sl.setShopGoodId(goodsId); - sl.setHasBought(boughtCount); - sl.setHasBoughtInPeriod(boughtCount); - sl.setNextRefreshTime(nextRefreshTime); - getShopLimit().add(sl); - } - this.save(); - } - public boolean getUnlimitedStamina() { - return stamina; - } - public void setUnlimitedStamina(boolean stamina) { - this.stamina = stamina; - } - public boolean inGodmode() { - return godmode; - } - - public void setGodmode(boolean godmode) { - this.godmode = godmode; - } - - public boolean hasSentAvatarDataNotify() { - return hasSentAvatarDataNotify; - } - - public void setHasSentAvatarDataNotify(boolean hasSentAvatarDataNotify) { - this.hasSentAvatarDataNotify = hasSentAvatarDataNotify; - } - - public void addAvatar(Avatar avatar, boolean addToCurrentTeam) { - boolean result = getAvatars().addAvatar(avatar); - - if (result) { - // Add starting weapon - getAvatars().addStartingWeapon(avatar); - - // Done - if (hasSentAvatarDataNotify()) { - // Recalc stats - avatar.recalcStats(); - // Packet, show notice on left if the avatar will be added to the team - sendPacket(new PacketAvatarAddNotify(avatar, addToCurrentTeam && this.getTeamManager().canAddAvatarToCurrentTeam())); - if (addToCurrentTeam) { - // If space in team, add - this.getTeamManager().addAvatarToCurrentTeam(avatar); - } - } - } else { - // Failed adding avatar - } - } - - public void addAvatar(Avatar avatar) { - addAvatar(avatar, true); - } - - public void addFlycloak(int flycloakId) { - this.getFlyCloakList().add(flycloakId); - this.sendPacket(new PacketAvatarGainFlycloakNotify(flycloakId)); - } - - public void addCostume(int costumeId) { - this.getCostumeList().add(costumeId); - this.sendPacket(new PacketAvatarGainCostumeNotify(costumeId)); - } - - public void addNameCard(int nameCardId) { - this.getNameCardList().add(nameCardId); - this.sendPacket(new PacketUnlockNameCardNotify(nameCardId)); - } - - public void setNameCard(int nameCardId) { - if (!this.getNameCardList().contains(nameCardId)) { - return; - } - - this.setNameCardId(nameCardId); - - this.sendPacket(new PacketSetNameCardRsp(nameCardId)); - } - - public void dropMessage(Object message) { - if (this.messageHandler != null) { - this.messageHandler.append(message.toString()); - return; - } - - this.getServer().getChatManager().sendPrivateMessageFromServer(getUid(), message.toString()); - // this.sendPacket(new PacketPrivateChatNotify(GameConstants.SERVER_CONSOLE_UID, getUid(), message.toString())); - } - - /** - * Sends a message to another player. - * - * @param sender The sender of the message. - * @param message The message to send. - */ - public void sendMessage(Player sender, Object message) { - // this.sendPacket(new PacketPrivateChatNotify(sender.getUid(), this.getUid(), message.toString())); - this.getServer().getChatManager().sendPrivateMessage(sender, this.getUid(), message.toString()); - } - - // ---------------------MAIL------------------------ - - public List getAllMail() { return this.getMailHandler().getMail(); } - - public void sendMail(Mail message) { - this.getMailHandler().sendMail(message); - } - - public boolean deleteMail(int mailId) { - return this.getMailHandler().deleteMail(mailId); - } - - public Mail getMail(int index) { return this.getMailHandler().getMailById(index); } - - public int getMailId(Mail message) { - return this.getMailHandler().getMailIndex(message); - } - - public boolean replaceMailByIndex(int index, Mail message) { - return this.getMailHandler().replaceMailByIndex(index, message); - } - - public void interactWith(int gadgetEntityId, GadgetInteractReq interactReq) { - GameEntity target = getScene().getEntityById(gadgetEntityId); - - if (target == null) { - return; - } - - target.onInteract(this, interactReq); - } - - public void onPause() { - getStaminaManager().stopSustainedStaminaHandler(); - } - - public void onUnpause() { - getStaminaManager().startSustainedStaminaHandler(); - } - - public void sendPacket(BasePacket packet) { - this.getSession().send(packet); - } - - public OnlinePlayerInfo getOnlinePlayerInfo() { - OnlinePlayerInfo.Builder onlineInfo = OnlinePlayerInfo.newBuilder() - .setUid(this.getUid()) - .setNickname(this.getNickname()) - .setPlayerLevel(this.getLevel()) - .setMpSettingType(this.getMpSetting()) - .setNameCardId(this.getNameCardId()) - .setSignature(this.getSignature()) - .setProfilePicture(ProfilePicture.newBuilder().setAvatarId(this.getHeadImage())); - - if (this.getWorld() != null) { - onlineInfo.setCurPlayerNumInWorld(getWorld().getPlayerCount()); - } else { - onlineInfo.setCurPlayerNumInWorld(1); - } - - return onlineInfo.build(); - } - - public PlayerBirthday getBirthday() { - return this.birthday; - } - - public void setBirthday(int d, int m) { - this.birthday = new PlayerBirthday(d, m); - this.updateProfile(); - } - - public boolean hasBirthday() { - return this.birthday.getDay() > 0; - } - - public PlayerCodex getCodex() { - return this.codex; - } - - public void setRewardedLevels(Set rewardedLevels) { - this.rewardedLevels = rewardedLevels; - } - - public SocialDetail.Builder getSocialDetail() { - List socialShowAvatarInfoList = new ArrayList<>(); - if (this.isOnline()) { - if (this.getShowAvatarList() != null) { - for (int avatarId : this.getShowAvatarList()) { - socialShowAvatarInfoList.add( - socialShowAvatarInfoList.size(), - SocialShowAvatarInfoOuterClass.SocialShowAvatarInfo.newBuilder() - .setAvatarId(avatarId) - .setLevel(getAvatars().getAvatarById(avatarId).getLevel()) - .setCostumeId(getAvatars().getAvatarById(avatarId).getCostume()) - .build() - ); - } - } - } else { - List showAvatarList = DatabaseHelper.getPlayerByUid(id).getShowAvatarList(); - AvatarStorage avatars = DatabaseHelper.getPlayerByUid(id).getAvatars(); - avatars.loadFromDatabase(); - if (showAvatarList != null) { - for (int avatarId : showAvatarList) { - socialShowAvatarInfoList.add( - socialShowAvatarInfoList.size(), - SocialShowAvatarInfoOuterClass.SocialShowAvatarInfo.newBuilder() - .setAvatarId(avatarId) - .setLevel(avatars.getAvatarById(avatarId).getLevel()) - .setCostumeId(avatars.getAvatarById(avatarId).getCostume()) - .build() - ); - } - } - } - - SocialDetail.Builder social = SocialDetail.newBuilder() - .setUid(this.getUid()) - .setProfilePicture(ProfilePicture.newBuilder().setAvatarId(this.getHeadImage())) - .setNickname(this.getNickname()) - .setSignature(this.getSignature()) - .setLevel(this.getLevel()) - .setBirthday(this.getBirthday().getFilledProtoWhenNotEmpty()) - .setWorldLevel(this.getWorldLevel()) - .setNameCardId(this.getNameCardId()) - .setIsShowAvatar(this.isShowAvatars()) - .addAllShowAvatarInfoList(socialShowAvatarInfoList) - .setFinishAchievementNum(0); - return social; - } - - public List getShowAvatarInfoList() { - List showAvatarInfoList = new ArrayList<>(); - - Player player; - boolean shouldRecalc; - if (this.isOnline()) { - player = this; - shouldRecalc = false; - } else { - player = DatabaseHelper.getPlayerByUid(id); - player.getAvatars().loadFromDatabase(); - player.getInventory().loadFromDatabase(); - shouldRecalc = true; - } - - List showAvatarList = player.getShowAvatarList(); - AvatarStorage avatars = player.getAvatars(); - if (showAvatarList != null) { - for (int avatarId : showAvatarList) { - Avatar avatar = avatars.getAvatarById(avatarId); - if (shouldRecalc) { - avatar.recalcStats(); - } - showAvatarInfoList.add(avatar.toShowAvatarInfoProto()); - } - } - return showAvatarInfoList; - } - - public PlayerWorldLocationInfoOuterClass.PlayerWorldLocationInfo getWorldPlayerLocationInfo() { - return PlayerWorldLocationInfoOuterClass.PlayerWorldLocationInfo.newBuilder() - .setSceneId(this.getSceneId()) - .setPlayerLoc(this.getPlayerLocationInfo()) - .build(); - } - - public PlayerLocationInfo getPlayerLocationInfo() { - return PlayerLocationInfo.newBuilder() - .setUid(this.getUid()) - .setPos(this.getPosition().toProto()) - .setRot(this.getRotation().toProto()) - .build(); - } - - public void loadBattlePassManager() { - if (this.battlePassManager != null) return; - this.battlePassManager = DatabaseHelper.loadBattlePass(this); - this.battlePassManager.getMissions().values().removeIf(mission -> mission.getData() == null); - } - - public PlayerCollectionRecords getCollectionRecordStore() { - if(this.collectionRecordStore==null){ - this.collectionRecordStore = new PlayerCollectionRecords(); - } - return collectionRecordStore; - } - - public Map getMapMarks() { - if (this.mapMarks == null) { - this.mapMarks = new HashMap(); - } - return mapMarks; - } - - public PlayerOpenStateManager getOpenStateManager() { - if (this.openStateManager == null) { + this.shopLimit = new ArrayList<>(); + this.expeditionInfo = new HashMap<>(); + this.messageHandler = null; + this.mapMarksManager = new MapMarksManager(this); + this.staminaManager = new StaminaManager(this); + this.sotsManager = new SotSManager(this); + this.energyManager = new EnergyManager(this); + this.resinManager = new ResinManager(this); + this.forgingManager = new ForgingManager(this); + this.furnitureManager = new FurnitureManager(this); + this.cookingManager = new CookingManager(this); + } + + // On player creation + public Player(GameSession session) { + this(); + this.account = session.getAccount(); + this.accountId = this.getAccount().getId(); + this.session = session; + this.nickname = "Traveler"; + this.signature = ""; + this.teamManager = new TeamManager(this); + this.birthday = new PlayerBirthday(); + this.codex = new PlayerCodex(this); + this.setProperty(PlayerProperty.PROP_PLAYER_LEVEL, 1, false); + this.setProperty(PlayerProperty.PROP_IS_SPRING_AUTO_USE, 1, false); + this.setProperty(PlayerProperty.PROP_SPRING_AUTO_USE_PERCENT, 50, false); + this.setProperty(PlayerProperty.PROP_IS_FLYABLE, 1, false); + this.setProperty(PlayerProperty.PROP_IS_TRANSFERABLE, 1, false); + this.setProperty(PlayerProperty.PROP_MAX_STAMINA, 24000, false); + this.setProperty(PlayerProperty.PROP_CUR_PERSIST_STAMINA, 24000, false); + this.setProperty(PlayerProperty.PROP_PLAYER_RESIN, 160, false); + this.getFlyCloakList().add(140001); + this.getNameCardList().add(210001); + this.messageHandler = null; + this.mapMarksManager = new MapMarksManager(this); + this.staminaManager = new StaminaManager(this); + this.sotsManager = new SotSManager(this); + this.energyManager = new EnergyManager(this); + this.resinManager = new ResinManager(this); + this.deforestationManager = new DeforestationManager(this); + this.forgingManager = new ForgingManager(this); + this.furnitureManager = new FurnitureManager(this); + this.cookingManager = new CookingManager(this); + } + + public int getUid() { + return id; + } + + public void setUid(int id) { + this.id = id; + } + + public long getNextGameGuid() { + long nextId = ++this.nextGuid; + return ((long) this.getUid() << 32) + nextId; + } + + public Account getAccount() { + if (this.account == null) + this.account = DatabaseHelper.getAccountById(Integer.toString(this.id)); + return this.account; + } + + public void setAccount(Account account) { + this.account = account; + } + + public GameSession getSession() { + return session; + } + + public void setSession(GameSession session) { + this.session = session; + } + + public boolean isOnline() { + return this.getSession() != null && this.getSession().isActive(); + } + + public GameServer getServer() { + return this.getSession().getServer(); + } + + public synchronized World getWorld() { + return this.world; + } + + public synchronized void setWorld(World world) { + this.world = world; + } + + public synchronized Scene getScene() { + return scene; + } + + public synchronized void setScene(Scene scene) { + this.scene = scene; + } + + synchronized public void setClimate(ClimateType climate) { + this.climate = climate; + this.session.send(new PacketSceneAreaWeatherNotify(this)); + } + + synchronized public void setWeather(int weather) { + this.setWeather(weather, ClimateType.CLIMATE_NONE); + } + + synchronized public void setWeather(int weatherId, ClimateType climate) { + // Lookup default climate for this weather + if (climate == ClimateType.CLIMATE_NONE) { + WeatherData w = GameData.getWeatherDataMap().get(weatherId); + if (w != null) { + climate = w.getDefaultClimate(); + } + } + this.weatherId = weatherId; + this.climate = climate; + this.session.send(new PacketSceneAreaWeatherNotify(this)); + } + + public String getNickname() { + return nickname; + } + + public void setNickname(String nickName) { + this.nickname = nickName; + this.updateProfile(); + } + + public int getHeadImage() { + return headImage; + } + + public void setHeadImage(int picture) { + this.headImage = picture; + this.updateProfile(); + } + + public String getSignature() { + return signature; + } + + public void setSignature(String signature) { + this.signature = signature; + this.updateProfile(); + } + + public Integer getWidgetId() { + return widgetId; + } + + public void setWidgetId(Integer widgetId) { + this.widgetId = widgetId; + } + + public void setRealmList(Set realmList) { + this.realmList = realmList; + } + + public void addRealmList(int realmId) { + if (this.realmList == null) { + this.realmList = new HashSet<>(); + } else if (this.realmList.contains(realmId)) { + return; + } + this.realmList.add(realmId); + } + + public int getCurrentRealmId() { + return currentRealmId; + } + + public void setCurrentRealmId(int currentRealmId) { + this.currentRealmId = currentRealmId; + } + + public Position getPosition() { + return position; + } + + public Position getRotation() { + return rotation; + } + + public int getLevel() { + return this.getProperty(PlayerProperty.PROP_PLAYER_LEVEL); + } + + public boolean setLevel(int level) { + if (this.getLevel() == level) { + return true; + } + + if (this.setProperty(PlayerProperty.PROP_PLAYER_LEVEL, level)) { + // Update world level and profile. + this.updateWorldLevel(); + this.updateProfile(); + + // Handle OpenState unlocks from level-up. + this.getOpenStateManager().unlockLevelDependentStates(); + + return true; + } + return false; + } + + public int getExp() { + return this.getProperty(PlayerProperty.PROP_PLAYER_EXP); + } + + public int getWorldLevel() { + return this.getProperty(PlayerProperty.PROP_PLAYER_WORLD_LEVEL); + } + + public boolean setWorldLevel(int level) { + if (this.setProperty(PlayerProperty.PROP_PLAYER_WORLD_LEVEL, level)) { + if (this.world.getHost() == this) // Don't update World's WL if we are in someone else's world + this.world.setWorldLevel(level); + this.updateProfile(); + return true; + } + return false; + } + + public int getForgePoints() { + return this.getProperty(PlayerProperty.PROP_PLAYER_FORGE_POINT); + } + + public boolean setForgePoints(int value) { + if (value == this.getForgePoints()) { + return true; + } + + return this.setProperty(PlayerProperty.PROP_PLAYER_FORGE_POINT, value); + } + + public int getPrimogems() { + return this.getProperty(PlayerProperty.PROP_PLAYER_HCOIN); + } + + public boolean setPrimogems(int primogem) { + return this.setProperty(PlayerProperty.PROP_PLAYER_HCOIN, primogem); + } + + public int getMora() { + return this.getProperty(PlayerProperty.PROP_PLAYER_SCOIN); + } + + public boolean setMora(int mora) { + return this.setProperty(PlayerProperty.PROP_PLAYER_SCOIN, mora); + } + + public int getCrystals() { + return this.getProperty(PlayerProperty.PROP_PLAYER_MCOIN); + } + + public boolean setCrystals(int crystals) { + return this.setProperty(PlayerProperty.PROP_PLAYER_MCOIN, crystals); + } + + public int getHomeCoin() { + return this.getProperty(PlayerProperty.PROP_PLAYER_HOME_COIN); + } + + public boolean setHomeCoin(int coin) { + return this.setProperty(PlayerProperty.PROP_PLAYER_HOME_COIN, coin); + } + private int getExpRequired(int level) { + PlayerLevelData levelData = GameData.getPlayerLevelDataMap().get(level); + return levelData != null ? levelData.getExp() : 0; + } + + private float getExpModifier() { + return GAME_OPTIONS.rates.adventureExp; + } + + // Affected by exp rate + public void earnExp(int exp) { + addExpDirectly((int) (exp * getExpModifier())); + } + + // Directly give player exp + public void addExpDirectly(int gain) { + int level = getLevel(); + int exp = getExp(); + int reqExp = getExpRequired(level); + + exp += gain; + + while (exp >= reqExp && reqExp > 0) { + exp -= reqExp; + level += 1; + reqExp = getExpRequired(level); + + // Set level each time to allow level-up specific logic to run. + this.setLevel(level); + } + + // Set exp + this.setProperty(PlayerProperty.PROP_PLAYER_EXP, exp); + } + + private void updateWorldLevel() { + int currentWorldLevel = this.getWorldLevel(); + int currentLevel = this.getLevel(); + + int newWorldLevel = + (currentLevel >= 55) ? 8 : + (currentLevel >= 50) ? 7 : + (currentLevel >= 45) ? 6 : + (currentLevel >= 40) ? 5 : + (currentLevel >= 35) ? 4 : + (currentLevel >= 30) ? 3 : + (currentLevel >= 25) ? 2 : + (currentLevel >= 20) ? 1 : + 0; + + if (newWorldLevel != currentWorldLevel) { + this.setWorldLevel(newWorldLevel); + } + } + + private void updateProfile() { + getProfile().syncWithCharacter(this); + } + + public boolean isFirstLoginEnterScene() { + return !this.hasSentAvatarDataNotify; + } + + public TeamManager getTeamManager() { + return this.teamManager; + } + + public TowerData getTowerData() { + if (towerData == null) { + // because of mistake, null may be saved as storage at some machine, this if can be removed in future + towerData = new TowerData(); + } + return towerData; + } + + public PlayerGachaInfo getGachaInfo() { + return gachaInfo; + } + + public PlayerProfile getProfile() { + if (this.playerProfile == null) { + this.playerProfile = new PlayerProfile(this); + } + return playerProfile; + } + + // TODO: Based on the proto, property value could be int or float. + // Although there's no float value at this moment, our code should be prepared for float values. + public Map getProperties() { + return properties; + } + + public boolean setProperty(PlayerProperty prop, int value) { + return setPropertyWithSanityCheck(prop, value, true); + } + + public boolean setProperty(PlayerProperty prop, int value, boolean sendPacket) { + return setPropertyWithSanityCheck(prop, value, sendPacket); + } + + public int getProperty(PlayerProperty prop) { + return getProperties().get(prop.getId()); + } + + public MpSettingType getMpSetting() { + return MpSettingType.MP_SETTING_TYPE_ENTER_AFTER_APPLY; // TEMP + } + + public Queue getAttackResults() { + return this.attackResults; + } + + public synchronized Int2ObjectMap getCoopRequests() { + return coopRequests; + } + + public int getEnterSceneToken() { + return enterSceneToken; + } + + public void setEnterSceneToken(int enterSceneToken) { + this.enterSceneToken = enterSceneToken; + } + + public int getNameCardId() { + return nameCardId; + } + + public void setNameCardId(int nameCardId) { + this.nameCardId = nameCardId; + this.updateProfile(); + } + + public int getMainCharacterId() { + return mainCharacterId; + } + + public void setMainCharacterId(int mainCharacterId) { + this.mainCharacterId = mainCharacterId; + } + + public int getPeerId() { + return peerId; + } + + public void setPeerId(int peerId) { + this.peerId = peerId; + } + + public int getClientTime() { + return session.getClientTime(); + } + + public long getLastPingTime() { + return session.getLastPingTime(); + } + + public boolean isPaused() { + return paused; + } + + public void setPaused(boolean newPauseState) { + boolean oldPauseState = this.paused; + this.paused = newPauseState; + + if (newPauseState && !oldPauseState) { + this.onPause(); + } else if (oldPauseState && !newPauseState) { + this.onUnpause(); + } + } + + public long getSpringLastUsed() { + return springLastUsed; + } + + public void setSpringLastUsed(long val) { + springLastUsed = val; + } + + public int getNextResinRefresh() { + return nextResinRefresh; + } + + public void setNextResinRefresh(int value) { + this.nextResinRefresh = value; + } + + public SceneLoadState getSceneLoadState() { + return sceneState; + } + + public void setSceneLoadState(SceneLoadState sceneState) { + this.sceneState = sceneState; + } + + public boolean isInMultiplayer() { + return this.getWorld() != null && this.getWorld().isMultiplayer(); + } + + public int getSceneId() { + return sceneId; + } + + public void setSceneId(int sceneId) { + this.sceneId = sceneId; + } + + public int getRegionId() { + return regionId; + } + + public void setRegionId(int regionId) { + this.regionId = regionId; + } + + public void setShowAvatars(boolean showAvatars) { + this.showAvatars = showAvatars; + } + + public boolean isShowAvatars() { + return showAvatars; + } + + public void setShowAvatarList(List showAvatarList) { + this.showAvatarList = showAvatarList; + } + + public List getShowAvatarList() { + return showAvatarList; + } + + public int getLastDailyReset() { + return this.lastDailyReset; + } + + public void setLastDailyReset(int value) { + this.lastDailyReset = value; + } + + public boolean inMoonCard() { + return moonCard; + } + + public void setMoonCard(boolean moonCard) { + this.moonCard = moonCard; + } + + public void addMoonCardDays(int days) { + this.moonCardDuration += days; + } + + public int getMoonCardDuration() { + return moonCardDuration; + } + + public void setMoonCardDuration(int moonCardDuration) { + this.moonCardDuration = moonCardDuration; + } + + public Date getMoonCardStartTime() { + return moonCardStartTime; + } + + public void setMoonCardStartTime(Date moonCardStartTime) { + this.moonCardStartTime = moonCardStartTime; + } + + public Set getMoonCardGetTimes() { + return moonCardGetTimes; + } + + public void setMoonCardGetTimes(Set moonCardGetTimes) { + this.moonCardGetTimes = moonCardGetTimes; + } + + public int getMoonCardRemainDays() { + Calendar remainCalendar = Calendar.getInstance(); + remainCalendar.setTime(moonCardStartTime); + remainCalendar.add(Calendar.DATE, moonCardDuration); + Date theLastDay = remainCalendar.getTime(); + Date now = DateHelper.onlyYearMonthDay(new Date()); + return (int) ((theLastDay.getTime() - now.getTime()) / (24 * 60 * 60 * 1000)); // By copilot + } + + public void rechargeMoonCard() { + inventory.addItem(new GameItem(203, 300)); + if (!moonCard) { + moonCard = true; + Date now = new Date(); + moonCardStartTime = DateHelper.onlyYearMonthDay(now); + moonCardDuration = 30; + } else { + moonCardDuration += 30; + } + if (!moonCardGetTimes.contains(moonCardStartTime)) { + moonCardGetTimes.add(moonCardStartTime); + } + } + + public void getTodayMoonCard() { + if (!moonCard) { + return; + } + Date now = DateHelper.onlyYearMonthDay(new Date()); + if (moonCardGetTimes.contains(now)) { + return; + } + Date stopTime = new Date(); + Calendar stopCalendar = Calendar.getInstance(); + stopCalendar.setTime(stopTime); + stopCalendar.add(Calendar.DATE, moonCardDuration); + stopTime = stopCalendar.getTime(); + if (now.after(stopTime)) { + moonCard = false; + return; + } + moonCardGetTimes.add(now); + addMoonCardDays(1); + GameItem item = new GameItem(201, 90); + getInventory().addItem(item, ActionReason.BlessingRedeemReward); + session.send(new PacketCardProductRewardNotify(getMoonCardRemainDays())); + } + + public void addExpeditionInfo(long avaterGuid, int expId, int hourTime, int startTime) { + ExpeditionInfo exp = new ExpeditionInfo(); + exp.setExpId(expId); + exp.setHourTime(hourTime); + exp.setState(1); + exp.setStartTime(startTime); + expeditionInfo.put(avaterGuid, exp); + } + + public void removeExpeditionInfo(long avaterGuid) { + expeditionInfo.remove(avaterGuid); + } + + public ExpeditionInfo getExpeditionInfo(long avaterGuid) { + return expeditionInfo.get(avaterGuid); + } + + public List getShopLimit() { + return shopLimit; + } + + public ShopLimit getGoodsLimit(int goodsId) { + Optional shopLimit = this.shopLimit.stream().filter(x -> x.getShopGoodId() == goodsId).findFirst(); + if (shopLimit.isEmpty()) + return null; + return shopLimit.get(); + } + + public void addShopLimit(int goodsId, int boughtCount, int nextRefreshTime) { + ShopLimit target = getGoodsLimit(goodsId); + if (target != null) { + target.setHasBought(target.getHasBought() + boughtCount); + target.setHasBoughtInPeriod(target.getHasBoughtInPeriod() + boughtCount); + target.setNextRefreshTime(nextRefreshTime); + } else { + ShopLimit sl = new ShopLimit(); + sl.setShopGoodId(goodsId); + sl.setHasBought(boughtCount); + sl.setHasBoughtInPeriod(boughtCount); + sl.setNextRefreshTime(nextRefreshTime); + getShopLimit().add(sl); + } + this.save(); + } + public boolean getUnlimitedStamina() { + return stamina; + } + public void setUnlimitedStamina(boolean stamina) { + this.stamina = stamina; + } + public boolean inGodmode() { + return godmode; + } + + public void setGodmode(boolean godmode) { + this.godmode = godmode; + } + + public boolean hasSentAvatarDataNotify() { + return hasSentAvatarDataNotify; + } + + public void setHasSentAvatarDataNotify(boolean hasSentAvatarDataNotify) { + this.hasSentAvatarDataNotify = hasSentAvatarDataNotify; + } + + public void addAvatar(Avatar avatar, boolean addToCurrentTeam) { + boolean result = getAvatars().addAvatar(avatar); + + if (result) { + // Add starting weapon + getAvatars().addStartingWeapon(avatar); + + // Done + if (hasSentAvatarDataNotify()) { + // Recalc stats + avatar.recalcStats(); + // Packet, show notice on left if the avatar will be added to the team + sendPacket(new PacketAvatarAddNotify(avatar, addToCurrentTeam && this.getTeamManager().canAddAvatarToCurrentTeam())); + if (addToCurrentTeam) { + // If space in team, add + this.getTeamManager().addAvatarToCurrentTeam(avatar); + } + } + } else { + // Failed adding avatar + } + } + + public void addAvatar(Avatar avatar) { + addAvatar(avatar, true); + } + + public void addFlycloak(int flycloakId) { + this.getFlyCloakList().add(flycloakId); + this.sendPacket(new PacketAvatarGainFlycloakNotify(flycloakId)); + } + + public void addCostume(int costumeId) { + this.getCostumeList().add(costumeId); + this.sendPacket(new PacketAvatarGainCostumeNotify(costumeId)); + } + + public void addNameCard(int nameCardId) { + this.getNameCardList().add(nameCardId); + this.sendPacket(new PacketUnlockNameCardNotify(nameCardId)); + } + + public void setNameCard(int nameCardId) { + if (!this.getNameCardList().contains(nameCardId)) { + return; + } + + this.setNameCardId(nameCardId); + + this.sendPacket(new PacketSetNameCardRsp(nameCardId)); + } + + public void dropMessage(Object message) { + if (this.messageHandler != null) { + this.messageHandler.append(message.toString()); + return; + } + + this.getServer().getChatManager().sendPrivateMessageFromServer(getUid(), message.toString()); + // this.sendPacket(new PacketPrivateChatNotify(GameConstants.SERVER_CONSOLE_UID, getUid(), message.toString())); + } + + /** + * Sends a message to another player. + * + * @param sender The sender of the message. + * @param message The message to send. + */ + public void sendMessage(Player sender, Object message) { + // this.sendPacket(new PacketPrivateChatNotify(sender.getUid(), this.getUid(), message.toString())); + this.getServer().getChatManager().sendPrivateMessage(sender, this.getUid(), message.toString()); + } + + // ---------------------MAIL------------------------ + + public List getAllMail() { return this.getMailHandler().getMail(); } + + public void sendMail(Mail message) { + this.getMailHandler().sendMail(message); + } + + public boolean deleteMail(int mailId) { + return this.getMailHandler().deleteMail(mailId); + } + + public Mail getMail(int index) { return this.getMailHandler().getMailById(index); } + + public int getMailId(Mail message) { + return this.getMailHandler().getMailIndex(message); + } + + public boolean replaceMailByIndex(int index, Mail message) { + return this.getMailHandler().replaceMailByIndex(index, message); + } + + public void interactWith(int gadgetEntityId, GadgetInteractReq interactReq) { + GameEntity target = getScene().getEntityById(gadgetEntityId); + + if (target == null) { + return; + } + + target.onInteract(this, interactReq); + } + + public void onPause() { + getStaminaManager().stopSustainedStaminaHandler(); + } + + public void onUnpause() { + getStaminaManager().startSustainedStaminaHandler(); + } + + public void sendPacket(BasePacket packet) { + this.getSession().send(packet); + } + + public OnlinePlayerInfo getOnlinePlayerInfo() { + OnlinePlayerInfo.Builder onlineInfo = OnlinePlayerInfo.newBuilder() + .setUid(this.getUid()) + .setNickname(this.getNickname()) + .setPlayerLevel(this.getLevel()) + .setMpSettingType(this.getMpSetting()) + .setNameCardId(this.getNameCardId()) + .setSignature(this.getSignature()) + .setProfilePicture(ProfilePicture.newBuilder().setAvatarId(this.getHeadImage())); + + if (this.getWorld() != null) { + onlineInfo.setCurPlayerNumInWorld(getWorld().getPlayerCount()); + } else { + onlineInfo.setCurPlayerNumInWorld(1); + } + + return onlineInfo.build(); + } + + public PlayerBirthday getBirthday() { + return this.birthday; + } + + public void setBirthday(int d, int m) { + this.birthday = new PlayerBirthday(d, m); + this.updateProfile(); + } + + public boolean hasBirthday() { + return this.birthday.getDay() > 0; + } + + public PlayerCodex getCodex() { + return this.codex; + } + + public void setRewardedLevels(Set rewardedLevels) { + this.rewardedLevels = rewardedLevels; + } + + public SocialDetail.Builder getSocialDetail() { + List socialShowAvatarInfoList = new ArrayList<>(); + if (this.isOnline()) { + if (this.getShowAvatarList() != null) { + for (int avatarId : this.getShowAvatarList()) { + socialShowAvatarInfoList.add( + socialShowAvatarInfoList.size(), + SocialShowAvatarInfoOuterClass.SocialShowAvatarInfo.newBuilder() + .setAvatarId(avatarId) + .setLevel(getAvatars().getAvatarById(avatarId).getLevel()) + .setCostumeId(getAvatars().getAvatarById(avatarId).getCostume()) + .build() + ); + } + } + } else { + List showAvatarList = DatabaseHelper.getPlayerByUid(id).getShowAvatarList(); + AvatarStorage avatars = DatabaseHelper.getPlayerByUid(id).getAvatars(); + avatars.loadFromDatabase(); + if (showAvatarList != null) { + for (int avatarId : showAvatarList) { + socialShowAvatarInfoList.add( + socialShowAvatarInfoList.size(), + SocialShowAvatarInfoOuterClass.SocialShowAvatarInfo.newBuilder() + .setAvatarId(avatarId) + .setLevel(avatars.getAvatarById(avatarId).getLevel()) + .setCostumeId(avatars.getAvatarById(avatarId).getCostume()) + .build() + ); + } + } + } + + SocialDetail.Builder social = SocialDetail.newBuilder() + .setUid(this.getUid()) + .setProfilePicture(ProfilePicture.newBuilder().setAvatarId(this.getHeadImage())) + .setNickname(this.getNickname()) + .setSignature(this.getSignature()) + .setLevel(this.getLevel()) + .setBirthday(this.getBirthday().getFilledProtoWhenNotEmpty()) + .setWorldLevel(this.getWorldLevel()) + .setNameCardId(this.getNameCardId()) + .setIsShowAvatar(this.isShowAvatars()) + .addAllShowAvatarInfoList(socialShowAvatarInfoList) + .setFinishAchievementNum(0); + return social; + } + + public List getShowAvatarInfoList() { + List showAvatarInfoList = new ArrayList<>(); + + Player player; + boolean shouldRecalc; + if (this.isOnline()) { + player = this; + shouldRecalc = false; + } else { + player = DatabaseHelper.getPlayerByUid(id); + player.getAvatars().loadFromDatabase(); + player.getInventory().loadFromDatabase(); + shouldRecalc = true; + } + + List showAvatarList = player.getShowAvatarList(); + AvatarStorage avatars = player.getAvatars(); + if (showAvatarList != null) { + for (int avatarId : showAvatarList) { + Avatar avatar = avatars.getAvatarById(avatarId); + if (shouldRecalc) { + avatar.recalcStats(); + } + showAvatarInfoList.add(avatar.toShowAvatarInfoProto()); + } + } + return showAvatarInfoList; + } + + public PlayerWorldLocationInfoOuterClass.PlayerWorldLocationInfo getWorldPlayerLocationInfo() { + return PlayerWorldLocationInfoOuterClass.PlayerWorldLocationInfo.newBuilder() + .setSceneId(this.getSceneId()) + .setPlayerLoc(this.getPlayerLocationInfo()) + .build(); + } + + public PlayerLocationInfo getPlayerLocationInfo() { + return PlayerLocationInfo.newBuilder() + .setUid(this.getUid()) + .setPos(this.getPosition().toProto()) + .setRot(this.getRotation().toProto()) + .build(); + } + + public void loadBattlePassManager() { + if (this.battlePassManager != null) return; + this.battlePassManager = DatabaseHelper.loadBattlePass(this); + this.battlePassManager.getMissions().values().removeIf(mission -> mission.getData() == null); + } + + public PlayerCollectionRecords getCollectionRecordStore() { + if (this.collectionRecordStore==null) { + this.collectionRecordStore = new PlayerCollectionRecords(); + } + return collectionRecordStore; + } + + public Map getMapMarks() { + if (this.mapMarks == null) { + this.mapMarks = new HashMap(); + } + return mapMarks; + } + + public PlayerOpenStateManager getOpenStateManager() { + if (this.openStateManager == null) { this.openStateManager = new PlayerOpenStateManager(this); } return openStateManager; } public synchronized void onTick() { - // Check ping - if (this.getLastPingTime() > System.currentTimeMillis() + 60000) { - this.getSession().close(); - return; - } - // Check co-op requests - Iterator it = this.getCoopRequests().values().iterator(); - while (it.hasNext()) { - CoopRequest req = it.next(); - if (req.isExpired()) { - req.getRequester().sendPacket(new PacketPlayerApplyEnterMpResultNotify( - this, - false, - PlayerApplyEnterMpResultNotifyOuterClass.PlayerApplyEnterMpResultNotify.Reason.REASON_SYSTEM_JUDGE)); - it.remove(); - } - } - // Ping - if (this.getWorld() != null) { - // RTT notify - very important to send this often - this.sendPacket(new PacketWorldPlayerRTTNotify(this.getWorld())); + // Check ping + if (this.getLastPingTime() > System.currentTimeMillis() + 60000) { + this.getSession().close(); + return; + } + // Check co-op requests + Iterator it = this.getCoopRequests().values().iterator(); + while (it.hasNext()) { + CoopRequest req = it.next(); + if (req.isExpired()) { + req.getRequester().sendPacket(new PacketPlayerApplyEnterMpResultNotify( + this, + false, + PlayerApplyEnterMpResultNotifyOuterClass.PlayerApplyEnterMpResultNotify.Reason.REASON_SYSTEM_JUDGE)); + it.remove(); + } + } + // Ping + if (this.getWorld() != null) { + // RTT notify - very important to send this often + this.sendPacket(new PacketWorldPlayerRTTNotify(this.getWorld())); - // Update player locations if in multiplayer every 5 seconds - long time = System.currentTimeMillis(); - if (this.getWorld().isMultiplayer() && this.getScene() != null && time > nextSendPlayerLocTime) { - this.sendPacket(new PacketWorldPlayerLocationNotify(this.getWorld())); - this.sendPacket(new PacketScenePlayerLocationNotify(this.getScene())); - this.resetSendPlayerLocTime(); - } - } + // Update player locations if in multiplayer every 5 seconds + long time = System.currentTimeMillis(); + if (this.getWorld().isMultiplayer() && this.getScene() != null && time > nextSendPlayerLocTime) { + this.sendPacket(new PacketWorldPlayerLocationNotify(this.getWorld())); + this.sendPacket(new PacketScenePlayerLocationNotify(this.getScene())); + this.resetSendPlayerLocTime(); + } + } - // Handle daily reset. - this.doDailyReset(); + // Handle daily reset. + this.doDailyReset(); - // Expedition - var timeNow = Utils.getCurrentSeconds(); - var needNotify = false; - for (Long key : expeditionInfo.keySet()) { - ExpeditionInfo e = expeditionInfo.get(key); - if(e.getState() == 1){ - if(timeNow - e.getStartTime() >= e.getHourTime() * 60 * 60){ - e.setState(2); - needNotify = true; - } - } - } - if(needNotify){ - this.save(); - this.sendPacket(new PacketAvatarExpeditionDataNotify(this)); - } + // Expedition + var timeNow = Utils.getCurrentSeconds(); + var needNotify = false; + for (Long key : expeditionInfo.keySet()) { + ExpeditionInfo e = expeditionInfo.get(key); + if (e.getState() == 1) { + if (timeNow - e.getStartTime() >= e.getHourTime() * 60 * 60) { + e.setState(2); + needNotify = true; + } + } + } + if (needNotify) { + this.save(); + this.sendPacket(new PacketAvatarExpeditionDataNotify(this)); + } - // Send updated forge queue data, if necessary. - this.getForgingManager().sendPlayerForgingUpdate(); + // Send updated forge queue data, if necessary. + this.getForgingManager().sendPlayerForgingUpdate(); - // Recharge resin. - this.getResinManager().rechargeResin(); - } + // Recharge resin. + this.getResinManager().rechargeResin(); + } - private synchronized void doDailyReset() { - // Check if we should execute a daily reset on this tick. - int currentTime = Utils.getCurrentSeconds(); + private synchronized void doDailyReset() { + // Check if we should execute a daily reset on this tick. + int currentTime = Utils.getCurrentSeconds(); - var currentDate = LocalDate.ofInstant(Instant.ofEpochSecond(currentTime), ZoneId.systemDefault()); - var lastResetDate = LocalDate.ofInstant(Instant.ofEpochSecond(this.getLastDailyReset()), ZoneId.systemDefault()); + var currentDate = LocalDate.ofInstant(Instant.ofEpochSecond(currentTime), ZoneId.systemDefault()); + var lastResetDate = LocalDate.ofInstant(Instant.ofEpochSecond(this.getLastDailyReset()), ZoneId.systemDefault()); - if (!currentDate.isAfter(lastResetDate)) { - return; - } + if (!currentDate.isAfter(lastResetDate)) { + return; + } - // We should - now execute all the resetting logic we need. - // Reset forge points. - this.setForgePoints(300_000); + // We should - now execute all the resetting logic we need. + // Reset forge points. + this.setForgePoints(300_000); - // Reset daily BP missions. - this.getBattlePassManager().resetDailyMissions(); + // Reset daily BP missions. + this.getBattlePassManager().resetDailyMissions(); - // Trigger login BP mission, so players who are online during the reset - // don't have to relog to clear the mission. - this.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_LOGIN); + // Trigger login BP mission, so players who are online during the reset + // don't have to relog to clear the mission. + this.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_LOGIN); - // Reset weekly BP missions. - if (currentDate.getDayOfWeek() == DayOfWeek.MONDAY) { - this.getBattlePassManager().resetWeeklyMissions(); - } + // Reset weekly BP missions. + if (currentDate.getDayOfWeek() == DayOfWeek.MONDAY) { + this.getBattlePassManager().resetWeeklyMissions(); + } - // Done. Update last reset time. - this.setLastDailyReset(currentTime); - } + // Done. Update last reset time. + this.setLastDailyReset(currentTime); + } - public void resetSendPlayerLocTime() { - this.nextSendPlayerLocTime = System.currentTimeMillis() + 5000; - } + public void resetSendPlayerLocTime() { + this.nextSendPlayerLocTime = System.currentTimeMillis() + 5000; + } - @PostLoad - private void onLoad() { - this.getCodex().setPlayer(this); + @PostLoad + private void onLoad() { + this.getCodex().setPlayer(this); this.getOpenStateManager().setPlayer(this); - this.getTeamManager().setPlayer(this); - } + this.getTeamManager().setPlayer(this); + } - public void save() { - DatabaseHelper.savePlayer(this); - } + public void save() { + DatabaseHelper.savePlayer(this); + } - // Called from tokenrsp - public void loadFromDatabase() { - // Make sure these exist - if (this.getTeamManager() == null) { - this.teamManager = new TeamManager(this); - } - if (this.getCodex() == null) { - this.codex = new PlayerCodex(this); - } - if (this.getProfile().getUid() == 0) { - this.getProfile().syncWithCharacter(this); - } + // Called from tokenrsp + public void loadFromDatabase() { + // Make sure these exist + if (this.getTeamManager() == null) { + this.teamManager = new TeamManager(this); + } + if (this.getCodex() == null) { + this.codex = new PlayerCodex(this); + } + if (this.getProfile().getUid() == 0) { + this.getProfile().syncWithCharacter(this); + } - // Load from db - this.getAvatars().loadFromDatabase(); - this.getInventory().loadFromDatabase(); - this.getAvatars().postLoad(); // Needs to be called after inventory is handled + // Load from db + this.getAvatars().loadFromDatabase(); + this.getInventory().loadFromDatabase(); + this.getAvatars().postLoad(); // Needs to be called after inventory is handled - this.getFriendsList().loadFromDatabase(); - this.getMailHandler().loadFromDatabase(); - this.getQuestManager().loadFromDatabase(); + this.getFriendsList().loadFromDatabase(); + this.getMailHandler().loadFromDatabase(); + this.getQuestManager().loadFromDatabase(); - this.loadBattlePassManager(); - } + this.loadBattlePassManager(); + } - public void onLogin() { - // Quest - Commented out because a problem is caused if you log out while this quest is active - /* - if (getQuestManager().getMainQuestById(351) == null) { - GameQuest quest = getQuestManager().addQuest(35104); - if (quest != null) { - quest.finish(); - } - getQuestManager().addQuest(35101); + public void onLogin() { + // Quest - Commented out because a problem is caused if you log out while this quest is active + /* + if (getQuestManager().getMainQuestById(351) == null) { + GameQuest quest = getQuestManager().addQuest(35104); + if (quest != null) { + quest.finish(); + } + getQuestManager().addQuest(35101); - this.setSceneId(3); - this.getPos().set(GameConstants.START_POSITION); - } - */ + this.setSceneId(3); + this.getPos().set(GameConstants.START_POSITION); + } + */ - // Create world - World world = new World(this); - world.addPlayer(this); + // Create world + World world = new World(this); + world.addPlayer(this); - // Multiplayer setting - this.setProperty(PlayerProperty.PROP_PLAYER_MP_SETTING_TYPE, this.getMpSetting().getNumber(), false); - this.setProperty(PlayerProperty.PROP_IS_MP_MODE_AVAILABLE, 1, false); + // Multiplayer setting + this.setProperty(PlayerProperty.PROP_PLAYER_MP_SETTING_TYPE, this.getMpSetting().getNumber(), false); + this.setProperty(PlayerProperty.PROP_IS_MP_MODE_AVAILABLE, 1, false); - // Execute daily reset logic if this is a new day. - this.doDailyReset(); + // Execute daily reset logic if this is a new day. + this.doDailyReset(); - // Packets - session.send(new PacketPlayerDataNotify(this)); // Player data - session.send(new PacketStoreWeightLimitNotify()); - session.send(new PacketPlayerStoreNotify(this)); - session.send(new PacketAvatarDataNotify(this)); - session.send(new PacketFinishedParentQuestNotify(this)); - session.send(new PacketBattlePassAllDataNotify(this)); - session.send(new PacketQuestListNotify(this)); - session.send(new PacketCodexDataFullNotify(this)); - session.send(new PacketAllWidgetDataNotify(this)); - session.send(new PacketWidgetGadgetAllDataNotify()); - session.send(new PacketCombineDataNotify(this.unlockedCombines)); - this.forgingManager.sendForgeDataNotify(); - this.resinManager.onPlayerLogin(); - this.cookingManager.sendCookDataNofity(); + // Packets + session.send(new PacketPlayerDataNotify(this)); // Player data + session.send(new PacketStoreWeightLimitNotify()); + session.send(new PacketPlayerStoreNotify(this)); + session.send(new PacketAvatarDataNotify(this)); + session.send(new PacketFinishedParentQuestNotify(this)); + session.send(new PacketBattlePassAllDataNotify(this)); + session.send(new PacketQuestListNotify(this)); + session.send(new PacketCodexDataFullNotify(this)); + session.send(new PacketAllWidgetDataNotify(this)); + session.send(new PacketWidgetGadgetAllDataNotify()); + session.send(new PacketCombineDataNotify(this.unlockedCombines)); + this.forgingManager.sendForgeDataNotify(); + this.resinManager.onPlayerLogin(); + this.cookingManager.sendCookDataNofity(); - // Unlock in case this is an existing user that reached a level before we implemented unlocking. - this.getOpenStateManager().unlockLevelDependentStates(); + // Unlock in case this is an existing user that reached a level before we implemented unlocking. + this.getOpenStateManager().unlockLevelDependentStates(); this.getOpenStateManager().onPlayerLogin(); - getTodayMoonCard(); // The timer works at 0:0, some users log in after that, use this method to check if they have received a reward today or not. If not, send the reward. + getTodayMoonCard(); // The timer works at 0:0, some users log in after that, use this method to check if they have received a reward today or not. If not, send the reward. - // Battle Pass trigger - this.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_LOGIN); + // Battle Pass trigger + this.getBattlePassManager().triggerMission(WatcherTriggerType.TRIGGER_LOGIN); - this.furnitureManager.onLogin(); - // Home - home = GameHome.getByUid(getUid()); - home.onOwnerLogin(this); + this.furnitureManager.onLogin(); + // Home + home = GameHome.getByUid(getUid()); + home.onOwnerLogin(this); // Activity activityManager = new ActivityManager(this); - session.send(new PacketPlayerEnterSceneNotify(this)); // Enter game world - session.send(new PacketPlayerLevelRewardUpdateNotify(rewardedLevels)); + session.send(new PacketPlayerEnterSceneNotify(this)); // Enter game world + session.send(new PacketPlayerLevelRewardUpdateNotify(rewardedLevels)); - // First notify packets sent - this.setHasSentAvatarDataNotify(true); + // First notify packets sent + this.setHasSentAvatarDataNotify(true); - // Send server welcome chat. - this.getServer().getChatManager().sendServerWelcomeMessages(this); - - // Set session state - session.setState(SessionState.ACTIVE); + // Send server welcome chat. + this.getServer().getChatManager().sendServerWelcomeMessages(this); - // Call join event. - PlayerJoinEvent event = new PlayerJoinEvent(this); event.call(); - if(event.isCanceled()){ // If event is not cancelled, continue. - session.close(); - return; - } + // Set session state + session.setState(SessionState.ACTIVE); - // register - getServer().registerPlayer(this); - getProfile().setPlayer(this); // Set online - } + // Call join event. + PlayerJoinEvent event = new PlayerJoinEvent(this); event.call(); + if (event.isCanceled()) { // If event is not cancelled, continue. + session.close(); + return; + } - public void onLogout() { - try{ - // Clear chat history. - this.getServer().getChatManager().clearHistoryOnLogout(this); + // register + getServer().registerPlayer(this); + getProfile().setPlayer(this); // Set online + } - // stop stamina calculation - getStaminaManager().stopSustainedStaminaHandler(); + public void onLogout() { + try { + // Clear chat history. + this.getServer().getChatManager().clearHistoryOnLogout(this); - // force to leave the dungeon (inside has a "if") - this.getServer().getDungeonSystem().exitDungeon(this); + // stop stamina calculation + getStaminaManager().stopSustainedStaminaHandler(); - // Leave world - if (this.getWorld() != null) { - this.getWorld().removePlayer(this); - } + // force to leave the dungeon (inside has a "if") + this.getServer().getDungeonSystem().exitDungeon(this); - // Status stuff - this.getProfile().syncWithCharacter(this); - this.getProfile().setPlayer(null); // Set offline + // Leave world + if (this.getWorld() != null) { + this.getWorld().removePlayer(this); + } - this.getCoopRequests().clear(); + // Status stuff + this.getProfile().syncWithCharacter(this); + this.getProfile().setPlayer(null); // Set offline - // Save to db - this.save(); - this.getTeamManager().saveAvatars(); - this.getFriendsList().save(); + this.getCoopRequests().clear(); - // Call quit event. - PlayerQuitEvent event = new PlayerQuitEvent(this); event.call(); - }catch (Throwable e){ - e.printStackTrace(); - Grasscutter.getLogger().warn("Player (UID {}) save failure", getUid()); - }finally { - removeFromServer(); - } - } + // Save to db + this.save(); + this.getTeamManager().saveAvatars(); + this.getFriendsList().save(); - public void removeFromServer() { - // Remove from server. - //Note: DON'T DELETE BY UID,BECAUSE THERE ARE MULTIPLE SAME UID PLAYERS WHEN DUPLICATED LOGIN! - //so I decide to delete by object rather than uid - getServer().getPlayers().values().removeIf(player1 -> player1 == this); - } + // Call quit event. + PlayerQuitEvent event = new PlayerQuitEvent(this); event.call(); + }catch (Throwable e) { + e.printStackTrace(); + Grasscutter.getLogger().warn("Player (UID {}) save failure", getUid()); + }finally { + removeFromServer(); + } + } + + public void removeFromServer() { + // Remove from server. + //Note: DON'T DELETE BY UID,BECAUSE THERE ARE MULTIPLE SAME UID PLAYERS WHEN DUPLICATED LOGIN! + //so I decide to delete by object rather than uid + getServer().getPlayers().values().removeIf(player1 -> player1 == this); + } public int getLegendaryKey() { return this.getProperty(PlayerProperty.PROP_PLAYER_LEGENDARY_KEY); @@ -1436,58 +1436,58 @@ public class Player { } public enum SceneLoadState { - NONE(0), LOADING(1), INIT(2), LOADED(3); + NONE(0), LOADING(1), INIT(2), LOADED(3); - private final int value; + private final int value; - private SceneLoadState(int value) { - this.value = value; - } + private SceneLoadState(int value) { + this.value = value; + } - public int getValue() { - return this.value; - } - } + public int getValue() { + return this.value; + } + } - public void setMessageHandler(MessageHandler messageHandler) { - this.messageHandler = messageHandler; - } + public void setMessageHandler(MessageHandler messageHandler) { + this.messageHandler = messageHandler; + } - public int getPropertyMin(PlayerProperty prop) { - if (prop.getDynamicRange()) { - return switch (prop) { - default -> 0; - }; - } else { - return prop.getMin(); - } - } + public int getPropertyMin(PlayerProperty prop) { + if (prop.getDynamicRange()) { + return switch (prop) { + default -> 0; + }; + } else { + return prop.getMin(); + } + } - public int getPropertyMax(PlayerProperty prop) { - if (prop.getDynamicRange()) { - return switch (prop) { - case PROP_CUR_SPRING_VOLUME -> getProperty(PlayerProperty.PROP_MAX_SPRING_VOLUME); - case PROP_CUR_PERSIST_STAMINA -> getProperty(PlayerProperty.PROP_MAX_STAMINA); - default -> 0; - }; - } else { - return prop.getMax(); - } - } + public int getPropertyMax(PlayerProperty prop) { + if (prop.getDynamicRange()) { + return switch (prop) { + case PROP_CUR_SPRING_VOLUME -> getProperty(PlayerProperty.PROP_MAX_SPRING_VOLUME); + case PROP_CUR_PERSIST_STAMINA -> getProperty(PlayerProperty.PROP_MAX_STAMINA); + default -> 0; + }; + } else { + return prop.getMax(); + } + } - private boolean setPropertyWithSanityCheck(PlayerProperty prop, int value, boolean sendPacket) { - int min = this.getPropertyMin(prop); - int max = this.getPropertyMax(prop); - if (min <= value && value <= max) { - this.properties.put(prop.getId(), value); - if (sendPacket) { - // Update player with packet - this.sendPacket(new PacketPlayerPropNotify(this, prop)); - } - return true; - } else { - return false; - } - } + private boolean setPropertyWithSanityCheck(PlayerProperty prop, int value, boolean sendPacket) { + int min = this.getPropertyMin(prop); + int max = this.getPropertyMax(prop); + if (min <= value && value <= max) { + this.properties.put(prop.getId(), value); + if (sendPacket) { + // Update player with packet + this.sendPacket(new PacketPlayerPropNotify(this, prop)); + } + return true; + } else { + return false; + } + } } diff --git a/src/main/java/emu/grasscutter/game/player/PlayerCollectionRecords.java b/src/main/java/emu/grasscutter/game/player/PlayerCollectionRecords.java index 676caee40..ce7bf68ec 100644 --- a/src/main/java/emu/grasscutter/game/player/PlayerCollectionRecords.java +++ b/src/main/java/emu/grasscutter/game/player/PlayerCollectionRecords.java @@ -8,60 +8,60 @@ import dev.morphia.annotations.Entity; @Entity(useDiscriminator = false) public class PlayerCollectionRecords { private Map records; - + private Map getRecords() { if (records == null) { - records = new HashMap<>(); + records = new HashMap<>(); } return records; } - - public void addRecord(int configId, long expiredMillisecond){ - Map records; + + public void addRecord(int configId, long expiredMillisecond) { + Map records; synchronized (records = getRecords()) { records.put(configId, new CollectionRecord(configId, expiredMillisecond + System.currentTimeMillis())); } } - + public boolean findRecord(int configId) { - Map records; + Map records; synchronized (records = getRecords()) { - CollectionRecord record = records.get(configId); - - if (record == null) { - return false; - } - - boolean expired = record.getExpiredTime() < System.currentTimeMillis(); - - if (expired) { - records.remove(configId); - return false; + CollectionRecord record = records.get(configId); + + if (record == null) { + return false; } - + + boolean expired = record.getExpiredTime() < System.currentTimeMillis(); + + if (expired) { + records.remove(configId); + return false; + } + return true; } } - + @Entity public static class CollectionRecord { - private int configId; - private long expiredTime; - - @Deprecated // Morphia - public CollectionRecord() {} - + private int configId; + private long expiredTime; + + @Deprecated // Morphia + public CollectionRecord() {} + public CollectionRecord(int configId, long expiredTime) { this.configId = configId; this.expiredTime = expiredTime; } - public int getConfigId() { - return configId; - } + public int getConfigId() { + return configId; + } - public long getExpiredTime() { - return expiredTime; - } + public long getExpiredTime() { + return expiredTime; + } } } diff --git a/src/main/java/emu/grasscutter/game/player/PlayerOpenStateManager.java b/src/main/java/emu/grasscutter/game/player/PlayerOpenStateManager.java index 8effaadac..8757639f4 100644 --- a/src/main/java/emu/grasscutter/game/player/PlayerOpenStateManager.java +++ b/src/main/java/emu/grasscutter/game/player/PlayerOpenStateManager.java @@ -19,7 +19,7 @@ import static emu.grasscutter.game.props.OpenState.*; public class PlayerOpenStateManager extends BasePlayerDataManager { // Map of all open states that this player has. Do not put default values here. private Map map; - + /* //DO NOT MODIFY. Based on conversation of official server and client, game version 2.7 private static Set newPlayerOpenStates = Set.of(OPEN_STATE_DERIVATIVE_MALL,OPEN_STATE_PHOTOGRAPH,OPEN_STATE_BATTLE_PASS,OPEN_STATE_SHOP_TYPE_GENESISCRYSTAL,OPEN_STATE_SHOP_TYPE_RECOMMANDED, @@ -27,7 +27,7 @@ public class PlayerOpenStateManager extends BasePlayerDataManager { OPEN_STATE_WEAPON_PROMOTE,OPEN_STATE_AVATAR_PROMOTE,OPEN_STATE_AVATAR_TALENT,OPEN_STATE_WEAPON_UPGRADE,OPEN_STATE_RESIN,OPEN_STATE_RELIQUARY_UPGRADE, OPEN_STATE_SHOP_TYPE_VIRTUAL_SHOP,OPEN_STATE_RELIQUARY_PROMOTE); */ - + // For development. Remove entry when properly implemented // TODO - Set as boolean in OpenState public static final Set DEV_OPEN_STATES = Stream.of(OpenState.values()) @@ -38,25 +38,25 @@ public class PlayerOpenStateManager extends BasePlayerDataManager { super(player); } - public Map getOpenStateMap() { - if (this.map == null) this.map = new HashMap<>(); - return this.map; - } + public Map getOpenStateMap() { + if (this.map == null) this.map = new HashMap<>(); + return this.map; + } public int getOpenState(OpenState openState) { return this.map.getOrDefault(openState.getValue(), 0); } - + public void setOpenState(OpenState openState, Integer value) { Integer previousValue = this.map.getOrDefault(openState.getValue(),0); - if(value != previousValue) { + if (value != previousValue) { this.map.put(openState.getValue(), value); player.getSession().send(new PacketOpenStateChangeNotify(openState.getValue(),value)); } } public void setOpenStates(Map openStatesChanged) { - for(Map.Entry entry : openStatesChanged.entrySet()) { + for (Map.Entry entry : openStatesChanged.entrySet()) { setOpenState(entry.getKey(), entry.getValue()); } } @@ -70,4 +70,4 @@ public class PlayerOpenStateManager extends BasePlayerDataManager { .filter(s -> s.getUnlockLevel() > 1 && s.getUnlockLevel() <= this.player.getLevel()) .forEach(s -> this.setOpenState(s, 1)); } -} \ No newline at end of file +} diff --git a/src/main/java/emu/grasscutter/game/player/TeamInfo.java b/src/main/java/emu/grasscutter/game/player/TeamInfo.java index b1f265339..692bf05c3 100644 --- a/src/main/java/emu/grasscutter/game/player/TeamInfo.java +++ b/src/main/java/emu/grasscutter/game/player/TeamInfo.java @@ -10,75 +10,75 @@ import emu.grasscutter.game.avatar.Avatar; @Entity public class TeamInfo { - private String name; - private List avatars; - - public TeamInfo() { - this.name = ""; - this.avatars = new ArrayList<>(GAME_OPTIONS.avatarLimits.singlePlayerTeam); - } + private String name; + private List avatars; - public TeamInfo(List avatars) { - this.name = ""; - this.avatars = avatars; - } + public TeamInfo() { + this.name = ""; + this.avatars = new ArrayList<>(GAME_OPTIONS.avatarLimits.singlePlayerTeam); + } - public String getName() { - return name; - } + public TeamInfo(List avatars) { + this.name = ""; + this.avatars = avatars; + } - public void setName(String name) { - this.name = name; - } + public String getName() { + return name; + } - public List getAvatars() { - return avatars; - } - - public int size() { - return avatars.size(); - } - - public boolean contains(Avatar avatar) { - return getAvatars().contains(avatar.getAvatarId()); - } + public void setName(String name) { + this.name = name; + } - public boolean addAvatar(Avatar avatar) { - if (contains(avatar)) { - return false; - } - - getAvatars().add(avatar.getAvatarId()); - - return true; - } - - public boolean removeAvatar(int slot) { - if (size() <= 1) { - return false; - } - - getAvatars().remove(slot); - - return true; - } - - public void copyFrom(TeamInfo team) { - copyFrom(team, GAME_OPTIONS.avatarLimits.singlePlayerTeam); - } - - public void copyFrom(TeamInfo team, int maxTeamSize) { - // Clone avatar ids from team to copy from - List avatarIds = new ArrayList<>(team.getAvatars()); - - // Clear current avatar list first - this.getAvatars().clear(); - - // Copy from team - int len = Math.min(avatarIds.size(), maxTeamSize); - for (int i = 0; i < len; i++) { - int id = avatarIds.get(i); - this.getAvatars().add(id); - } - } + public List getAvatars() { + return avatars; + } + + public int size() { + return avatars.size(); + } + + public boolean contains(Avatar avatar) { + return getAvatars().contains(avatar.getAvatarId()); + } + + public boolean addAvatar(Avatar avatar) { + if (contains(avatar)) { + return false; + } + + getAvatars().add(avatar.getAvatarId()); + + return true; + } + + public boolean removeAvatar(int slot) { + if (size() <= 1) { + return false; + } + + getAvatars().remove(slot); + + return true; + } + + public void copyFrom(TeamInfo team) { + copyFrom(team, GAME_OPTIONS.avatarLimits.singlePlayerTeam); + } + + public void copyFrom(TeamInfo team, int maxTeamSize) { + // Clone avatar ids from team to copy from + List avatarIds = new ArrayList<>(team.getAvatars()); + + // Clear current avatar list first + this.getAvatars().clear(); + + // Copy from team + int len = Math.min(avatarIds.size(), maxTeamSize); + for (int i = 0; i < len; i++) { + int id = avatarIds.get(i); + this.getAvatars().add(id); + } + } } diff --git a/src/main/java/emu/grasscutter/game/player/TeamManager.java b/src/main/java/emu/grasscutter/game/player/TeamManager.java index 5281f85f5..9fd19abdf 100644 --- a/src/main/java/emu/grasscutter/game/player/TeamManager.java +++ b/src/main/java/emu/grasscutter/game/player/TeamManager.java @@ -42,636 +42,636 @@ import it.unimi.dsi.fastutil.ints.IntSet; @Entity public class TeamManager extends BasePlayerDataManager { - @Transient private Player player; - - private Map teams; - private int currentTeamIndex; - private int currentCharacterIndex; - - @Transient private TeamInfo mpTeam; - @Transient private int entityId; - @Transient private final List avatars; - @Transient private final Set gadgets; - @Transient private final IntSet teamResonances; - @Transient private final IntSet teamResonancesConfig; + @Transient private Player player; - @Transient private int useTemporarilyTeamIndex = -1; - @Transient private List temporaryTeam; // Temporary Team for tower + private Map teams; + private int currentTeamIndex; + private int currentCharacterIndex; - public TeamManager() { - this.mpTeam = new TeamInfo(); - this.avatars = new ArrayList<>(); - this.gadgets = new HashSet<>(); - this.teamResonances = new IntOpenHashSet(); - this.teamResonancesConfig = new IntOpenHashSet(); - } - - public TeamManager(Player player) { - this(); - this.setPlayer(player); - - this.teams = new HashMap<>(); - this.currentTeamIndex = 1; - for (int i = 1; i <= GameConstants.MAX_TEAMS; i++) { - this.teams.put(i, new TeamInfo()); - } - } - - public World getWorld() { - return player.getWorld(); - } - - public Map getTeams() { - return this.teams; - } + @Transient private TeamInfo mpTeam; + @Transient private int entityId; + @Transient private final List avatars; + @Transient private final Set gadgets; + @Transient private final IntSet teamResonances; + @Transient private final IntSet teamResonancesConfig; - public TeamInfo getMpTeam() { - return mpTeam; - } + @Transient private int useTemporarilyTeamIndex = -1; + @Transient private List temporaryTeam; // Temporary Team for tower - public void setMpTeam(TeamInfo mpTeam) { - this.mpTeam = mpTeam; - } + public TeamManager() { + this.mpTeam = new TeamInfo(); + this.avatars = new ArrayList<>(); + this.gadgets = new HashSet<>(); + this.teamResonances = new IntOpenHashSet(); + this.teamResonancesConfig = new IntOpenHashSet(); + } - /** - * Search through all teams and if the team matches, return that index. - * Otherwise, return -1. - * No match could mean that the team does not currently belong to the player. - */ - public int getTeamId(TeamInfo team) { - for (int i = 1; i <= this.teams.size(); i++) { - if (this.teams.get(i).equals(team)) { - return i; - } - } - return -1; - } + public TeamManager(Player player) { + this(); + this.setPlayer(player); - public int getCurrentTeamId() { - // Starts from 1 - return currentTeamIndex; - } + this.teams = new HashMap<>(); + this.currentTeamIndex = 1; + for (int i = 1; i <= GameConstants.MAX_TEAMS; i++) { + this.teams.put(i, new TeamInfo()); + } + } - private void setCurrentTeamId(int currentTeamIndex) { - this.currentTeamIndex = currentTeamIndex; - } + public World getWorld() { + return player.getWorld(); + } - public int getCurrentCharacterIndex() { - return currentCharacterIndex; - } + public Map getTeams() { + return this.teams; + } - public void setCurrentCharacterIndex(int currentCharacterIndex) { - this.currentCharacterIndex = currentCharacterIndex; - } + public TeamInfo getMpTeam() { + return mpTeam; + } - public long getCurrentCharacterGuid() { - return getCurrentAvatarEntity().getAvatar().getGuid(); - } - - public TeamInfo getCurrentTeamInfo() { - if (useTemporarilyTeamIndex >= 0 && - useTemporarilyTeamIndex < temporaryTeam.size()){ - return temporaryTeam.get(useTemporarilyTeamIndex); - } - if (this.getPlayer().isInMultiplayer()) { - return this.getMpTeam(); - } - return this.getTeams().get(this.currentTeamIndex); - } - - public TeamInfo getCurrentSinglePlayerTeamInfo() { - return this.getTeams().get(this.currentTeamIndex); - } + public void setMpTeam(TeamInfo mpTeam) { + this.mpTeam = mpTeam; + } - public int getEntityId() { - return entityId; - } + /** + * Search through all teams and if the team matches, return that index. + * Otherwise, return -1. + * No match could mean that the team does not currently belong to the player. + */ + public int getTeamId(TeamInfo team) { + for (int i = 1; i <= this.teams.size(); i++) { + if (this.teams.get(i).equals(team)) { + return i; + } + } + return -1; + } - public void setEntityId(int entityId) { - this.entityId = entityId; - } + public int getCurrentTeamId() { + // Starts from 1 + return currentTeamIndex; + } - public Set getGadgets() { - return gadgets; - } + private void setCurrentTeamId(int currentTeamIndex) { + this.currentTeamIndex = currentTeamIndex; + } - public IntSet getTeamResonances() { - return teamResonances; - } + public int getCurrentCharacterIndex() { + return currentCharacterIndex; + } - public IntSet getTeamResonancesConfig() { - return teamResonancesConfig; - } + public void setCurrentCharacterIndex(int currentCharacterIndex) { + this.currentCharacterIndex = currentCharacterIndex; + } - public List getActiveTeam() { - return avatars; - } - - public EntityAvatar getCurrentAvatarEntity() { - return getActiveTeam().get(currentCharacterIndex); - } - - public boolean isSpawned() { - return getPlayer().getScene() != null && getPlayer().getScene().getEntities().containsKey(getCurrentAvatarEntity().getId()); - } - - public int getMaxTeamSize() { - if (getPlayer().isInMultiplayer()) { - int max = GAME_OPTIONS.avatarLimits.multiplayerTeam; - if (getPlayer().getWorld().getHost() == this.getPlayer()) { - return Math.max(1, (int) Math.ceil(max / (double) getWorld().getPlayerCount())); - } - return Math.max(1, (int) Math.floor(max / (double) getWorld().getPlayerCount())); - } - - return GAME_OPTIONS.avatarLimits.singlePlayerTeam; - } - - // Methods + public long getCurrentCharacterGuid() { + return getCurrentAvatarEntity().getAvatar().getGuid(); + } - /** - * Returns true if there is space to add the number of avatars to the team. - */ - public boolean canAddAvatarsToTeam(TeamInfo team, int avatars) { - return team.size() + avatars <= getMaxTeamSize(); - } + public TeamInfo getCurrentTeamInfo() { + if (useTemporarilyTeamIndex >= 0 && + useTemporarilyTeamIndex < temporaryTeam.size()) { + return temporaryTeam.get(useTemporarilyTeamIndex); + } + if (this.getPlayer().isInMultiplayer()) { + return this.getMpTeam(); + } + return this.getTeams().get(this.currentTeamIndex); + } - /** - * Returns true if there is space to add to the team. - */ - public boolean canAddAvatarToTeam(TeamInfo team) { - return canAddAvatarsToTeam(team, 1); - } + public TeamInfo getCurrentSinglePlayerTeamInfo() { + return this.getTeams().get(this.currentTeamIndex); + } - /** - * Returns true if there is space to add the number of avatars to the current team. - * If the current team is temporary, returns false. - */ - public boolean canAddAvatarsToCurrentTeam(int avatars) { - if (this.useTemporarilyTeamIndex != -1){ - return false; - } - return canAddAvatarsToTeam(this.getCurrentTeamInfo(), avatars); - } + public int getEntityId() { + return entityId; + } - /** - * Returns true if there is space to add to the current team. - * If the current team is temporary, returns false. - */ - public boolean canAddAvatarToCurrentTeam() { - return canAddAvatarsToCurrentTeam(1); - } + public void setEntityId(int entityId) { + this.entityId = entityId; + } - /** - * Try to add the collection of avatars to the team. - * Returns true if all were successfully added. - * If some can not be added, returns false and does not add any. - */ - public boolean addAvatarsToTeam(TeamInfo team, Collection avatars) { - if (!canAddAvatarsToTeam(team, avatars.size())) { - return false; - } + public Set getGadgets() { + return gadgets; + } - // Convert avatars into a collection of avatar IDs, then add - team.getAvatars().addAll(avatars.stream().map(a -> a.getAvatarId()).toList()); + public IntSet getTeamResonances() { + return teamResonances; + } - // Update team - if (this.getPlayer().isInMultiplayer()) { - if (team.equals(this.getMpTeam())) { - // MP team Packet - this.updateTeamEntities(new PacketChangeMpTeamAvatarRsp(getPlayer(), team)); - } - } else { - // SP team update packet - getPlayer().sendPacket(new PacketAvatarTeamUpdateNotify(getPlayer())); + public IntSet getTeamResonancesConfig() { + return teamResonancesConfig; + } - int teamId = this.getTeamId(team); - if (teamId != -1) { - // This is one of the player's teams - // Update entites - if (teamId == this.getCurrentTeamId()) { - this.updateTeamEntities(new PacketSetUpAvatarTeamRsp(getPlayer(), teamId, team)); - } else { - getPlayer().sendPacket(new PacketSetUpAvatarTeamRsp(getPlayer(), teamId, team)); - } - } - } + public List getActiveTeam() { + return avatars; + } - return true; - } + public EntityAvatar getCurrentAvatarEntity() { + return getActiveTeam().get(currentCharacterIndex); + } - /** - * Try to add an avatar to a team. - * Returns true if successful. - */ - public boolean addAvatarToTeam(TeamInfo team, Avatar avatar){ - return addAvatarsToTeam(team, Collections.singleton(avatar)); - } + public boolean isSpawned() { + return getPlayer().getScene() != null && getPlayer().getScene().getEntities().containsKey(getCurrentAvatarEntity().getId()); + } - /** - * Try to add the collection of avatars to the current team. - * Will not modify a temporary team. - * Returns true if all were successfully added. - * If some can not be added, returns false and does not add any. - */ - public boolean addAvatarsToCurrentTeam(Collection avatars) { - if (this.useTemporarilyTeamIndex != -1){ - return false; - } - return addAvatarsToTeam(this.getCurrentTeamInfo(), avatars); - } + public int getMaxTeamSize() { + if (getPlayer().isInMultiplayer()) { + int max = GAME_OPTIONS.avatarLimits.multiplayerTeam; + if (getPlayer().getWorld().getHost() == this.getPlayer()) { + return Math.max(1, (int) Math.ceil(max / (double) getWorld().getPlayerCount())); + } + return Math.max(1, (int) Math.floor(max / (double) getWorld().getPlayerCount())); + } - /** - * Try to add an avatar to the current team. - * Will not modify a temporary team. - * Returns true if successful. - */ - public boolean addAvatarToCurrentTeam(Avatar avatar) { - return addAvatarsToCurrentTeam(Collections.singleton(avatar)); - } + return GAME_OPTIONS.avatarLimits.singlePlayerTeam; + } - private void updateTeamResonances() { - Int2IntOpenHashMap map = new Int2IntOpenHashMap(); - - this.getTeamResonances().clear(); - this.getTeamResonancesConfig().clear(); - - for (EntityAvatar entity : getActiveTeam()) { - AvatarSkillDepotData skillData = entity.getAvatar().getAvatarData().getSkillDepot(); - if (skillData != null) { - map.addTo(skillData.getElementType().getValue(), 1); - } - } - - for (Int2IntMap.Entry e : map.int2IntEntrySet()) { - if (e.getIntValue() >= 2) { - ElementType element = ElementType.getTypeByValue(e.getIntKey()); - if (element.getTeamResonanceId() != 0) { - this.getTeamResonances().add(element.getTeamResonanceId()); - this.getTeamResonancesConfig().add(element.getConfigHash()); - } - } - } - - // No resonances - if (this.getTeamResonances().size() == 0) { - this.getTeamResonances().add(ElementType.Default.getTeamResonanceId()); - this.getTeamResonancesConfig().add(ElementType.Default.getTeamResonanceId()); - } - } - - public void updateTeamEntities(BasePacket responsePacket) { - // Sanity check - Should never happen - if (this.getCurrentTeamInfo().getAvatars().size() <= 0) { - return; - } - - // If current team has changed - EntityAvatar currentEntity = this.getCurrentAvatarEntity(); - Int2ObjectMap existingAvatars = new Int2ObjectOpenHashMap<>(); - int prevSelectedAvatarIndex = -1; - - for (EntityAvatar entity : getActiveTeam()) { - existingAvatars.put(entity.getAvatar().getAvatarId(), entity); - } - - // Clear active team entity list - this.getActiveTeam().clear(); - - // Add back entities into team - for (int i = 0; i < this.getCurrentTeamInfo().getAvatars().size(); i++) { - int avatarId = this.getCurrentTeamInfo().getAvatars().get(i); - EntityAvatar entity; - - if (existingAvatars.containsKey(avatarId)) { - entity = existingAvatars.get(avatarId); - existingAvatars.remove(avatarId); - if (entity == currentEntity) { - prevSelectedAvatarIndex = i; - } - } else { - entity = new EntityAvatar(getPlayer().getScene(), getPlayer().getAvatars().getAvatarById(avatarId)); - } - - this.getActiveTeam().add(entity); - } - - // Unload removed entities - for (EntityAvatar entity : existingAvatars.values()) { - getPlayer().getScene().removeEntity(entity); - entity.getAvatar().save(); - } - - // Set new selected character index - if (prevSelectedAvatarIndex == -1) { - // Previous selected avatar is not in the same spot, we will select the current one in the prev slot - prevSelectedAvatarIndex = Math.min(this.currentCharacterIndex, this.getActiveTeam().size() - 1); - } - this.currentCharacterIndex = prevSelectedAvatarIndex; - - // Update team resonances - updateTeamResonances(); - - // Packets - getPlayer().getWorld().broadcastPacket(new PacketSceneTeamUpdateNotify(getPlayer())); - - // Skill charges packet - Yes, this is official server behavior as of 2.6.0 - for (EntityAvatar entity : getActiveTeam()) { - if (entity.getAvatar().getSkillExtraChargeMap().size() > 0) { - getPlayer().sendPacket(new PacketAvatarSkillInfoNotify(entity.getAvatar())); - } - } - - // Run callback - if (responsePacket != null) { - getPlayer().sendPacket(responsePacket); - } + // Methods - // Check if character changed - if (currentEntity != getCurrentAvatarEntity()) { - // Remove and Add - getPlayer().getScene().replaceEntity(currentEntity, getCurrentAvatarEntity()); - } - } - - public synchronized void setupAvatarTeam(int teamId, List list) { - // Sanity checks - if (list.size() == 0 || list.size() > getMaxTeamSize() || getPlayer().isInMultiplayer()) { - return; - } - - // Get team - TeamInfo teamInfo = this.getTeams().get(teamId); - if (teamInfo == null) { - return; - } - - // Set team data - LinkedHashSet newTeam = new LinkedHashSet<>(); - for (Long aLong : list) { - Avatar avatar = getPlayer().getAvatars().getAvatarByGuid(aLong); - if (avatar == null || newTeam.contains(avatar)) { - // Should never happen - return; - } - newTeam.add(avatar); - } - - // Clear current team info and add avatars from our new team - teamInfo.getAvatars().clear(); - this.addAvatarsToTeam(teamInfo, newTeam); - } - - public void setupMpTeam(List list) { - // Sanity checks - if (list.size() == 0 || list.size() > getMaxTeamSize() || !getPlayer().isInMultiplayer()) { - return; - } + /** + * Returns true if there is space to add the number of avatars to the team. + */ + public boolean canAddAvatarsToTeam(TeamInfo team, int avatars) { + return team.size() + avatars <= getMaxTeamSize(); + } - TeamInfo teamInfo = this.getMpTeam(); - - // Set team data - LinkedHashSet newTeam = new LinkedHashSet<>(); - for (Long aLong : list) { - Avatar avatar = getPlayer().getAvatars().getAvatarByGuid(aLong); - if (avatar == null || newTeam.contains(avatar)) { - // Should never happen - return; - } - newTeam.add(avatar); - } - - // Clear current team info and add avatars from our new team - teamInfo.getAvatars().clear(); - this.addAvatarsToTeam(teamInfo, newTeam); - } + /** + * Returns true if there is space to add to the team. + */ + public boolean canAddAvatarToTeam(TeamInfo team) { + return canAddAvatarsToTeam(team, 1); + } - public void setupTemporaryTeam(List> guidList) { - this.temporaryTeam = guidList.stream().map(list -> { - // Sanity checks - if (list.size() == 0 || list.size() > getMaxTeamSize()) { - return null; - } + /** + * Returns true if there is space to add the number of avatars to the current team. + * If the current team is temporary, returns false. + */ + public boolean canAddAvatarsToCurrentTeam(int avatars) { + if (this.useTemporarilyTeamIndex != -1) { + return false; + } + return canAddAvatarsToTeam(this.getCurrentTeamInfo(), avatars); + } - // Set team data - LinkedHashSet newTeam = new LinkedHashSet<>(); - for (Long aLong : list) { - Avatar avatar = getPlayer().getAvatars().getAvatarByGuid(aLong); - if (avatar == null || newTeam.contains(avatar)) { - // Should never happen - return null; - } - newTeam.add(avatar); - } + /** + * Returns true if there is space to add to the current team. + * If the current team is temporary, returns false. + */ + public boolean canAddAvatarToCurrentTeam() { + return canAddAvatarsToCurrentTeam(1); + } - // convert to avatar ids - return newTeam.stream() - .map(Avatar::getAvatarId) - .toList(); - }) - .filter(Objects::nonNull) - .map(TeamInfo::new) - .toList(); - } + /** + * Try to add the collection of avatars to the team. + * Returns true if all were successfully added. + * If some can not be added, returns false and does not add any. + */ + public boolean addAvatarsToTeam(TeamInfo team, Collection avatars) { + if (!canAddAvatarsToTeam(team, avatars.size())) { + return false; + } - public void useTemporaryTeam(int index) { - this.useTemporarilyTeamIndex = index; - updateTeamEntities(null); - } + // Convert avatars into a collection of avatar IDs, then add + team.getAvatars().addAll(avatars.stream().map(a -> a.getAvatarId()).toList()); - public void cleanTemporaryTeam() { - // check if using temporary team - if(useTemporarilyTeamIndex < 0){ - return; - } + // Update team + if (this.getPlayer().isInMultiplayer()) { + if (team.equals(this.getMpTeam())) { + // MP team Packet + this.updateTeamEntities(new PacketChangeMpTeamAvatarRsp(getPlayer(), team)); + } + } else { + // SP team update packet + getPlayer().sendPacket(new PacketAvatarTeamUpdateNotify(getPlayer())); - this.useTemporarilyTeamIndex = -1; - this.temporaryTeam = null; - updateTeamEntities(null); - } - public synchronized void setCurrentTeam(int teamId) { - // - if (getPlayer().isInMultiplayer()) { - return; - } - - // Get team - TeamInfo teamInfo = this.getTeams().get(teamId); - if (teamInfo == null || teamInfo.getAvatars().size() == 0) { - return; - } - - // Set - this.setCurrentTeamId(teamId); - this.updateTeamEntities(new PacketChooseCurAvatarTeamRsp(teamId)); - } + int teamId = this.getTeamId(team); + if (teamId != -1) { + // This is one of the player's teams + // Update entites + if (teamId == this.getCurrentTeamId()) { + this.updateTeamEntities(new PacketSetUpAvatarTeamRsp(getPlayer(), teamId, team)); + } else { + getPlayer().sendPacket(new PacketSetUpAvatarTeamRsp(getPlayer(), teamId, team)); + } + } + } - public synchronized void setTeamName(int teamId, String teamName) { - // Get team - TeamInfo teamInfo = this.getTeams().get(teamId); - if (teamInfo == null) { - return; - } - - teamInfo.setName(teamName); - - // Packet - getPlayer().sendPacket(new PacketChangeTeamNameRsp(teamId, teamName)); - } + return true; + } - public synchronized void changeAvatar(long guid) { - EntityAvatar oldEntity = this.getCurrentAvatarEntity(); - - if (guid == oldEntity.getAvatar().getGuid()) { - return; - } + /** + * Try to add an avatar to a team. + * Returns true if successful. + */ + public boolean addAvatarToTeam(TeamInfo team, Avatar avatar) { + return addAvatarsToTeam(team, Collections.singleton(avatar)); + } - EntityAvatar newEntity = null; - int index = -1; - for (int i = 0; i < getActiveTeam().size(); i++) { - if (guid == getActiveTeam().get(i).getAvatar().getGuid()) { - index = i; - newEntity = getActiveTeam().get(i); - } - } - - if (index < 0 || newEntity == oldEntity) { - return; - } - - // Set index - this.setCurrentCharacterIndex(index); - - // Old entity motion state - oldEntity.setMotionState(MotionState.MOTION_STATE_STANDBY); + /** + * Try to add the collection of avatars to the current team. + * Will not modify a temporary team. + * Returns true if all were successfully added. + * If some can not be added, returns false and does not add any. + */ + public boolean addAvatarsToCurrentTeam(Collection avatars) { + if (this.useTemporarilyTeamIndex != -1) { + return false; + } + return addAvatarsToTeam(this.getCurrentTeamInfo(), avatars); + } - // Remove and Add - getPlayer().getScene().replaceEntity(oldEntity, newEntity); - getPlayer().sendPacket(new PacketChangeAvatarRsp(guid)); - } - - public void onAvatarDie(long dieGuid) { - EntityAvatar deadAvatar = this.getCurrentAvatarEntity(); - - if (deadAvatar.isAlive() || deadAvatar.getId() != dieGuid) { - return; - } + /** + * Try to add an avatar to the current team. + * Will not modify a temporary team. + * Returns true if successful. + */ + public boolean addAvatarToCurrentTeam(Avatar avatar) { + return addAvatarsToCurrentTeam(Collections.singleton(avatar)); + } - PlayerDieType dieType = deadAvatar.getKilledType(); - int killedBy = deadAvatar.getKilledBy(); + private void updateTeamResonances() { + Int2IntOpenHashMap map = new Int2IntOpenHashMap(); - if (dieType == PlayerDieType.PLAYER_DIE_TYPE_DRAWN) { - // Died in water. Do not replace - // The official server has skipped this notify and will just respawn the team immediately after the animation. - // TODO: Perhaps find a way to get vanilla experience? - getPlayer().sendPacket(new PacketWorldPlayerDieNotify(dieType, killedBy)); - } else { - // Replacement avatar - EntityAvatar replacement = null; - int replaceIndex = -1; + this.getTeamResonances().clear(); + this.getTeamResonancesConfig().clear(); - for (int i = 0; i < this.getActiveTeam().size(); i++) { - EntityAvatar entity = this.getActiveTeam().get(i); - if (entity.isAlive()) { - replaceIndex = i; - replacement = entity; - break; - } - } + for (EntityAvatar entity : getActiveTeam()) { + AvatarSkillDepotData skillData = entity.getAvatar().getAvatarData().getSkillDepot(); + if (skillData != null) { + map.addTo(skillData.getElementType().getValue(), 1); + } + } - if (replacement == null) { - // No more living team members... - getPlayer().sendPacket(new PacketWorldPlayerDieNotify(dieType, killedBy)); - } else { - // Set index and spawn replacement member - this.setCurrentCharacterIndex(replaceIndex); - getPlayer().getScene().addEntity(replacement); - } - } + for (Int2IntMap.Entry e : map.int2IntEntrySet()) { + if (e.getIntValue() >= 2) { + ElementType element = ElementType.getTypeByValue(e.getIntKey()); + if (element.getTeamResonanceId() != 0) { + this.getTeamResonances().add(element.getTeamResonanceId()); + this.getTeamResonancesConfig().add(element.getConfigHash()); + } + } + } - // Response packet - getPlayer().sendPacket(new PacketAvatarDieAnimationEndRsp(deadAvatar.getId(), 0)); - } - - public boolean reviveAvatar(Avatar avatar) { - for (EntityAvatar entity : getActiveTeam()) { - if (entity.getAvatar() == avatar) { - if (entity.isAlive()) { - return false; - } - - entity.setFightProperty( - FightProperty.FIGHT_PROP_CUR_HP, - entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * .1f - ); - getPlayer().sendPacket(new PacketAvatarFightPropUpdateNotify(entity.getAvatar(), FightProperty.FIGHT_PROP_CUR_HP)); - getPlayer().sendPacket(new PacketAvatarLifeStateChangeNotify(entity.getAvatar())); - return true; - } - } - - return false; - } + // No resonances + if (this.getTeamResonances().size() == 0) { + this.getTeamResonances().add(ElementType.Default.getTeamResonanceId()); + this.getTeamResonancesConfig().add(ElementType.Default.getTeamResonanceId()); + } + } - public boolean healAvatar(Avatar avatar, int healRate, int healAmount) { - for (EntityAvatar entity : getActiveTeam()) { - if (entity.getAvatar() == avatar) { - if (!entity.isAlive()) { - return false; - } + public void updateTeamEntities(BasePacket responsePacket) { + // Sanity check - Should never happen + if (this.getCurrentTeamInfo().getAvatars().size() <= 0) { + return; + } - entity.setFightProperty( - FightProperty.FIGHT_PROP_CUR_HP, - (float) Math.min( - (entity.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) + - entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * (float) healRate / 100.0 + - (float) healAmount / 100.0), - entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) - ) - ); - getPlayer().sendPacket(new PacketAvatarFightPropUpdateNotify(entity.getAvatar(), FightProperty.FIGHT_PROP_CUR_HP)); - getPlayer().sendPacket(new PacketAvatarLifeStateChangeNotify(entity.getAvatar())); - return true; - } - } - return false; - } + // If current team has changed + EntityAvatar currentEntity = this.getCurrentAvatarEntity(); + Int2ObjectMap existingAvatars = new Int2ObjectOpenHashMap<>(); + int prevSelectedAvatarIndex = -1; - public void respawnTeam() { - // Make sure all team members are dead - // Drowning needs revive when there may be other team members still alive. - // for (EntityAvatar entity : getActiveTeam()) { - // if (entity.isAlive()) { - // return; - // } - // } - player.getStaminaManager().stopSustainedStaminaHandler(); // prevent drowning immediately after respawn - - // Revive all team members - for (EntityAvatar entity : getActiveTeam()) { - entity.setFightProperty( - FightProperty.FIGHT_PROP_CUR_HP, - entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * .4f - ); - getPlayer().sendPacket(new PacketAvatarFightPropUpdateNotify(entity.getAvatar(), FightProperty.FIGHT_PROP_CUR_HP)); - getPlayer().sendPacket(new PacketAvatarLifeStateChangeNotify(entity.getAvatar())); - } - - // Teleport player - getPlayer().sendPacket(new PacketPlayerEnterSceneNotify(getPlayer(), EnterType.ENTER_TYPE_SELF, EnterReason.Revival, 3, GameConstants.START_POSITION)); - - // Set player position - player.setSceneId(3); - player.getPosition().set(GameConstants.START_POSITION); + for (EntityAvatar entity : getActiveTeam()) { + existingAvatars.put(entity.getAvatar().getAvatarId(), entity); + } - // Packets - getPlayer().sendPacket(new BasePacket(PacketOpcodes.WorldPlayerReviveRsp)); - } + // Clear active team entity list + this.getActiveTeam().clear(); - public void saveAvatars() { - // Save all avatars from active team - for (EntityAvatar entity : getActiveTeam()) { - entity.getAvatar().save(); - } - } + // Add back entities into team + for (int i = 0; i < this.getCurrentTeamInfo().getAvatars().size(); i++) { + int avatarId = this.getCurrentTeamInfo().getAvatars().get(i); + EntityAvatar entity; + + if (existingAvatars.containsKey(avatarId)) { + entity = existingAvatars.get(avatarId); + existingAvatars.remove(avatarId); + if (entity == currentEntity) { + prevSelectedAvatarIndex = i; + } + } else { + entity = new EntityAvatar(getPlayer().getScene(), getPlayer().getAvatars().getAvatarById(avatarId)); + } + + this.getActiveTeam().add(entity); + } + + // Unload removed entities + for (EntityAvatar entity : existingAvatars.values()) { + getPlayer().getScene().removeEntity(entity); + entity.getAvatar().save(); + } + + // Set new selected character index + if (prevSelectedAvatarIndex == -1) { + // Previous selected avatar is not in the same spot, we will select the current one in the prev slot + prevSelectedAvatarIndex = Math.min(this.currentCharacterIndex, this.getActiveTeam().size() - 1); + } + this.currentCharacterIndex = prevSelectedAvatarIndex; + + // Update team resonances + updateTeamResonances(); + + // Packets + getPlayer().getWorld().broadcastPacket(new PacketSceneTeamUpdateNotify(getPlayer())); + + // Skill charges packet - Yes, this is official server behavior as of 2.6.0 + for (EntityAvatar entity : getActiveTeam()) { + if (entity.getAvatar().getSkillExtraChargeMap().size() > 0) { + getPlayer().sendPacket(new PacketAvatarSkillInfoNotify(entity.getAvatar())); + } + } + + // Run callback + if (responsePacket != null) { + getPlayer().sendPacket(responsePacket); + } + + // Check if character changed + if (currentEntity != getCurrentAvatarEntity()) { + // Remove and Add + getPlayer().getScene().replaceEntity(currentEntity, getCurrentAvatarEntity()); + } + } + + public synchronized void setupAvatarTeam(int teamId, List list) { + // Sanity checks + if (list.size() == 0 || list.size() > getMaxTeamSize() || getPlayer().isInMultiplayer()) { + return; + } + + // Get team + TeamInfo teamInfo = this.getTeams().get(teamId); + if (teamInfo == null) { + return; + } + + // Set team data + LinkedHashSet newTeam = new LinkedHashSet<>(); + for (Long aLong : list) { + Avatar avatar = getPlayer().getAvatars().getAvatarByGuid(aLong); + if (avatar == null || newTeam.contains(avatar)) { + // Should never happen + return; + } + newTeam.add(avatar); + } + + // Clear current team info and add avatars from our new team + teamInfo.getAvatars().clear(); + this.addAvatarsToTeam(teamInfo, newTeam); + } + + public void setupMpTeam(List list) { + // Sanity checks + if (list.size() == 0 || list.size() > getMaxTeamSize() || !getPlayer().isInMultiplayer()) { + return; + } + + TeamInfo teamInfo = this.getMpTeam(); + + // Set team data + LinkedHashSet newTeam = new LinkedHashSet<>(); + for (Long aLong : list) { + Avatar avatar = getPlayer().getAvatars().getAvatarByGuid(aLong); + if (avatar == null || newTeam.contains(avatar)) { + // Should never happen + return; + } + newTeam.add(avatar); + } + + // Clear current team info and add avatars from our new team + teamInfo.getAvatars().clear(); + this.addAvatarsToTeam(teamInfo, newTeam); + } + + public void setupTemporaryTeam(List> guidList) { + this.temporaryTeam = guidList.stream().map(list -> { + // Sanity checks + if (list.size() == 0 || list.size() > getMaxTeamSize()) { + return null; + } + + // Set team data + LinkedHashSet newTeam = new LinkedHashSet<>(); + for (Long aLong : list) { + Avatar avatar = getPlayer().getAvatars().getAvatarByGuid(aLong); + if (avatar == null || newTeam.contains(avatar)) { + // Should never happen + return null; + } + newTeam.add(avatar); + } + + // convert to avatar ids + return newTeam.stream() + .map(Avatar::getAvatarId) + .toList(); + }) + .filter(Objects::nonNull) + .map(TeamInfo::new) + .toList(); + } + + public void useTemporaryTeam(int index) { + this.useTemporarilyTeamIndex = index; + updateTeamEntities(null); + } + + public void cleanTemporaryTeam() { + // check if using temporary team + if (useTemporarilyTeamIndex < 0) { + return; + } + + this.useTemporarilyTeamIndex = -1; + this.temporaryTeam = null; + updateTeamEntities(null); + } + public synchronized void setCurrentTeam(int teamId) { + // + if (getPlayer().isInMultiplayer()) { + return; + } + + // Get team + TeamInfo teamInfo = this.getTeams().get(teamId); + if (teamInfo == null || teamInfo.getAvatars().size() == 0) { + return; + } + + // Set + this.setCurrentTeamId(teamId); + this.updateTeamEntities(new PacketChooseCurAvatarTeamRsp(teamId)); + } + + public synchronized void setTeamName(int teamId, String teamName) { + // Get team + TeamInfo teamInfo = this.getTeams().get(teamId); + if (teamInfo == null) { + return; + } + + teamInfo.setName(teamName); + + // Packet + getPlayer().sendPacket(new PacketChangeTeamNameRsp(teamId, teamName)); + } + + public synchronized void changeAvatar(long guid) { + EntityAvatar oldEntity = this.getCurrentAvatarEntity(); + + if (guid == oldEntity.getAvatar().getGuid()) { + return; + } + + EntityAvatar newEntity = null; + int index = -1; + for (int i = 0; i < getActiveTeam().size(); i++) { + if (guid == getActiveTeam().get(i).getAvatar().getGuid()) { + index = i; + newEntity = getActiveTeam().get(i); + } + } + + if (index < 0 || newEntity == oldEntity) { + return; + } + + // Set index + this.setCurrentCharacterIndex(index); + + // Old entity motion state + oldEntity.setMotionState(MotionState.MOTION_STATE_STANDBY); + + // Remove and Add + getPlayer().getScene().replaceEntity(oldEntity, newEntity); + getPlayer().sendPacket(new PacketChangeAvatarRsp(guid)); + } + + public void onAvatarDie(long dieGuid) { + EntityAvatar deadAvatar = this.getCurrentAvatarEntity(); + + if (deadAvatar.isAlive() || deadAvatar.getId() != dieGuid) { + return; + } + + PlayerDieType dieType = deadAvatar.getKilledType(); + int killedBy = deadAvatar.getKilledBy(); + + if (dieType == PlayerDieType.PLAYER_DIE_TYPE_DRAWN) { + // Died in water. Do not replace + // The official server has skipped this notify and will just respawn the team immediately after the animation. + // TODO: Perhaps find a way to get vanilla experience? + getPlayer().sendPacket(new PacketWorldPlayerDieNotify(dieType, killedBy)); + } else { + // Replacement avatar + EntityAvatar replacement = null; + int replaceIndex = -1; + + for (int i = 0; i < this.getActiveTeam().size(); i++) { + EntityAvatar entity = this.getActiveTeam().get(i); + if (entity.isAlive()) { + replaceIndex = i; + replacement = entity; + break; + } + } + + if (replacement == null) { + // No more living team members... + getPlayer().sendPacket(new PacketWorldPlayerDieNotify(dieType, killedBy)); + } else { + // Set index and spawn replacement member + this.setCurrentCharacterIndex(replaceIndex); + getPlayer().getScene().addEntity(replacement); + } + } + + // Response packet + getPlayer().sendPacket(new PacketAvatarDieAnimationEndRsp(deadAvatar.getId(), 0)); + } + + public boolean reviveAvatar(Avatar avatar) { + for (EntityAvatar entity : getActiveTeam()) { + if (entity.getAvatar() == avatar) { + if (entity.isAlive()) { + return false; + } + + entity.setFightProperty( + FightProperty.FIGHT_PROP_CUR_HP, + entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * .1f + ); + getPlayer().sendPacket(new PacketAvatarFightPropUpdateNotify(entity.getAvatar(), FightProperty.FIGHT_PROP_CUR_HP)); + getPlayer().sendPacket(new PacketAvatarLifeStateChangeNotify(entity.getAvatar())); + return true; + } + } + + return false; + } + + public boolean healAvatar(Avatar avatar, int healRate, int healAmount) { + for (EntityAvatar entity : getActiveTeam()) { + if (entity.getAvatar() == avatar) { + if (!entity.isAlive()) { + return false; + } + + entity.setFightProperty( + FightProperty.FIGHT_PROP_CUR_HP, + (float) Math.min( + (entity.getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) + + entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * (float) healRate / 100.0 + + (float) healAmount / 100.0), + entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) + ) + ); + getPlayer().sendPacket(new PacketAvatarFightPropUpdateNotify(entity.getAvatar(), FightProperty.FIGHT_PROP_CUR_HP)); + getPlayer().sendPacket(new PacketAvatarLifeStateChangeNotify(entity.getAvatar())); + return true; + } + } + return false; + } + + public void respawnTeam() { + // Make sure all team members are dead + // Drowning needs revive when there may be other team members still alive. + // for (EntityAvatar entity : getActiveTeam()) { + // if (entity.isAlive()) { + // return; + // } + // } + player.getStaminaManager().stopSustainedStaminaHandler(); // prevent drowning immediately after respawn + + // Revive all team members + for (EntityAvatar entity : getActiveTeam()) { + entity.setFightProperty( + FightProperty.FIGHT_PROP_CUR_HP, + entity.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * .4f + ); + getPlayer().sendPacket(new PacketAvatarFightPropUpdateNotify(entity.getAvatar(), FightProperty.FIGHT_PROP_CUR_HP)); + getPlayer().sendPacket(new PacketAvatarLifeStateChangeNotify(entity.getAvatar())); + } + + // Teleport player + getPlayer().sendPacket(new PacketPlayerEnterSceneNotify(getPlayer(), EnterType.ENTER_TYPE_SELF, EnterReason.Revival, 3, GameConstants.START_POSITION)); + + // Set player position + player.setSceneId(3); + player.getPosition().set(GameConstants.START_POSITION); + + // Packets + getPlayer().sendPacket(new BasePacket(PacketOpcodes.WorldPlayerReviveRsp)); + } + + public void saveAvatars() { + // Save all avatars from active team + for (EntityAvatar entity : getActiveTeam()) { + entity.getAvatar().save(); + } + } } diff --git a/src/main/java/emu/grasscutter/game/props/OpenState.java b/src/main/java/emu/grasscutter/game/props/OpenState.java index 536c57d45..b908bd45b 100644 --- a/src/main/java/emu/grasscutter/game/props/OpenState.java +++ b/src/main/java/emu/grasscutter/game/props/OpenState.java @@ -8,221 +8,221 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; public enum OpenState { - OPEN_STATE_NONE (0), - OPEN_STATE_PAIMON (1), - OPEN_STATE_PAIMON_NAVIGATION (2), - OPEN_STATE_AVATAR_PROMOTE (3), - OPEN_STATE_AVATAR_TALENT (4), - OPEN_STATE_WEAPON_PROMOTE (5), - OPEN_STATE_WEAPON_AWAKEN (6), - OPEN_STATE_QUEST_REMIND (7), - OPEN_STATE_GAME_GUIDE (8), - OPEN_STATE_COOK (9), - OPEN_STATE_WEAPON_UPGRADE (10), - OPEN_STATE_RELIQUARY_UPGRADE (11), - OPEN_STATE_RELIQUARY_PROMOTE (12), - OPEN_STATE_WEAPON_PROMOTE_GUIDE (13), - OPEN_STATE_WEAPON_CHANGE_GUIDE (14), - OPEN_STATE_PLAYER_LVUP_GUIDE (15), - OPEN_STATE_FRESHMAN_GUIDE (16), - OPEN_STATE_SKIP_FRESHMAN_GUIDE (17), - OPEN_STATE_GUIDE_MOVE_CAMERA (18), - OPEN_STATE_GUIDE_SCALE_CAMERA (19), - OPEN_STATE_GUIDE_KEYBOARD (20), - OPEN_STATE_GUIDE_MOVE (21), - OPEN_STATE_GUIDE_JUMP (22), - OPEN_STATE_GUIDE_SPRINT (23), - OPEN_STATE_GUIDE_MAP (24), - OPEN_STATE_GUIDE_ATTACK (25), - OPEN_STATE_GUIDE_FLY (26), - OPEN_STATE_GUIDE_TALENT (27), - OPEN_STATE_GUIDE_RELIC (28), - OPEN_STATE_GUIDE_RELIC_PROM (29), - OPEN_STATE_COMBINE (30, 2), - OPEN_STATE_GACHA (31), - OPEN_STATE_GUIDE_GACHA (32), - OPEN_STATE_GUIDE_TEAM (33), - OPEN_STATE_GUIDE_PROUD (34), - OPEN_STATE_GUIDE_AVATAR_PROMOTE (35), - OPEN_STATE_GUIDE_ADVENTURE_CARD (36), - OPEN_STATE_FORGE (37, 2), - OPEN_STATE_GUIDE_BAG (38), - OPEN_STATE_EXPEDITION (39, 14), - OPEN_STATE_GUIDE_ADVENTURE_DAILYTASK (40), - OPEN_STATE_GUIDE_ADVENTURE_DUNGEON (41), - OPEN_STATE_TOWER (42), - OPEN_STATE_WORLD_STAMINA (43), - OPEN_STATE_TOWER_FIRST_ENTER (44), - OPEN_STATE_RESIN (45), - OPEN_STATE_LIMIT_REGION_FRESHMEAT (47), - OPEN_STATE_LIMIT_REGION_GLOBAL (48), - OPEN_STATE_MULTIPLAYER (49, 16), - OPEN_STATE_GUIDE_MOUSEPC (50), - OPEN_STATE_GUIDE_MULTIPLAYER (51), - OPEN_STATE_GUIDE_DUNGEONREWARD (52), - OPEN_STATE_GUIDE_BLOSSOM (53, 8), - OPEN_STATE_AVATAR_FASHION (54), - OPEN_STATE_PHOTOGRAPH (55), - OPEN_STATE_GUIDE_KSLQUEST (56), - OPEN_STATE_PERSONAL_LINE (57, 26), - OPEN_STATE_GUIDE_PERSONAL_LINE (58), - OPEN_STATE_GUIDE_APPEARANCE (59), - OPEN_STATE_GUIDE_PROCESS (60), - OPEN_STATE_GUIDE_PERSONAL_LINE_KEY (61), - OPEN_STATE_GUIDE_WIDGET (62), - OPEN_STATE_GUIDE_ACTIVITY_SKILL_ASTER (63), - OPEN_STATE_GUIDE_COLDCLIMATE (64), - OPEN_STATE_DERIVATIVE_MALL (65), - OPEN_STATE_GUIDE_EXITMULTIPLAYER (66), - OPEN_STATE_GUIDE_THEATREMACHANICUS_BUILD (67), - OPEN_STATE_GUIDE_THEATREMACHANICUS_REBUILD (68), - OPEN_STATE_GUIDE_THEATREMACHANICUS_CARD (69), - OPEN_STATE_GUIDE_THEATREMACHANICUS_MONSTER (70), - OPEN_STATE_GUIDE_THEATREMACHANICUS_MISSION_CHECK (71), - OPEN_STATE_GUIDE_THEATREMACHANICUS_BUILD_SELECT (72), - OPEN_STATE_GUIDE_THEATREMACHANICUS_CHALLENGE_START (73), - OPEN_STATE_GUIDE_CONVERT (74), - OPEN_STATE_GUIDE_THEATREMACHANICUS_MULTIPLAYER (75), - OPEN_STATE_GUIDE_COOP_TASK (76), - OPEN_STATE_GUIDE_HOMEWORLD_ADEPTIABODE (77), - OPEN_STATE_GUIDE_HOMEWORLD_DEPLOY (78), - OPEN_STATE_GUIDE_CHANNELLERSLAB_EQUIP (79), - OPEN_STATE_GUIDE_CHANNELLERSLAB_MP_SOLUTION (80), - OPEN_STATE_GUIDE_CHANNELLERSLAB_POWER (81), - OPEN_STATE_GUIDE_HIDEANDSEEK_SKILL (82), - OPEN_STATE_GUIDE_HOMEWORLD_MAPLIST (83), - OPEN_STATE_GUIDE_RELICRESOLVE (84), - OPEN_STATE_GUIDE_GGUIDE (85), - OPEN_STATE_GUIDE_GGUIDE_HINT (86), - OPEN_STATE_GUIDE_CHANNELLERSLAB_EQUIP_V2 (87), - OPEN_STATE_GUIDE_CHANNELLERSLAB_MP_SOLUTION_V2 (88), - OPEN_STATE_GUIDE_CHANNELLERSLAB_POWER_V2 (89), - OPEN_STATE_GUIDE_QUICK_TEAMMEMBERCHANGE (90), // Mobile only - OPEN_STATE_GGUIDE_FIRSTSHOW (91), - OPEN_STATE_GGUIDE_MAINPAGE_ENTRY_DISAPPEAR (92), - OPEN_STATE_CITY_REPUATION_MENGDE (800), - OPEN_STATE_CITY_REPUATION_LIYUE (801), - OPEN_STATE_CITY_REPUATION_UI_HINT (802, 25), - OPEN_STATE_CITY_REPUATION_INAZUMA (803), - OPEN_STATE_SHOP_TYPE_MALL (900), - OPEN_STATE_SHOP_TYPE_RECOMMANDED (901, 1), - OPEN_STATE_SHOP_TYPE_GENESISCRYSTAL (902, 1), - OPEN_STATE_SHOP_TYPE_GIFTPACKAGE (903, 1), - OPEN_STATE_SHOP_TYPE_PAIMON (1001), - OPEN_STATE_SHOP_TYPE_CITY (1002), - OPEN_STATE_SHOP_TYPE_BLACKSMITH (1003), - OPEN_STATE_SHOP_TYPE_GROCERY (1004, 5), - OPEN_STATE_SHOP_TYPE_FOOD (1005, 5), - OPEN_STATE_SHOP_TYPE_SEA_LAMP (1006, 13), - OPEN_STATE_SHOP_TYPE_VIRTUAL_SHOP (1007), - OPEN_STATE_SHOP_TYPE_LIYUE_GROCERY (1008, 5), - OPEN_STATE_SHOP_TYPE_LIYUE_SOUVENIR (1009), - OPEN_STATE_SHOP_TYPE_LIYUE_RESTAURANT (1010, 5), - OPEN_STATE_SHOP_TYPE_INAZUMA_SOUVENIR (1011), - OPEN_STATE_SHOP_TYPE_NPC_TOMOKI (1012), - OPEN_STATE_SHOP_TYPE_INAZUMA_SOUVENIR_BLACK_BAR (1013), - OPEN_ADVENTURE_MANUAL (1100), - OPEN_ADVENTURE_MANUAL_CITY_MENGDE (1101), - OPEN_ADVENTURE_MANUAL_CITY_LIYUE (1102), - OPEN_ADVENTURE_MANUAL_MONSTER (1103, 8), - OPEN_ADVENTURE_MANUAL_BOSS_DUNGEON (1104), - OPEN_STATE_ACTIVITY_SEALAMP (1200), - OPEN_STATE_ACTIVITY_SEALAMP_TAB2 (1201), - OPEN_STATE_ACTIVITY_SEALAMP_TAB3 (1202), - OPEN_STATE_BATTLE_PASS (1300, 1), - OPEN_STATE_BATTLE_PASS_ENTRY (1301, 20), - OPEN_STATE_ACTIVITY_CRUCIBLE (1400), - OPEN_STATE_ACTIVITY_NEWBEEBOUNS_OPEN (1401), - OPEN_STATE_ACTIVITY_NEWBEEBOUNS_CLOSE (1402), - OPEN_STATE_ACTIVITY_ENTRY_OPEN (1403), - OPEN_STATE_MENGDE_INFUSEDCRYSTAL (1404), - OPEN_STATE_LIYUE_INFUSEDCRYSTAL (1405), - OPEN_STATE_SNOW_MOUNTAIN_ELDER_TREE (1406), - OPEN_STATE_MIRACLE_RING (1407), - OPEN_STATE_COOP_LINE (1408, 26), - OPEN_STATE_INAZUMA_INFUSEDCRYSTAL (1409), - OPEN_STATE_FISH (1410), - OPEN_STATE_GUIDE_SUMO_TEAM_SKILL (1411), - OPEN_STATE_GUIDE_FISH_RECIPE (1412), - OPEN_STATE_HOME (1500), - OPEN_STATE_ACTIVITY_HOMEWORLD (1501, 28), - OPEN_STATE_ADEPTIABODE (1502), - OPEN_STATE_HOME_AVATAR (1503), - OPEN_STATE_HOME_EDIT (1504), - OPEN_STATE_HOME_EDIT_TIPS (1505), - OPEN_STATE_RELIQUARY_DECOMPOSE (1600, 45), - OPEN_STATE_ACTIVITY_H5 (1700, 10), - OPEN_STATE_ORAIONOKAMI (2000), - OPEN_STATE_GUIDE_CHESS_MISSION_CHECK (2001), - OPEN_STATE_GUIDE_CHESS_BUILD (2002), - OPEN_STATE_GUIDE_CHESS_WIND_TOWER_CIRCLE (2003), - OPEN_STATE_GUIDE_CHESS_CARD_SELECT (2004), - OPEN_STATE_INAZUMA_MAINQUEST_FINISHED (2005), - OPEN_STATE_PAIMON_LVINFO (2100, 7), - OPEN_STATE_TELEPORT_HUD (2101, 2), - OPEN_STATE_GUIDE_MAP_UNLOCK (2102), - OPEN_STATE_GUIDE_PAIMON_LVINFO (2103), - OPEN_STATE_GUIDE_AMBORTRANSPORT (2104), - OPEN_STATE_GUIDE_FLY_SECOND (2105), - OPEN_STATE_GUIDE_KAEYA_CLUE (2106), - OPEN_STATE_CAPTURE_CODEX (2107), - OPEN_STATE_ACTIVITY_FISH_OPEN (2200), - OPEN_STATE_ACTIVITY_FISH_CLOSE (2201), - OPEN_STATE_GUIDE_ROGUE_MAP (2205), - OPEN_STATE_GUIDE_ROGUE_RUNE (2206), - OPEN_STATE_GUIDE_BARTENDER_FORMULA (2210), - OPEN_STATE_GUIDE_BARTENDER_MIX (2211), - OPEN_STATE_GUIDE_BARTENDER_CUP (2212), - OPEN_STATE_GUIDE_MAIL_FAVORITES (2400), - OPEN_STATE_GUIDE_POTION_CONFIGURE (2401), - OPEN_STATE_GUIDE_LANV2_FIREWORK (2402), - OPEN_STATE_LOADINGTIPS_ENKANOMIYA (2403), - OPEN_STATE_MICHIAE_CASKET (2500, 30), - OPEN_STATE_MAIL_COLLECT_UNLOCK_RED_POINT (2501), - OPEN_STATE_LUMEN_STONE (2600), - OPEN_STATE_GUIDE_CRYSTALLINK_BUFF (2601), - OPEN_STATE_GUIDE_MUSIC_GAME_V3 (2700), - OPEN_STATE_GUIDE_MUSIC_GAME_V3_REAL_TIME_EDIT (2701), - OPEN_STATE_GUIDE_MUSIC_GAME_V3_TIMELINE_EDIT (2702), - OPEN_STATE_GUIDE_MUSIC_GAME_V3_SETTING (2703), - OPEN_STATE_GUIDE_ROBOTGACHA (2704), - OPEN_STATE_GUIDE_FRAGILE_RESIN (2800), - OPEN_ADVENTURE_MANUAL_EDUCATION (2801); - - private final int value; - private final int unlockLevel; - private static final Int2ObjectMap map = new Int2ObjectOpenHashMap<>(); - private static final Map stringMap = new HashMap<>(); - - static { - Stream.of(values()).forEach(e -> { - map.put(e.getValue(), e); - stringMap.put(e.name(), e); - }); - } - - private OpenState(int value) { - this.value = value; - this.unlockLevel = -1; - } - private OpenState(int value, int unlockLevel) { - this.value = value; - this.unlockLevel = unlockLevel; - } + OPEN_STATE_NONE (0), + OPEN_STATE_PAIMON (1), + OPEN_STATE_PAIMON_NAVIGATION (2), + OPEN_STATE_AVATAR_PROMOTE (3), + OPEN_STATE_AVATAR_TALENT (4), + OPEN_STATE_WEAPON_PROMOTE (5), + OPEN_STATE_WEAPON_AWAKEN (6), + OPEN_STATE_QUEST_REMIND (7), + OPEN_STATE_GAME_GUIDE (8), + OPEN_STATE_COOK (9), + OPEN_STATE_WEAPON_UPGRADE (10), + OPEN_STATE_RELIQUARY_UPGRADE (11), + OPEN_STATE_RELIQUARY_PROMOTE (12), + OPEN_STATE_WEAPON_PROMOTE_GUIDE (13), + OPEN_STATE_WEAPON_CHANGE_GUIDE (14), + OPEN_STATE_PLAYER_LVUP_GUIDE (15), + OPEN_STATE_FRESHMAN_GUIDE (16), + OPEN_STATE_SKIP_FRESHMAN_GUIDE (17), + OPEN_STATE_GUIDE_MOVE_CAMERA (18), + OPEN_STATE_GUIDE_SCALE_CAMERA (19), + OPEN_STATE_GUIDE_KEYBOARD (20), + OPEN_STATE_GUIDE_MOVE (21), + OPEN_STATE_GUIDE_JUMP (22), + OPEN_STATE_GUIDE_SPRINT (23), + OPEN_STATE_GUIDE_MAP (24), + OPEN_STATE_GUIDE_ATTACK (25), + OPEN_STATE_GUIDE_FLY (26), + OPEN_STATE_GUIDE_TALENT (27), + OPEN_STATE_GUIDE_RELIC (28), + OPEN_STATE_GUIDE_RELIC_PROM (29), + OPEN_STATE_COMBINE (30, 2), + OPEN_STATE_GACHA (31), + OPEN_STATE_GUIDE_GACHA (32), + OPEN_STATE_GUIDE_TEAM (33), + OPEN_STATE_GUIDE_PROUD (34), + OPEN_STATE_GUIDE_AVATAR_PROMOTE (35), + OPEN_STATE_GUIDE_ADVENTURE_CARD (36), + OPEN_STATE_FORGE (37, 2), + OPEN_STATE_GUIDE_BAG (38), + OPEN_STATE_EXPEDITION (39, 14), + OPEN_STATE_GUIDE_ADVENTURE_DAILYTASK (40), + OPEN_STATE_GUIDE_ADVENTURE_DUNGEON (41), + OPEN_STATE_TOWER (42), + OPEN_STATE_WORLD_STAMINA (43), + OPEN_STATE_TOWER_FIRST_ENTER (44), + OPEN_STATE_RESIN (45), + OPEN_STATE_LIMIT_REGION_FRESHMEAT (47), + OPEN_STATE_LIMIT_REGION_GLOBAL (48), + OPEN_STATE_MULTIPLAYER (49, 16), + OPEN_STATE_GUIDE_MOUSEPC (50), + OPEN_STATE_GUIDE_MULTIPLAYER (51), + OPEN_STATE_GUIDE_DUNGEONREWARD (52), + OPEN_STATE_GUIDE_BLOSSOM (53, 8), + OPEN_STATE_AVATAR_FASHION (54), + OPEN_STATE_PHOTOGRAPH (55), + OPEN_STATE_GUIDE_KSLQUEST (56), + OPEN_STATE_PERSONAL_LINE (57, 26), + OPEN_STATE_GUIDE_PERSONAL_LINE (58), + OPEN_STATE_GUIDE_APPEARANCE (59), + OPEN_STATE_GUIDE_PROCESS (60), + OPEN_STATE_GUIDE_PERSONAL_LINE_KEY (61), + OPEN_STATE_GUIDE_WIDGET (62), + OPEN_STATE_GUIDE_ACTIVITY_SKILL_ASTER (63), + OPEN_STATE_GUIDE_COLDCLIMATE (64), + OPEN_STATE_DERIVATIVE_MALL (65), + OPEN_STATE_GUIDE_EXITMULTIPLAYER (66), + OPEN_STATE_GUIDE_THEATREMACHANICUS_BUILD (67), + OPEN_STATE_GUIDE_THEATREMACHANICUS_REBUILD (68), + OPEN_STATE_GUIDE_THEATREMACHANICUS_CARD (69), + OPEN_STATE_GUIDE_THEATREMACHANICUS_MONSTER (70), + OPEN_STATE_GUIDE_THEATREMACHANICUS_MISSION_CHECK (71), + OPEN_STATE_GUIDE_THEATREMACHANICUS_BUILD_SELECT (72), + OPEN_STATE_GUIDE_THEATREMACHANICUS_CHALLENGE_START (73), + OPEN_STATE_GUIDE_CONVERT (74), + OPEN_STATE_GUIDE_THEATREMACHANICUS_MULTIPLAYER (75), + OPEN_STATE_GUIDE_COOP_TASK (76), + OPEN_STATE_GUIDE_HOMEWORLD_ADEPTIABODE (77), + OPEN_STATE_GUIDE_HOMEWORLD_DEPLOY (78), + OPEN_STATE_GUIDE_CHANNELLERSLAB_EQUIP (79), + OPEN_STATE_GUIDE_CHANNELLERSLAB_MP_SOLUTION (80), + OPEN_STATE_GUIDE_CHANNELLERSLAB_POWER (81), + OPEN_STATE_GUIDE_HIDEANDSEEK_SKILL (82), + OPEN_STATE_GUIDE_HOMEWORLD_MAPLIST (83), + OPEN_STATE_GUIDE_RELICRESOLVE (84), + OPEN_STATE_GUIDE_GGUIDE (85), + OPEN_STATE_GUIDE_GGUIDE_HINT (86), + OPEN_STATE_GUIDE_CHANNELLERSLAB_EQUIP_V2 (87), + OPEN_STATE_GUIDE_CHANNELLERSLAB_MP_SOLUTION_V2 (88), + OPEN_STATE_GUIDE_CHANNELLERSLAB_POWER_V2 (89), + OPEN_STATE_GUIDE_QUICK_TEAMMEMBERCHANGE (90), // Mobile only + OPEN_STATE_GGUIDE_FIRSTSHOW (91), + OPEN_STATE_GGUIDE_MAINPAGE_ENTRY_DISAPPEAR (92), + OPEN_STATE_CITY_REPUATION_MENGDE (800), + OPEN_STATE_CITY_REPUATION_LIYUE (801), + OPEN_STATE_CITY_REPUATION_UI_HINT (802, 25), + OPEN_STATE_CITY_REPUATION_INAZUMA (803), + OPEN_STATE_SHOP_TYPE_MALL (900), + OPEN_STATE_SHOP_TYPE_RECOMMANDED (901, 1), + OPEN_STATE_SHOP_TYPE_GENESISCRYSTAL (902, 1), + OPEN_STATE_SHOP_TYPE_GIFTPACKAGE (903, 1), + OPEN_STATE_SHOP_TYPE_PAIMON (1001), + OPEN_STATE_SHOP_TYPE_CITY (1002), + OPEN_STATE_SHOP_TYPE_BLACKSMITH (1003), + OPEN_STATE_SHOP_TYPE_GROCERY (1004, 5), + OPEN_STATE_SHOP_TYPE_FOOD (1005, 5), + OPEN_STATE_SHOP_TYPE_SEA_LAMP (1006, 13), + OPEN_STATE_SHOP_TYPE_VIRTUAL_SHOP (1007), + OPEN_STATE_SHOP_TYPE_LIYUE_GROCERY (1008, 5), + OPEN_STATE_SHOP_TYPE_LIYUE_SOUVENIR (1009), + OPEN_STATE_SHOP_TYPE_LIYUE_RESTAURANT (1010, 5), + OPEN_STATE_SHOP_TYPE_INAZUMA_SOUVENIR (1011), + OPEN_STATE_SHOP_TYPE_NPC_TOMOKI (1012), + OPEN_STATE_SHOP_TYPE_INAZUMA_SOUVENIR_BLACK_BAR (1013), + OPEN_ADVENTURE_MANUAL (1100), + OPEN_ADVENTURE_MANUAL_CITY_MENGDE (1101), + OPEN_ADVENTURE_MANUAL_CITY_LIYUE (1102), + OPEN_ADVENTURE_MANUAL_MONSTER (1103, 8), + OPEN_ADVENTURE_MANUAL_BOSS_DUNGEON (1104), + OPEN_STATE_ACTIVITY_SEALAMP (1200), + OPEN_STATE_ACTIVITY_SEALAMP_TAB2 (1201), + OPEN_STATE_ACTIVITY_SEALAMP_TAB3 (1202), + OPEN_STATE_BATTLE_PASS (1300, 1), + OPEN_STATE_BATTLE_PASS_ENTRY (1301, 20), + OPEN_STATE_ACTIVITY_CRUCIBLE (1400), + OPEN_STATE_ACTIVITY_NEWBEEBOUNS_OPEN (1401), + OPEN_STATE_ACTIVITY_NEWBEEBOUNS_CLOSE (1402), + OPEN_STATE_ACTIVITY_ENTRY_OPEN (1403), + OPEN_STATE_MENGDE_INFUSEDCRYSTAL (1404), + OPEN_STATE_LIYUE_INFUSEDCRYSTAL (1405), + OPEN_STATE_SNOW_MOUNTAIN_ELDER_TREE (1406), + OPEN_STATE_MIRACLE_RING (1407), + OPEN_STATE_COOP_LINE (1408, 26), + OPEN_STATE_INAZUMA_INFUSEDCRYSTAL (1409), + OPEN_STATE_FISH (1410), + OPEN_STATE_GUIDE_SUMO_TEAM_SKILL (1411), + OPEN_STATE_GUIDE_FISH_RECIPE (1412), + OPEN_STATE_HOME (1500), + OPEN_STATE_ACTIVITY_HOMEWORLD (1501, 28), + OPEN_STATE_ADEPTIABODE (1502), + OPEN_STATE_HOME_AVATAR (1503), + OPEN_STATE_HOME_EDIT (1504), + OPEN_STATE_HOME_EDIT_TIPS (1505), + OPEN_STATE_RELIQUARY_DECOMPOSE (1600, 45), + OPEN_STATE_ACTIVITY_H5 (1700, 10), + OPEN_STATE_ORAIONOKAMI (2000), + OPEN_STATE_GUIDE_CHESS_MISSION_CHECK (2001), + OPEN_STATE_GUIDE_CHESS_BUILD (2002), + OPEN_STATE_GUIDE_CHESS_WIND_TOWER_CIRCLE (2003), + OPEN_STATE_GUIDE_CHESS_CARD_SELECT (2004), + OPEN_STATE_INAZUMA_MAINQUEST_FINISHED (2005), + OPEN_STATE_PAIMON_LVINFO (2100, 7), + OPEN_STATE_TELEPORT_HUD (2101, 2), + OPEN_STATE_GUIDE_MAP_UNLOCK (2102), + OPEN_STATE_GUIDE_PAIMON_LVINFO (2103), + OPEN_STATE_GUIDE_AMBORTRANSPORT (2104), + OPEN_STATE_GUIDE_FLY_SECOND (2105), + OPEN_STATE_GUIDE_KAEYA_CLUE (2106), + OPEN_STATE_CAPTURE_CODEX (2107), + OPEN_STATE_ACTIVITY_FISH_OPEN (2200), + OPEN_STATE_ACTIVITY_FISH_CLOSE (2201), + OPEN_STATE_GUIDE_ROGUE_MAP (2205), + OPEN_STATE_GUIDE_ROGUE_RUNE (2206), + OPEN_STATE_GUIDE_BARTENDER_FORMULA (2210), + OPEN_STATE_GUIDE_BARTENDER_MIX (2211), + OPEN_STATE_GUIDE_BARTENDER_CUP (2212), + OPEN_STATE_GUIDE_MAIL_FAVORITES (2400), + OPEN_STATE_GUIDE_POTION_CONFIGURE (2401), + OPEN_STATE_GUIDE_LANV2_FIREWORK (2402), + OPEN_STATE_LOADINGTIPS_ENKANOMIYA (2403), + OPEN_STATE_MICHIAE_CASKET (2500, 30), + OPEN_STATE_MAIL_COLLECT_UNLOCK_RED_POINT (2501), + OPEN_STATE_LUMEN_STONE (2600), + OPEN_STATE_GUIDE_CRYSTALLINK_BUFF (2601), + OPEN_STATE_GUIDE_MUSIC_GAME_V3 (2700), + OPEN_STATE_GUIDE_MUSIC_GAME_V3_REAL_TIME_EDIT (2701), + OPEN_STATE_GUIDE_MUSIC_GAME_V3_TIMELINE_EDIT (2702), + OPEN_STATE_GUIDE_MUSIC_GAME_V3_SETTING (2703), + OPEN_STATE_GUIDE_ROBOTGACHA (2704), + OPEN_STATE_GUIDE_FRAGILE_RESIN (2800), + OPEN_ADVENTURE_MANUAL_EDUCATION (2801); - public int getValue() { - return value; - } + private final int value; + private final int unlockLevel; + private static final Int2ObjectMap map = new Int2ObjectOpenHashMap<>(); + private static final Map stringMap = new HashMap<>(); - public int getUnlockLevel() { - return this.unlockLevel; - } - - public static OpenState getTypeByValue(int value) { - return map.getOrDefault(value, OPEN_STATE_NONE); - } - - public static OpenState getTypeByName(String name) { - return stringMap.getOrDefault(name, OPEN_STATE_NONE); - } + static { + Stream.of(values()).forEach(e -> { + map.put(e.getValue(), e); + stringMap.put(e.name(), e); + }); + } + + private OpenState(int value) { + this.value = value; + this.unlockLevel = -1; + } + private OpenState(int value, int unlockLevel) { + this.value = value; + this.unlockLevel = unlockLevel; + } + + public int getValue() { + return value; + } + + public int getUnlockLevel() { + return this.unlockLevel; + } + + public static OpenState getTypeByValue(int value) { + return map.getOrDefault(value, OPEN_STATE_NONE); + } + + public static OpenState getTypeByName(String name) { + return stringMap.getOrDefault(name, OPEN_STATE_NONE); + } } diff --git a/src/main/java/emu/grasscutter/game/quest/GameQuest.java b/src/main/java/emu/grasscutter/game/quest/GameQuest.java index 87e31a6fb..7d76c152e 100644 --- a/src/main/java/emu/grasscutter/game/quest/GameQuest.java +++ b/src/main/java/emu/grasscutter/game/quest/GameQuest.java @@ -22,47 +22,47 @@ import emu.grasscutter.utils.Utils; @Entity public class GameQuest { - @Transient private GameMainQuest mainQuest; - @Transient private QuestData questData; + @Transient private GameMainQuest mainQuest; + @Transient private QuestData questData; - private int questId; - private int mainQuestId; - private QuestState state; + private int questId; + private int mainQuestId; + private QuestState state; - private int startTime; - private int acceptTime; - private int finishTime; + private int startTime; + private int acceptTime; + private int finishTime; - private int[] finishProgressList; - private int[] failProgressList; + private int[] finishProgressList; + private int[] failProgressList; - @Deprecated // Morphia only. Do not use. - public GameQuest() {} + @Deprecated // Morphia only. Do not use. + public GameQuest() {} - public GameQuest(GameMainQuest mainQuest, QuestData questData) { - this.mainQuest = mainQuest; - this.questId = questData.getId(); - this.mainQuestId = questData.getMainId(); - this.questData = questData; - this.acceptTime = Utils.getCurrentSeconds(); - this.startTime = this.acceptTime; - this.state = QuestState.QUEST_STATE_UNFINISHED; + public GameQuest(GameMainQuest mainQuest, QuestData questData) { + this.mainQuest = mainQuest; + this.questId = questData.getId(); + this.mainQuestId = questData.getMainId(); + this.questData = questData; + this.acceptTime = Utils.getCurrentSeconds(); + this.startTime = this.acceptTime; + this.state = QuestState.QUEST_STATE_UNFINISHED; - if (questData.getFinishCond() != null && questData.getAcceptCond().size() != 0) { - this.finishProgressList = new int[questData.getFinishCond().size()]; - } + if (questData.getFinishCond() != null && questData.getAcceptCond().size() != 0) { + this.finishProgressList = new int[questData.getFinishCond().size()]; + } - if (questData.getFailCond() != null && questData.getFailCond().size() != 0) { - this.failProgressList = new int[questData.getFailCond().size()]; - } + if (questData.getFailCond() != null && questData.getFailCond().size() != 0) { + this.failProgressList = new int[questData.getFailCond().size()]; + } - this.mainQuest.getChildQuests().put(this.questId, this); + this.mainQuest.getChildQuests().put(this.questId, this); this.getData().getBeginExec().forEach(e -> getOwner().getServer().getQuestSystem().triggerExec(this, e, e.getParam())); this.getOwner().getQuestManager().triggerEvent(QuestTrigger.QUEST_CONTENT_QUEST_STATE_EQUAL, this.questId, this.state.getValue()); - if (ChapterData.beginQuestChapterMap.containsKey(questId)){ + if (ChapterData.beginQuestChapterMap.containsKey(questId)) { mainQuest.getOwner().sendPacket(new PacketChapterStateNotify( ChapterData.beginQuestChapterMap.get(questId).getId(), ChapterStateOuterClass.ChapterState.CHAPTER_STATE_BEGIN @@ -70,112 +70,112 @@ public class GameQuest { } Grasscutter.getLogger().debug("Quest {} is started", questId); - } + } - public GameMainQuest getMainQuest() { - return mainQuest; - } + public GameMainQuest getMainQuest() { + return mainQuest; + } - public void setMainQuest(GameMainQuest mainQuest) { - this.mainQuest = mainQuest; - } + public void setMainQuest(GameMainQuest mainQuest) { + this.mainQuest = mainQuest; + } - public Player getOwner() { - return getMainQuest().getOwner(); - } + public Player getOwner() { + return getMainQuest().getOwner(); + } - public int getQuestId() { - return questId; - } + public int getQuestId() { + return questId; + } - public int getMainQuestId() { - return mainQuestId; - } + public int getMainQuestId() { + return mainQuestId; + } - public QuestData getData() { - return questData; - } + public QuestData getData() { + return questData; + } - public void setConfig(QuestData config) { - if (this.getQuestId() != config.getId()) return; - this.questData = config; - } + public void setConfig(QuestData config) { + if (this.getQuestId() != config.getId()) return; + this.questData = config; + } - public QuestState getState() { - return state; - } + public QuestState getState() { + return state; + } - public void setState(QuestState state) { - this.state = state; - } + public void setState(QuestState state) { + this.state = state; + } - public int getStartTime() { - return startTime; - } + public int getStartTime() { + return startTime; + } - public void setStartTime(int startTime) { - this.startTime = startTime; - } + public void setStartTime(int startTime) { + this.startTime = startTime; + } - public int getAcceptTime() { - return acceptTime; - } + public int getAcceptTime() { + return acceptTime; + } - public void setAcceptTime(int acceptTime) { - this.acceptTime = acceptTime; - } + public void setAcceptTime(int acceptTime) { + this.acceptTime = acceptTime; + } - public int getFinishTime() { - return finishTime; - } + public int getFinishTime() { + return finishTime; + } - public void setFinishTime(int finishTime) { - this.finishTime = finishTime; - } + public void setFinishTime(int finishTime) { + this.finishTime = finishTime; + } - public int[] getFinishProgressList() { - return finishProgressList; - } + public int[] getFinishProgressList() { + return finishProgressList; + } - public void setFinishProgress(int index, int value) { - finishProgressList[index] = value; - } + public void setFinishProgress(int index, int value) { + finishProgressList[index] = value; + } - public int[] getFailProgressList() { - return failProgressList; - } + public int[] getFailProgressList() { + return failProgressList; + } - public void setFailProgress(int index, int value) { - failProgressList[index] = value; - } + public void setFailProgress(int index, int value) { + failProgressList[index] = value; + } - public void finish() { - this.state = QuestState.QUEST_STATE_FINISHED; - this.finishTime = Utils.getCurrentSeconds(); + public void finish() { + this.state = QuestState.QUEST_STATE_FINISHED; + this.finishTime = Utils.getCurrentSeconds(); - if (this.getFinishProgressList() != null) { - for (int i = 0 ; i < getFinishProgressList().length; i++) { - getFinishProgressList()[i] = 1; - } - } + if (this.getFinishProgressList() != null) { + for (int i = 0 ; i < getFinishProgressList().length; i++) { + getFinishProgressList()[i] = 1; + } + } - this.getOwner().getSession().send(new PacketQuestProgressUpdateNotify(this)); - this.getOwner().getSession().send(new PacketQuestListUpdateNotify(this)); + this.getOwner().getSession().send(new PacketQuestProgressUpdateNotify(this)); + this.getOwner().getSession().send(new PacketQuestListUpdateNotify(this)); - if (this.getData().finishParent()) { - // This quest finishes the questline - the main quest will also save the quest to db so we dont have to call save() here - this.getMainQuest().finish(); - } else { - // Try and accept other quests if possible - this.tryAcceptQuestLine(); - this.save(); - } + if (this.getData().finishParent()) { + // This quest finishes the questline - the main quest will also save the quest to db so we dont have to call save() here + this.getMainQuest().finish(); + } else { + // Try and accept other quests if possible + this.tryAcceptQuestLine(); + this.save(); + } this.getData().getFinishExec().forEach(e -> getOwner().getServer().getQuestSystem().triggerExec(this, e, e.getParam())); this.getOwner().getQuestManager().triggerEvent(QuestTrigger.QUEST_CONTENT_QUEST_STATE_EQUAL, this.questId, this.state.getValue()); - if (ChapterData.endQuestChapterMap.containsKey(questId)){ + if (ChapterData.endQuestChapterMap.containsKey(questId)) { mainQuest.getOwner().sendPacket(new PacketChapterStateNotify( ChapterData.endQuestChapterMap.get(questId).getId(), ChapterStateOuterClass.ChapterState.CHAPTER_STATE_END @@ -183,74 +183,74 @@ public class GameQuest { } Grasscutter.getLogger().debug("Quest {} is finished", questId); - } + } - public boolean tryAcceptQuestLine() { - try { - MainQuestData questConfig = GameData.getMainQuestDataMap().get(this.getMainQuestId()); + public boolean tryAcceptQuestLine() { + try { + MainQuestData questConfig = GameData.getMainQuestDataMap().get(this.getMainQuestId()); - for (SubQuestData subQuest : questConfig.getSubQuests()) { - GameQuest quest = getMainQuest().getChildQuestById(subQuest.getSubId()); + for (SubQuestData subQuest : questConfig.getSubQuests()) { + GameQuest quest = getMainQuest().getChildQuestById(subQuest.getSubId()); - if (quest == null) { - QuestData questData = GameData.getQuestDataMap().get(subQuest.getSubId()); + if (quest == null) { + QuestData questData = GameData.getQuestDataMap().get(subQuest.getSubId()); - if (questData == null || questData.getAcceptCond() == null - || questData.getAcceptCond().size() == 0) { - continue; - } + if (questData == null || questData.getAcceptCond() == null + || questData.getAcceptCond().size() == 0) { + continue; + } - int[] accept = new int[questData.getAcceptCond().size()]; + int[] accept = new int[questData.getAcceptCond().size()]; - // TODO - for (int i = 0; i < questData.getAcceptCond().size(); i++) { - QuestCondition condition = questData.getAcceptCond().get(i); - boolean result = getOwner().getServer().getQuestSystem().triggerCondition(this, condition, + // TODO + for (int i = 0; i < questData.getAcceptCond().size(); i++) { + QuestCondition condition = questData.getAcceptCond().get(i); + boolean result = getOwner().getServer().getQuestSystem().triggerCondition(this, condition, condition.getParamStr(), - condition.getParam()); + condition.getParam()); - accept[i] = result ? 1 : 0; - } + accept[i] = result ? 1 : 0; + } - boolean shouldAccept = LogicType.calculate(questData.getAcceptCondComb(), accept); + boolean shouldAccept = LogicType.calculate(questData.getAcceptCondComb(), accept); - if (shouldAccept) { - this.getOwner().getQuestManager().addQuest(questData.getId()); - } - } - } - } catch (Exception e) { - Grasscutter.getLogger().error("An error occurred while trying to accept quest.", e); - } + if (shouldAccept) { + this.getOwner().getQuestManager().addQuest(questData.getId()); + } + } + } + } catch (Exception e) { + Grasscutter.getLogger().error("An error occurred while trying to accept quest.", e); + } - return false; - } + return false; + } - public void save() { - getMainQuest().save(); - } + public void save() { + getMainQuest().save(); + } - public Quest toProto() { - Quest.Builder proto = Quest.newBuilder() - .setQuestId(this.getQuestId()) - .setState(this.getState().getValue()) - .setParentQuestId(this.getMainQuestId()) - .setStartTime(this.getStartTime()) - .setStartGameTime(438) - .setAcceptTime(this.getAcceptTime()); + public Quest toProto() { + Quest.Builder proto = Quest.newBuilder() + .setQuestId(this.getQuestId()) + .setState(this.getState().getValue()) + .setParentQuestId(this.getMainQuestId()) + .setStartTime(this.getStartTime()) + .setStartGameTime(438) + .setAcceptTime(this.getAcceptTime()); - if (this.getFinishProgressList() != null) { - for (int i : this.getFinishProgressList()) { - proto.addFinishProgressList(i); - } - } + if (this.getFinishProgressList() != null) { + for (int i : this.getFinishProgressList()) { + proto.addFinishProgressList(i); + } + } - if (this.getFailProgressList() != null) { - for (int i : this.getFailProgressList()) { - proto.addFailProgressList(i); - } - } + if (this.getFailProgressList() != null) { + for (int i : this.getFailProgressList()) { + proto.addFailProgressList(i); + } + } - return proto.build(); - } + return proto.build(); + } } diff --git a/src/main/java/emu/grasscutter/game/quest/QuestManager.java b/src/main/java/emu/grasscutter/game/quest/QuestManager.java index 28a17973f..c8049f362 100644 --- a/src/main/java/emu/grasscutter/game/quest/QuestManager.java +++ b/src/main/java/emu/grasscutter/game/quest/QuestManager.java @@ -21,106 +21,106 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; public class QuestManager extends BasePlayerManager { - private final Int2ObjectMap quests; + private final Int2ObjectMap quests; - public QuestManager(Player player) { - super(player); - this.quests = new Int2ObjectOpenHashMap<>(); - } + public QuestManager(Player player) { + super(player); + this.quests = new Int2ObjectOpenHashMap<>(); + } - public Int2ObjectMap getQuests() { - return quests; - } - - public GameMainQuest getMainQuestById(int mainQuestId) { - return getQuests().get(mainQuestId); - } - - public GameQuest getQuestById(int questId) { - QuestData questConfig = GameData.getQuestDataMap().get(questId); - if (questConfig == null) { - return null; - } - - GameMainQuest mainQuest = getQuests().get(questConfig.getMainId()); - - if (mainQuest == null) { - return null; - } - - return mainQuest.getChildQuests().get(questId); - } - - public void forEachQuest(Consumer callback) { - for (GameMainQuest mainQuest : getQuests().values()) { - for (GameQuest quest : mainQuest.getChildQuests().values()) { - callback.accept(quest); - } - } - } + public Int2ObjectMap getQuests() { + return quests; + } - public void forEachMainQuest(Consumer callback) { - for (GameMainQuest mainQuest : getQuests().values()) { - callback.accept(mainQuest); - } - } - - // TODO - public void forEachActiveQuest(Consumer callback) { - for (GameMainQuest mainQuest : getQuests().values()) { - for (GameQuest quest : mainQuest.getChildQuests().values()) { - if (quest.getState() != QuestState.QUEST_STATE_FINISHED) { - callback.accept(quest); - } - } - } - } - - public GameMainQuest addMainQuest(QuestData questConfig) { - GameMainQuest mainQuest = new GameMainQuest(getPlayer(), questConfig.getMainId()); - getQuests().put(mainQuest.getParentQuestId(), mainQuest); + public GameMainQuest getMainQuestById(int mainQuestId) { + return getQuests().get(mainQuestId); + } - getPlayer().sendPacket(new PacketFinishedParentQuestUpdateNotify(mainQuest)); - - return mainQuest; - } - - public GameQuest addQuest(int questId) { - QuestData questConfig = GameData.getQuestDataMap().get(questId); - if (questConfig == null) { - return null; - } - - // Main quest - GameMainQuest mainQuest = this.getMainQuestById(questConfig.getMainId()); - - // Create main quest if it doesnt exist - if (mainQuest == null) { - mainQuest = addMainQuest(questConfig); - } - - // Sub quest - GameQuest quest = mainQuest.getChildQuestById(questId); - - if (quest != null) { - return null; - } + public GameQuest getQuestById(int questId) { + QuestData questConfig = GameData.getQuestDataMap().get(questId); + if (questConfig == null) { + return null; + } - // Create - quest = new GameQuest(mainQuest, questConfig); + GameMainQuest mainQuest = getQuests().get(questConfig.getMainId()); - // Save main quest - mainQuest.save(); + if (mainQuest == null) { + return null; + } - // Send packet - getPlayer().sendPacket(new PacketQuestListUpdateNotify(quest)); + return mainQuest.getChildQuests().get(questId); + } - return quest; - } - public void startMainQuest(int mainQuestId){ + public void forEachQuest(Consumer callback) { + for (GameMainQuest mainQuest : getQuests().values()) { + for (GameQuest quest : mainQuest.getChildQuests().values()) { + callback.accept(quest); + } + } + } + + public void forEachMainQuest(Consumer callback) { + for (GameMainQuest mainQuest : getQuests().values()) { + callback.accept(mainQuest); + } + } + + // TODO + public void forEachActiveQuest(Consumer callback) { + for (GameMainQuest mainQuest : getQuests().values()) { + for (GameQuest quest : mainQuest.getChildQuests().values()) { + if (quest.getState() != QuestState.QUEST_STATE_FINISHED) { + callback.accept(quest); + } + } + } + } + + public GameMainQuest addMainQuest(QuestData questConfig) { + GameMainQuest mainQuest = new GameMainQuest(getPlayer(), questConfig.getMainId()); + getQuests().put(mainQuest.getParentQuestId(), mainQuest); + + getPlayer().sendPacket(new PacketFinishedParentQuestUpdateNotify(mainQuest)); + + return mainQuest; + } + + public GameQuest addQuest(int questId) { + QuestData questConfig = GameData.getQuestDataMap().get(questId); + if (questConfig == null) { + return null; + } + + // Main quest + GameMainQuest mainQuest = this.getMainQuestById(questConfig.getMainId()); + + // Create main quest if it doesnt exist + if (mainQuest == null) { + mainQuest = addMainQuest(questConfig); + } + + // Sub quest + GameQuest quest = mainQuest.getChildQuestById(questId); + + if (quest != null) { + return null; + } + + // Create + quest = new GameQuest(mainQuest, questConfig); + + // Save main quest + mainQuest.save(); + + // Send packet + getPlayer().sendPacket(new PacketQuestListUpdateNotify(quest)); + + return quest; + } + public void startMainQuest(int mainQuestId) { var mainQuestData = GameData.getMainQuestDataMap().get(mainQuestId); - if (mainQuestData == null){ + if (mainQuestData == null) { return; } @@ -133,52 +133,52 @@ public class QuestManager extends BasePlayerManager { triggerEvent(condType, "", params); } - public void triggerEvent(QuestTrigger condType, String paramStr, int... params) { + public void triggerEvent(QuestTrigger condType, String paramStr, int... params) { Grasscutter.getLogger().debug("Trigger Event {}, {}, {}", condType, paramStr, params); - Set changedQuests = new HashSet<>(); + Set changedQuests = new HashSet<>(); - this.forEachActiveQuest(quest -> { - QuestData data = quest.getData(); + this.forEachActiveQuest(quest -> { + QuestData data = quest.getData(); - for (int i = 0; i < data.getFinishCond().size(); i++) { - if (quest.getFinishProgressList() == null - || quest.getFinishProgressList().length == 0 - || quest.getFinishProgressList()[i] == 1) { - continue; - } + for (int i = 0; i < data.getFinishCond().size(); i++) { + if (quest.getFinishProgressList() == null + || quest.getFinishProgressList().length == 0 + || quest.getFinishProgressList()[i] == 1) { + continue; + } - QuestCondition condition = data.getFinishCond().get(i); + QuestCondition condition = data.getFinishCond().get(i); - if (condition.getType() != condType) { - continue; - } + if (condition.getType() != condType) { + continue; + } - boolean result = getPlayer().getServer().getQuestSystem().triggerContent(quest, condition, paramStr, params); + boolean result = getPlayer().getServer().getQuestSystem().triggerContent(quest, condition, paramStr, params); - if (result) { - quest.getFinishProgressList()[i] = 1; + if (result) { + quest.getFinishProgressList()[i] = 1; - changedQuests.add(quest); - } - } - }); + changedQuests.add(quest); + } + } + }); - for (GameQuest quest : changedQuests) { - LogicType logicType = quest.getData().getFailCondComb(); - int[] progress = quest.getFinishProgressList(); + for (GameQuest quest : changedQuests) { + LogicType logicType = quest.getData().getFailCondComb(); + int[] progress = quest.getFinishProgressList(); - // Handle logical comb - boolean finish = LogicType.calculate(logicType, progress); + // Handle logical comb + boolean finish = LogicType.calculate(logicType, progress); - // Finish - if (finish) { - quest.finish(); - } else { - getPlayer().sendPacket(new PacketQuestProgressUpdateNotify(quest)); - quest.save(); - } - } - } + // Finish + if (finish) { + quest.finish(); + } else { + getPlayer().sendPacket(new PacketQuestProgressUpdateNotify(quest)); + quest.save(); + } + } + } public List getSceneGroupSuite(int sceneId) { return getQuests().values().stream() @@ -189,18 +189,18 @@ public class QuestManager extends BasePlayerManager { .filter(i -> i.getScene() == sceneId) .toList(); } - public void loadFromDatabase() { - List quests = DatabaseHelper.getAllQuests(getPlayer()); - - for (GameMainQuest mainQuest : quests) { - mainQuest.setOwner(this.getPlayer()); - - for (GameQuest quest : mainQuest.getChildQuests().values()) { - quest.setMainQuest(mainQuest); - quest.setConfig(GameData.getQuestDataMap().get(quest.getQuestId())); - } - - this.getQuests().put(mainQuest.getParentQuestId(), mainQuest); - } - } + public void loadFromDatabase() { + List quests = DatabaseHelper.getAllQuests(getPlayer()); + + for (GameMainQuest mainQuest : quests) { + mainQuest.setOwner(this.getPlayer()); + + for (GameQuest quest : mainQuest.getChildQuests().values()) { + quest.setMainQuest(mainQuest); + quest.setConfig(GameData.getQuestDataMap().get(quest.getQuestId())); + } + + this.getQuests().put(mainQuest.getParentQuestId(), mainQuest); + } + } } diff --git a/src/main/java/emu/grasscutter/game/quest/QuestSystem.java b/src/main/java/emu/grasscutter/game/quest/QuestSystem.java index 24f78b9d4..16167b010 100644 --- a/src/main/java/emu/grasscutter/game/quest/QuestSystem.java +++ b/src/main/java/emu/grasscutter/game/quest/QuestSystem.java @@ -17,81 +17,81 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; @SuppressWarnings("unchecked") public class QuestSystem extends BaseGameSystem { - private final Int2ObjectMap condHandlers; - private final Int2ObjectMap contHandlers; - private final Int2ObjectMap execHandlers; + private final Int2ObjectMap condHandlers; + private final Int2ObjectMap contHandlers; + private final Int2ObjectMap execHandlers; - public QuestSystem(GameServer server) { - super(server); - - this.condHandlers = new Int2ObjectOpenHashMap<>(); - this.contHandlers = new Int2ObjectOpenHashMap<>(); - this.execHandlers = new Int2ObjectOpenHashMap<>(); + public QuestSystem(GameServer server) { + super(server); - this.registerHandlers(); - } + this.condHandlers = new Int2ObjectOpenHashMap<>(); + this.contHandlers = new Int2ObjectOpenHashMap<>(); + this.execHandlers = new Int2ObjectOpenHashMap<>(); - public void registerHandlers() { - this.registerHandlers(this.condHandlers, "emu.grasscutter.game.quest.conditions", QuestBaseHandler.class); - this.registerHandlers(this.contHandlers, "emu.grasscutter.game.quest.content", QuestBaseHandler.class); - this.registerHandlers(this.execHandlers, "emu.grasscutter.game.quest.exec", QuestExecHandler.class); - } + this.registerHandlers(); + } - public void registerHandlers(Int2ObjectMap map, String packageName, Class clazz) { - Reflections reflections = new Reflections(packageName); - var handlerClasses = reflections.getSubTypesOf(clazz); + public void registerHandlers() { + this.registerHandlers(this.condHandlers, "emu.grasscutter.game.quest.conditions", QuestBaseHandler.class); + this.registerHandlers(this.contHandlers, "emu.grasscutter.game.quest.content", QuestBaseHandler.class); + this.registerHandlers(this.execHandlers, "emu.grasscutter.game.quest.exec", QuestExecHandler.class); + } - for (var obj : handlerClasses) { - this.registerPacketHandler(map, obj); - } - } + public void registerHandlers(Int2ObjectMap map, String packageName, Class clazz) { + Reflections reflections = new Reflections(packageName); + var handlerClasses = reflections.getSubTypesOf(clazz); - public void registerPacketHandler(Int2ObjectMap map, Class handlerClass) { - try { - QuestValue opcode = handlerClass.getAnnotation(QuestValue.class); + for (var obj : handlerClasses) { + this.registerPacketHandler(map, obj); + } + } - if (opcode == null || opcode.value().getValue() <= 0) { - return; - } + public void registerPacketHandler(Int2ObjectMap map, Class handlerClass) { + try { + QuestValue opcode = handlerClass.getAnnotation(QuestValue.class); - map.put(opcode.value().getValue(), handlerClass.newInstance()); - } catch (Exception e) { - e.printStackTrace(); - } - } + if (opcode == null || opcode.value().getValue() <= 0) { + return; + } - // TODO make cleaner + map.put(opcode.value().getValue(), handlerClass.newInstance()); + } catch (Exception e) { + e.printStackTrace(); + } + } - public boolean triggerCondition(GameQuest quest, QuestCondition condition, String paramStr, int... params) { - QuestBaseHandler handler = condHandlers.get(condition.getType().getValue()); + // TODO make cleaner - if (handler == null || quest.getData() == null) { + public boolean triggerCondition(GameQuest quest, QuestCondition condition, String paramStr, int... params) { + QuestBaseHandler handler = condHandlers.get(condition.getType().getValue()); + + if (handler == null || quest.getData() == null) { Grasscutter.getLogger().debug("Could not trigger condition {} at {}", condition.getType().getValue(), quest.getData()); - return false; - } + return false; + } - return handler.execute(quest, condition, paramStr, params); - } + return handler.execute(quest, condition, paramStr, params); + } - public boolean triggerContent(GameQuest quest, QuestCondition condition, String paramStr, int... params) { - QuestBaseHandler handler = contHandlers.get(condition.getType().getValue()); + public boolean triggerContent(GameQuest quest, QuestCondition condition, String paramStr, int... params) { + QuestBaseHandler handler = contHandlers.get(condition.getType().getValue()); - if (handler == null || quest.getData() == null) { + if (handler == null || quest.getData() == null) { Grasscutter.getLogger().debug("Could not trigger content {} at {}", condition.getType().getValue(), quest.getData()); - return false; - } + return false; + } - return handler.execute(quest, condition, paramStr, params); - } + return handler.execute(quest, condition, paramStr, params); + } - public boolean triggerExec(GameQuest quest, QuestExecParam execParam, String... params) { - QuestExecHandler handler = execHandlers.get(execParam.getType().getValue()); + public boolean triggerExec(GameQuest quest, QuestExecParam execParam, String... params) { + QuestExecHandler handler = execHandlers.get(execParam.getType().getValue()); - if (handler == null || quest.getData() == null) { + if (handler == null || quest.getData() == null) { Grasscutter.getLogger().debug("Could not trigger exec {} at {}", execParam.getType().getValue(), quest.getData()); - return false; - } + return false; + } - return handler.execute(quest, execParam, params); - } + return handler.execute(quest, execParam, params); + } } diff --git a/src/main/java/emu/grasscutter/game/shop/ShopSystem.java b/src/main/java/emu/grasscutter/game/shop/ShopSystem.java index 8ad4fa657..006af71d2 100644 --- a/src/main/java/emu/grasscutter/game/shop/ShopSystem.java +++ b/src/main/java/emu/grasscutter/game/shop/ShopSystem.java @@ -23,22 +23,22 @@ import java.util.Iterator; import java.util.List; public class ShopSystem extends BaseGameSystem { - private final Int2ObjectMap> shopData; - private final List shopChestData; - private final List shopChestBatchUseData; - + private final Int2ObjectMap> shopData; + private final List shopChestData; + private final List shopChestBatchUseData; + private static final int REFRESH_HOUR = 4; // In GMT+8 server private static final String TIME_ZONE = "Asia/Shanghai"; // GMT+8 Timezone - public ShopSystem(GameServer server) { - super(server); - this.shopData = new Int2ObjectOpenHashMap<>(); - this.shopChestData = new ArrayList<>(); - this.shopChestBatchUseData = new ArrayList<>(); - this.load(); - } - - public Int2ObjectMap> getShopData() { + public ShopSystem(GameServer server) { + super(server); + this.shopData = new Int2ObjectOpenHashMap<>(); + this.shopChestData = new ArrayList<>(); + this.shopChestBatchUseData = new ArrayList<>(); + this.load(); + } + + public Int2ObjectMap> getShopData() { return shopData; } @@ -50,96 +50,96 @@ public class ShopSystem extends BaseGameSystem { return shopChestBatchUseData; } - public static int getShopNextRefreshTime(ShopInfo shopInfo) { - return switch (shopInfo.getShopRefreshType()) { - case SHOP_REFRESH_DAILY -> Utils.getNextTimestampOfThisHour(REFRESH_HOUR, TIME_ZONE, shopInfo.getShopRefreshParam()); - case SHOP_REFRESH_WEEKLY -> Utils.getNextTimestampOfThisHourInNextWeek(REFRESH_HOUR, TIME_ZONE, shopInfo.getShopRefreshParam()); - case SHOP_REFRESH_MONTHLY -> Utils.getNextTimestampOfThisHourInNextMonth(REFRESH_HOUR, TIME_ZONE, shopInfo.getShopRefreshParam()); - default -> 0; - }; - } + public static int getShopNextRefreshTime(ShopInfo shopInfo) { + return switch (shopInfo.getShopRefreshType()) { + case SHOP_REFRESH_DAILY -> Utils.getNextTimestampOfThisHour(REFRESH_HOUR, TIME_ZONE, shopInfo.getShopRefreshParam()); + case SHOP_REFRESH_WEEKLY -> Utils.getNextTimestampOfThisHourInNextWeek(REFRESH_HOUR, TIME_ZONE, shopInfo.getShopRefreshParam()); + case SHOP_REFRESH_MONTHLY -> Utils.getNextTimestampOfThisHourInNextMonth(REFRESH_HOUR, TIME_ZONE, shopInfo.getShopRefreshParam()); + default -> 0; + }; + } - private void loadShop() { - try (Reader fileReader = DataLoader.loadReader("Shop.json")) { - getShopData().clear(); - List banners = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, ShopTable.class).getType()); - if(banners.size() > 0) { - for (ShopTable shopTable : banners) { - for (ShopInfo cost : shopTable.getItems()) { - if (cost.getCostItemList() != null) { - Iterator iterator = cost.getCostItemList().iterator(); - while (iterator.hasNext()) { - ItemParamData ipd = iterator.next(); - if (ipd.getId() == 201) { - cost.setHcoin(cost.getHcoin() + ipd.getCount()); - iterator.remove(); - } - if (ipd.getId() == 203) { - cost.setMcoin(cost.getMcoin() + ipd.getCount()); - iterator.remove(); - } - } - } - } - getShopData().put(shopTable.getShopId(), shopTable.getItems()); - } - Grasscutter.getLogger().debug("Shop data successfully loaded."); - } else { - Grasscutter.getLogger().error("Unable to load shop data. Shop data size is 0."); - } + private void loadShop() { + try (Reader fileReader = DataLoader.loadReader("Shop.json")) { + getShopData().clear(); + List banners = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, ShopTable.class).getType()); + if (banners.size() > 0) { + for (ShopTable shopTable : banners) { + for (ShopInfo cost : shopTable.getItems()) { + if (cost.getCostItemList() != null) { + Iterator iterator = cost.getCostItemList().iterator(); + while (iterator.hasNext()) { + ItemParamData ipd = iterator.next(); + if (ipd.getId() == 201) { + cost.setHcoin(cost.getHcoin() + ipd.getCount()); + iterator.remove(); + } + if (ipd.getId() == 203) { + cost.setMcoin(cost.getMcoin() + ipd.getCount()); + iterator.remove(); + } + } + } + } + getShopData().put(shopTable.getShopId(), shopTable.getItems()); + } + Grasscutter.getLogger().debug("Shop data successfully loaded."); + } else { + Grasscutter.getLogger().error("Unable to load shop data. Shop data size is 0."); + } - if (GAME_OPTIONS.enableShopItems) { - GameData.getShopGoodsDataEntries().forEach((k, v) -> { - if (!getShopData().containsKey(k.intValue())) - getShopData().put(k.intValue(), new ArrayList<>()); - for (ShopGoodsData sgd : v) { - var shopInfo = new ShopInfo(sgd); - getShopData().get(k.intValue()).add(shopInfo); - } - }); - } - } catch (Exception e) { - Grasscutter.getLogger().error("Unable to load shop data.", e); - } - } + if (GAME_OPTIONS.enableShopItems) { + GameData.getShopGoodsDataEntries().forEach((k, v) -> { + if (!getShopData().containsKey(k.intValue())) + getShopData().put(k.intValue(), new ArrayList<>()); + for (ShopGoodsData sgd : v) { + var shopInfo = new ShopInfo(sgd); + getShopData().get(k.intValue()).add(shopInfo); + } + }); + } + } catch (Exception e) { + Grasscutter.getLogger().error("Unable to load shop data.", e); + } + } - private void loadShopChest() { - try (Reader fileReader = DataLoader.loadReader("ShopChest.json")) { - getShopChestData().clear(); - List shopChestTableList = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, ShopChestTable.class).getType()); - if (shopChestTableList.size() > 0) { - getShopChestData().addAll(shopChestTableList); - Grasscutter.getLogger().debug("ShopChest data successfully loaded."); - } else { - Grasscutter.getLogger().error("Unable to load ShopChest data. ShopChest data size is 0."); - } - } catch (Exception e) { - Grasscutter.getLogger().error("Unable to load ShopChest data.", e); - } - } + private void loadShopChest() { + try (Reader fileReader = DataLoader.loadReader("ShopChest.json")) { + getShopChestData().clear(); + List shopChestTableList = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, ShopChestTable.class).getType()); + if (shopChestTableList.size() > 0) { + getShopChestData().addAll(shopChestTableList); + Grasscutter.getLogger().debug("ShopChest data successfully loaded."); + } else { + Grasscutter.getLogger().error("Unable to load ShopChest data. ShopChest data size is 0."); + } + } catch (Exception e) { + Grasscutter.getLogger().error("Unable to load ShopChest data.", e); + } + } - private void loadShopChestBatchUse() { - try (Reader fileReader = DataLoader.loadReader("ShopChestBatchUse.json")) { - getShopChestBatchUseData().clear(); - List shopChestBatchUseTableList = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, ShopChestBatchUseTable.class).getType()); - if (shopChestBatchUseTableList.size() > 0) { - getShopChestBatchUseData().addAll(shopChestBatchUseTableList); - Grasscutter.getLogger().debug("ShopChestBatchUse data successfully loaded."); - } else { - Grasscutter.getLogger().error("Unable to load ShopChestBatchUse data. ShopChestBatchUse data size is 0."); - } - } catch (Exception e) { - Grasscutter.getLogger().error("Unable to load ShopChestBatchUse data.", e); - } - } + private void loadShopChestBatchUse() { + try (Reader fileReader = DataLoader.loadReader("ShopChestBatchUse.json")) { + getShopChestBatchUseData().clear(); + List shopChestBatchUseTableList = Grasscutter.getGsonFactory().fromJson(fileReader, TypeToken.getParameterized(Collection.class, ShopChestBatchUseTable.class).getType()); + if (shopChestBatchUseTableList.size() > 0) { + getShopChestBatchUseData().addAll(shopChestBatchUseTableList); + Grasscutter.getLogger().debug("ShopChestBatchUse data successfully loaded."); + } else { + Grasscutter.getLogger().error("Unable to load ShopChestBatchUse data. ShopChestBatchUse data size is 0."); + } + } catch (Exception e) { + Grasscutter.getLogger().error("Unable to load ShopChestBatchUse data.", e); + } + } - public synchronized void load() { - loadShop(); - loadShopChest(); - loadShopChestBatchUse(); - } + public synchronized void load() { + loadShop(); + loadShopChest(); + loadShopChestBatchUse(); + } - public GameServer getServer() { - return server; - } + public GameServer getServer() { + return server; + } } diff --git a/src/main/java/emu/grasscutter/game/systems/AnnouncementSystem.java b/src/main/java/emu/grasscutter/game/systems/AnnouncementSystem.java index 5d2161b94..510a3f61a 100644 --- a/src/main/java/emu/grasscutter/game/systems/AnnouncementSystem.java +++ b/src/main/java/emu/grasscutter/game/systems/AnnouncementSystem.java @@ -22,8 +22,8 @@ import java.util.*; @Getter public class AnnouncementSystem extends BaseGameSystem { private final Map announceConfigItemMap; - - public AnnouncementSystem(GameServer server){ + + public AnnouncementSystem(GameServer server) { super(server); this.announceConfigItemMap = new HashMap<>(); loadConfig(); @@ -51,7 +51,7 @@ public class AnnouncementSystem extends BaseGameSystem { } public void broadcast(List tpl) { - if(tpl == null || tpl.size() == 0){ + if (tpl == null || tpl.size() == 0) { return; } @@ -83,7 +83,7 @@ public class AnnouncementSystem extends BaseGameSystem { boolean tick; int interval; - public AnnounceDataOuterClass.AnnounceData.Builder toProto(){ + public AnnounceDataOuterClass.AnnounceData.Builder toProto() { var proto = AnnounceDataOuterClass.AnnounceData.newBuilder(); proto.setConfigId(templateId) @@ -91,11 +91,11 @@ public class AnnouncementSystem extends BaseGameSystem { .setBeginTime(Utils.getCurrentSeconds() + 1) .setEndTime(Utils.getCurrentSeconds() + 10); - if(type == AnnounceType.CENTER){ + if (type == AnnounceType.CENTER) { proto.setCenterSystemText(content) .setCenterSystemFrequency(frequency) ; - }else{ + }else { proto.setCountDownText(content) .setCountDownFrequency(frequency) ; diff --git a/src/main/java/emu/grasscutter/game/systems/InventorySystem.java b/src/main/java/emu/grasscutter/game/systems/InventorySystem.java index 37b988ff8..2f7a0614b 100644 --- a/src/main/java/emu/grasscutter/game/systems/InventorySystem.java +++ b/src/main/java/emu/grasscutter/game/systems/InventorySystem.java @@ -35,922 +35,922 @@ import it.unimi.dsi.fastutil.ints.Int2IntMap; import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; public class InventorySystem extends BaseGameSystem { - private final static int RELIC_MATERIAL_1 = 105002; // Sanctifying Unction - private final static int RELIC_MATERIAL_2 = 105003; // Sanctifying Essence - private final static int RELIC_MATERIAL_EXP_1 = 2500; // Sanctifying Unction - private final static int RELIC_MATERIAL_EXP_2 = 10000; // Sanctifying Essence - - private final static int WEAPON_ORE_1 = 104011; // Enhancement Ore - private final static int WEAPON_ORE_2 = 104012; // Fine Enhancement Ore - private final static int WEAPON_ORE_3 = 104013; // Mystic Enhancement Ore - private final static int WEAPON_ORE_EXP_1 = 400; // Enhancement Ore - private final static int WEAPON_ORE_EXP_2 = 2000; // Fine Enhancement Ore - private final static int WEAPON_ORE_EXP_3 = 10000; // Mystic Enhancement Ore - - private final static int AVATAR_BOOK_1 = 104001; // Wanderer's Advice - private final static int AVATAR_BOOK_2 = 104002; // Adventurer's Experience - private final static int AVATAR_BOOK_3 = 104003; // Hero's Wit - private final static int AVATAR_BOOK_EXP_1 = 1000; // Wanderer's Advice - private final static int AVATAR_BOOK_EXP_2 = 5000; // Adventurer's Experience - private final static int AVATAR_BOOK_EXP_3 = 20000; // Hero's Wit - - public InventorySystem(GameServer server) { - super(server); - } - - public void lockEquip(Player player, long targetEquipGuid, boolean isLocked) { - GameItem equip = player.getInventory().getItemByGuid(targetEquipGuid); - - if (equip == null || !equip.getItemData().isEquip()) { - return; - } - - equip.setLocked(isLocked); - equip.save(); - - player.sendPacket(new PacketStoreItemChangeNotify(equip)); - player.sendPacket(new PacketSetEquipLockStateRsp(equip)); - } + private final static int RELIC_MATERIAL_1 = 105002; // Sanctifying Unction + private final static int RELIC_MATERIAL_2 = 105003; // Sanctifying Essence + private final static int RELIC_MATERIAL_EXP_1 = 2500; // Sanctifying Unction + private final static int RELIC_MATERIAL_EXP_2 = 10000; // Sanctifying Essence - public void upgradeRelic(Player player, long targetGuid, List foodRelicList, List list) { - GameItem relic = player.getInventory().getItemByGuid(targetGuid); - - if (relic == null || relic.getItemType() != ItemType.ITEM_RELIQUARY) { - return; - } - - int moraCost = 0; - int expGain = 0; - - List foodRelics = new ArrayList(); - for (long guid : foodRelicList) { - // Add to delete queue - GameItem food = player.getInventory().getItemByGuid(guid); - if (food == null || !food.isDestroyable()) { - continue; - } - // Calculate mora cost - moraCost += food.getItemData().getBaseConvExp(); - expGain += food.getItemData().getBaseConvExp(); - // Feeding artifact with exp already - if (food.getTotalExp() > 0) { - expGain += (food.getTotalExp() * 4) / 5; - } - foodRelics.add(food); - } - List payList = new ArrayList(); - for (ItemParam itemParam : list) { - int amount = itemParam.getCount(); // Previously this capped to inventory amount, but rejecting the payment makes more sense for an invalid order - int gain = amount * switch(itemParam.getItemId()) { - case RELIC_MATERIAL_1 -> RELIC_MATERIAL_EXP_1; - case RELIC_MATERIAL_2 -> RELIC_MATERIAL_EXP_2; - default -> 0; - }; - expGain += gain; - moraCost += gain; - payList.add(new ItemParamData(itemParam.getItemId(), itemParam.getCount())); - } - - // Make sure exp gain is valid - if (expGain <= 0) { - return; - } - - // Confirm payment of materials and mora (assume food relics are payable afterwards) - payList.add(new ItemParamData(202, moraCost)); - if (!player.getInventory().payItems(payList.toArray(new ItemParamData[0]))) { - return; - } - - // Consume food relics - player.getInventory().removeItems(foodRelics); - - // Implement random rate boost - int rate = 1; - int boost = Utils.randomRange(1, 100); - if (boost == 100) { - rate = 5; - } else if (boost <= 9) { - rate = 2; - } - expGain *= rate; - - // Now we upgrade - int level = relic.getLevel(); - int oldLevel = level; - int exp = relic.getExp(); - int totalExp = relic.getTotalExp(); - int reqExp = GameData.getRelicExpRequired(relic.getItemData().getRankLevel(), level); - int upgrades = 0; + private final static int WEAPON_ORE_1 = 104011; // Enhancement Ore + private final static int WEAPON_ORE_2 = 104012; // Fine Enhancement Ore + private final static int WEAPON_ORE_3 = 104013; // Mystic Enhancement Ore + private final static int WEAPON_ORE_EXP_1 = 400; // Enhancement Ore + private final static int WEAPON_ORE_EXP_2 = 2000; // Fine Enhancement Ore + private final static int WEAPON_ORE_EXP_3 = 10000; // Mystic Enhancement Ore + + private final static int AVATAR_BOOK_1 = 104001; // Wanderer's Advice + private final static int AVATAR_BOOK_2 = 104002; // Adventurer's Experience + private final static int AVATAR_BOOK_3 = 104003; // Hero's Wit + private final static int AVATAR_BOOK_EXP_1 = 1000; // Wanderer's Advice + private final static int AVATAR_BOOK_EXP_2 = 5000; // Adventurer's Experience + private final static int AVATAR_BOOK_EXP_3 = 20000; // Hero's Wit + + public InventorySystem(GameServer server) { + super(server); + } + + public void lockEquip(Player player, long targetEquipGuid, boolean isLocked) { + GameItem equip = player.getInventory().getItemByGuid(targetEquipGuid); + + if (equip == null || !equip.getItemData().isEquip()) { + return; + } + + equip.setLocked(isLocked); + equip.save(); + + player.sendPacket(new PacketStoreItemChangeNotify(equip)); + player.sendPacket(new PacketSetEquipLockStateRsp(equip)); + } + + public void upgradeRelic(Player player, long targetGuid, List foodRelicList, List list) { + GameItem relic = player.getInventory().getItemByGuid(targetGuid); + + if (relic == null || relic.getItemType() != ItemType.ITEM_RELIQUARY) { + return; + } + + int moraCost = 0; + int expGain = 0; + + List foodRelics = new ArrayList(); + for (long guid : foodRelicList) { + // Add to delete queue + GameItem food = player.getInventory().getItemByGuid(guid); + if (food == null || !food.isDestroyable()) { + continue; + } + // Calculate mora cost + moraCost += food.getItemData().getBaseConvExp(); + expGain += food.getItemData().getBaseConvExp(); + // Feeding artifact with exp already + if (food.getTotalExp() > 0) { + expGain += (food.getTotalExp() * 4) / 5; + } + foodRelics.add(food); + } + List payList = new ArrayList(); + for (ItemParam itemParam : list) { + int amount = itemParam.getCount(); // Previously this capped to inventory amount, but rejecting the payment makes more sense for an invalid order + int gain = amount * switch (itemParam.getItemId()) { + case RELIC_MATERIAL_1 -> RELIC_MATERIAL_EXP_1; + case RELIC_MATERIAL_2 -> RELIC_MATERIAL_EXP_2; + default -> 0; + }; + expGain += gain; + moraCost += gain; + payList.add(new ItemParamData(itemParam.getItemId(), itemParam.getCount())); + } + + // Make sure exp gain is valid + if (expGain <= 0) { + return; + } + + // Confirm payment of materials and mora (assume food relics are payable afterwards) + payList.add(new ItemParamData(202, moraCost)); + if (!player.getInventory().payItems(payList.toArray(new ItemParamData[0]))) { + return; + } + + // Consume food relics + player.getInventory().removeItems(foodRelics); + + // Implement random rate boost + int rate = 1; + int boost = Utils.randomRange(1, 100); + if (boost == 100) { + rate = 5; + } else if (boost <= 9) { + rate = 2; + } + expGain *= rate; + + // Now we upgrade + int level = relic.getLevel(); + int oldLevel = level; + int exp = relic.getExp(); + int totalExp = relic.getTotalExp(); + int reqExp = GameData.getRelicExpRequired(relic.getItemData().getRankLevel(), level); + int upgrades = 0; List oldAppendPropIdList = new ArrayList<>(relic.getAppendPropIdList()); - - while (expGain > 0 && reqExp > 0 && level < relic.getItemData().getMaxLevel()) { - // Do calculations - int toGain = Math.min(expGain, reqExp - exp); - exp += toGain; - totalExp += toGain; - expGain -= toGain; - // Level up - if (exp >= reqExp) { - // Exp - exp = 0; - level += 1; - // On relic levelup - if (relic.getItemData().getAddPropLevelSet() != null && relic.getItemData().getAddPropLevelSet().contains(level)) { - upgrades += 1; - } - // Set req exp - reqExp = GameData.getRelicExpRequired(relic.getItemData().getRankLevel(), level); - } - } - + + while (expGain > 0 && reqExp > 0 && level < relic.getItemData().getMaxLevel()) { + // Do calculations + int toGain = Math.min(expGain, reqExp - exp); + exp += toGain; + totalExp += toGain; + expGain -= toGain; + // Level up + if (exp >= reqExp) { + // Exp + exp = 0; + level += 1; + // On relic levelup + if (relic.getItemData().getAddPropLevelSet() != null && relic.getItemData().getAddPropLevelSet().contains(level)) { + upgrades += 1; + } + // Set req exp + reqExp = GameData.getRelicExpRequired(relic.getItemData().getRankLevel(), level); + } + } + relic.addAppendProps(upgrades); - - // Save - relic.setLevel(level); - relic.setExp(exp); - relic.setTotalExp(totalExp); - relic.save(); - - // Avatar - if (oldLevel != level) { - Avatar avatar = relic.getEquipCharacter() > 0 ? player.getAvatars().getAvatarById(relic.getEquipCharacter()) : null; - if (avatar != null) { - avatar.recalcStats(); - } - } - // Packet - player.sendPacket(new PacketStoreItemChangeNotify(relic)); - player.sendPacket(new PacketReliquaryUpgradeRsp(relic, rate, oldLevel, oldAppendPropIdList)); - } + // Save + relic.setLevel(level); + relic.setExp(exp); + relic.setTotalExp(totalExp); + relic.save(); - public List calcWeaponUpgradeReturnItems(Player player, long targetGuid, List foodWeaponGuidList, List itemParamList) { - GameItem weapon = player.getInventory().getItemByGuid(targetGuid); - - // Sanity checks - if (weapon == null || weapon.getItemType() != ItemType.ITEM_WEAPON) { - return null; - } - - WeaponPromoteData promoteData = GameData.getWeaponPromoteData(weapon.getItemData().getWeaponPromoteId(), weapon.getPromoteLevel()); - if (promoteData == null) { - return null; - } - - // Get exp gain - int expGain = 0; - for (long guid : foodWeaponGuidList) { - GameItem food = player.getInventory().getItemByGuid(guid); - if (food == null) { - continue; - } - expGain += food.getItemData().getWeaponBaseExp(); - if (food.getTotalExp() > 0) { - expGain += (food.getTotalExp() * 4) / 5; - } - } - for (ItemParam param : itemParamList) { - expGain += param.getCount() * switch(param.getItemId()) { - case WEAPON_ORE_1 -> WEAPON_ORE_EXP_1; - case WEAPON_ORE_2 -> WEAPON_ORE_EXP_2; - case WEAPON_ORE_3 -> WEAPON_ORE_EXP_3; - default -> 0; - }; - } - - // Try - int maxLevel = promoteData.getUnlockMaxLevel(); - int level = weapon.getLevel(); - int exp = weapon.getExp(); - int reqExp = GameData.getWeaponExpRequired(weapon.getItemData().getRankLevel(), level); - - while (expGain > 0 && reqExp > 0 && level < maxLevel) { - // Do calculations - int toGain = Math.min(expGain, reqExp - exp); - exp += toGain; - expGain -= toGain; - // Level up - if (exp >= reqExp) { - // Exp - exp = 0; - level += 1; - // Set req exp - reqExp = GameData.getWeaponExpRequired(weapon.getItemData().getRankLevel(), level); - } - } - - return getLeftoverOres(expGain); - } - + // Avatar + if (oldLevel != level) { + Avatar avatar = relic.getEquipCharacter() > 0 ? player.getAvatars().getAvatarById(relic.getEquipCharacter()) : null; + if (avatar != null) { + avatar.recalcStats(); + } + } - public void upgradeWeapon(Player player, long targetGuid, List foodWeaponGuidList, List itemParamList) { - GameItem weapon = player.getInventory().getItemByGuid(targetGuid); - - // Sanity checks - if (weapon == null || weapon.getItemType() != ItemType.ITEM_WEAPON) { - return; - } - - WeaponPromoteData promoteData = GameData.getWeaponPromoteData(weapon.getItemData().getWeaponPromoteId(), weapon.getPromoteLevel()); - if (promoteData == null) { - return; - } - - // Get exp gain - int expGain = 0, expGainFree = 0; - List foodWeapons = new ArrayList(); - for (long guid : foodWeaponGuidList) { - GameItem food = player.getInventory().getItemByGuid(guid); - if (food == null || !food.isDestroyable()) { - continue; - } - expGain += food.getItemData().getWeaponBaseExp(); - if (food.getTotalExp() > 0) { - expGainFree += (food.getTotalExp() * 4) / 5; // No tax :D - } - foodWeapons.add(food); - } - List payList = new ArrayList(); - for (ItemParam param : itemParamList) { - int amount = param.getCount(); // Previously this capped to inventory amount, but rejecting the payment makes more sense for an invalid order - int gain = amount * switch(param.getItemId()) { - case WEAPON_ORE_1 -> WEAPON_ORE_EXP_1; - case WEAPON_ORE_2 -> WEAPON_ORE_EXP_2; - case WEAPON_ORE_3 -> WEAPON_ORE_EXP_3; - default -> 0; - }; - expGain += gain; - payList.add(new ItemParamData(param.getItemId(), amount)); - } - - // Make sure exp gain is valid - int moraCost = expGain / 10; - expGain += expGainFree; - if (expGain <= 0) { - return; - } + // Packet + player.sendPacket(new PacketStoreItemChangeNotify(relic)); + player.sendPacket(new PacketReliquaryUpgradeRsp(relic, rate, oldLevel, oldAppendPropIdList)); + } - // Confirm payment of materials and mora (assume food weapons are payable afterwards) - payList.add(new ItemParamData(202, moraCost)); - if (!player.getInventory().payItems(payList.toArray(new ItemParamData[0]))) { - return; - } - player.getInventory().removeItems(foodWeapons); - - // Level up - int maxLevel = promoteData.getUnlockMaxLevel(); - int level = weapon.getLevel(); - int oldLevel = level; - int exp = weapon.getExp(); - int totalExp = weapon.getTotalExp(); - int reqExp = GameData.getWeaponExpRequired(weapon.getItemData().getRankLevel(), level); - - while (expGain > 0 && reqExp > 0 && level < maxLevel) { - // Do calculations - int toGain = Math.min(expGain, reqExp - exp); - exp += toGain; - totalExp += toGain; - expGain -= toGain; - // Level up - if (exp >= reqExp) { - // Exp - exp = 0; - level += 1; - // Set req exp - reqExp = GameData.getWeaponExpRequired(weapon.getItemData().getRankLevel(), level); - } - } - - List leftovers = getLeftoverOres(expGain); - player.getInventory().addItemParams(leftovers); - - weapon.setLevel(level); - weapon.setExp(exp); - weapon.setTotalExp(totalExp); - weapon.save(); - - // Avatar - if (oldLevel != level) { - Avatar avatar = weapon.getEquipCharacter() > 0 ? player.getAvatars().getAvatarById(weapon.getEquipCharacter()) : null; - if (avatar != null) { - avatar.recalcStats(); - } - } - - // Packets - player.sendPacket(new PacketStoreItemChangeNotify(weapon)); - player.sendPacket(new PacketWeaponUpgradeRsp(weapon, oldLevel, leftovers)); - } - - private List getLeftoverOres(int leftover) { - List leftoverOreList = new ArrayList<>(3); - - if (leftover < WEAPON_ORE_EXP_1) { - return leftoverOreList; - } - - // Get leftovers - int ore3 = leftover / WEAPON_ORE_EXP_3; - leftover = leftover % WEAPON_ORE_EXP_3; - int ore2 = leftover / WEAPON_ORE_EXP_2; - leftover = leftover % WEAPON_ORE_EXP_2; - int ore1 = leftover / WEAPON_ORE_EXP_1; - - if (ore3 > 0) { - leftoverOreList.add(ItemParam.newBuilder().setItemId(WEAPON_ORE_3).setCount(ore3).build()); - } if (ore2 > 0) { - leftoverOreList.add(ItemParam.newBuilder().setItemId(WEAPON_ORE_2).setCount(ore2).build()); - } if (ore1 > 0) { - leftoverOreList.add(ItemParam.newBuilder().setItemId(WEAPON_ORE_1).setCount(ore1).build()); - } - - return leftoverOreList; - } + public List calcWeaponUpgradeReturnItems(Player player, long targetGuid, List foodWeaponGuidList, List itemParamList) { + GameItem weapon = player.getInventory().getItemByGuid(targetGuid); - public void refineWeapon(Player player, long targetGuid, long feedGuid) { - GameItem weapon = player.getInventory().getItemByGuid(targetGuid); - GameItem feed = player.getInventory().getItemByGuid(feedGuid); - - // Sanity checks - if (weapon == null || feed == null || !feed.isDestroyable()) { - return; - } - - if (weapon.getItemData().getAwakenMaterial() == 0) { - if (weapon.getItemType() != ItemType.ITEM_WEAPON || weapon.getItemId() != feed.getItemId()) { - return; - } - } else { - if (weapon.getItemType() != ItemType.ITEM_WEAPON || weapon.getItemData().getAwakenMaterial() != feed.getItemId()) { - return; - } - } - - if (weapon.getRefinement() >= 4 || weapon.getAffixes() == null || weapon.getAffixes().size() == 0) { - return; - } - - // Calculate - int oldRefineLevel = weapon.getRefinement(); - int targetRefineLevel = Math.min(oldRefineLevel + feed.getRefinement() + 1, 4); - int moraCost = 0; - - try { - moraCost = weapon.getItemData().getAwakenCosts()[weapon.getRefinement()]; - } catch (Exception e) { - return; - } - - // Mora check - if (player.getMora() >= moraCost) { - player.setMora(player.getMora() - moraCost); - } else { - return; - } - - // Consume weapon - player.getInventory().removeItem(feed, 1); - - // Get - weapon.setRefinement(targetRefineLevel); - weapon.save(); - - // Avatar - Avatar avatar = weapon.getEquipCharacter() > 0 ? player.getAvatars().getAvatarById(weapon.getEquipCharacter()) : null; - if (avatar != null) { - avatar.recalcStats(); - } - - // Packets - player.sendPacket(new PacketStoreItemChangeNotify(weapon)); - player.sendPacket(new PacketWeaponAwakenRsp(avatar, weapon, feed, oldRefineLevel)); - } + // Sanity checks + if (weapon == null || weapon.getItemType() != ItemType.ITEM_WEAPON) { + return null; + } - public void promoteWeapon(Player player, long targetGuid) { - GameItem weapon = player.getInventory().getItemByGuid(targetGuid); - - if (weapon == null || weapon.getItemType() != ItemType.ITEM_WEAPON) { - return; - } - - int nextPromoteLevel = weapon.getPromoteLevel() + 1; - WeaponPromoteData currentPromoteData = GameData.getWeaponPromoteData(weapon.getItemData().getWeaponPromoteId(), weapon.getPromoteLevel()); - WeaponPromoteData nextPromoteData = GameData.getWeaponPromoteData(weapon.getItemData().getWeaponPromoteId(), nextPromoteLevel); - if (currentPromoteData == null || nextPromoteData == null) { - return; - } - - // Level check - if (weapon.getLevel() != currentPromoteData.getUnlockMaxLevel()) { - return; - } - - // Pay materials and mora if possible - ItemParamData[] costs = nextPromoteData.getCostItems(); // Can this be null? - if (nextPromoteData.getCoinCost() > 0) { - costs = Arrays.copyOf(costs, costs.length + 1); - costs[costs.length-1] = new ItemParamData(202, nextPromoteData.getCoinCost()); - } - if (!player.getInventory().payItems(costs)) { - return; - } - - int oldPromoteLevel = weapon.getPromoteLevel(); - weapon.setPromoteLevel(nextPromoteLevel); - weapon.save(); - - // Avatar - Avatar avatar = weapon.getEquipCharacter() > 0 ? player.getAvatars().getAvatarById(weapon.getEquipCharacter()) : null; - if (avatar != null) { - avatar.recalcStats(); - } - - // Packets - player.sendPacket(new PacketStoreItemChangeNotify(weapon)); - player.sendPacket(new PacketWeaponPromoteRsp(weapon, oldPromoteLevel)); - } + WeaponPromoteData promoteData = GameData.getWeaponPromoteData(weapon.getItemData().getWeaponPromoteId(), weapon.getPromoteLevel()); + if (promoteData == null) { + return null; + } - public void promoteAvatar(Player player, long guid) { - Avatar avatar = player.getAvatars().getAvatarByGuid(guid); - - // Sanity checks - if (avatar == null) { - return; - } - - int nextPromoteLevel = avatar.getPromoteLevel() + 1; - AvatarPromoteData currentPromoteData = GameData.getAvatarPromoteData(avatar.getAvatarData().getAvatarPromoteId(), avatar.getPromoteLevel()); - AvatarPromoteData nextPromoteData = GameData.getAvatarPromoteData(avatar.getAvatarData().getAvatarPromoteId(), nextPromoteLevel); - if (currentPromoteData == null || nextPromoteData == null) { - return; - } - - // Level check - if (avatar.getLevel() != currentPromoteData.getUnlockMaxLevel()) { - return; - } - - // Pay materials and mora if possible - ItemParamData[] costs = nextPromoteData.getCostItems(); // Can this be null? - if (nextPromoteData.getCoinCost() > 0) { - costs = Arrays.copyOf(costs, costs.length + 1); - costs[costs.length-1] = new ItemParamData(202, nextPromoteData.getCoinCost()); - } - if (!player.getInventory().payItems(costs)) { - return; - } - - // Update promote level - avatar.setPromoteLevel(nextPromoteLevel); - - // Update proud skills - AvatarSkillDepotData skillDepot = GameData.getAvatarSkillDepotDataMap().get(avatar.getSkillDepotId()); - - if (skillDepot != null && skillDepot.getInherentProudSkillOpens() != null) { - for (InherentProudSkillOpens openData : skillDepot.getInherentProudSkillOpens()) { - if (openData.getProudSkillGroupId() == 0) { - continue; - } - if (openData.getNeedAvatarPromoteLevel() == avatar.getPromoteLevel()) { - int proudSkillId = (openData.getProudSkillGroupId() * 100) + 1; - if (GameData.getProudSkillDataMap().containsKey(proudSkillId)) { - avatar.getProudSkillList().add(proudSkillId); - player.sendPacket(new PacketProudSkillChangeNotify(avatar)); - } - } - } - } - - // Packets - player.sendPacket(new PacketAvatarPropNotify(avatar)); - player.sendPacket(new PacketAvatarPromoteRsp(avatar)); - - // TODO Send entity prop update packet to world - avatar.recalcStats(true); - avatar.save(); - } + // Get exp gain + int expGain = 0; + for (long guid : foodWeaponGuidList) { + GameItem food = player.getInventory().getItemByGuid(guid); + if (food == null) { + continue; + } + expGain += food.getItemData().getWeaponBaseExp(); + if (food.getTotalExp() > 0) { + expGain += (food.getTotalExp() * 4) / 5; + } + } + for (ItemParam param : itemParamList) { + expGain += param.getCount() * switch (param.getItemId()) { + case WEAPON_ORE_1 -> WEAPON_ORE_EXP_1; + case WEAPON_ORE_2 -> WEAPON_ORE_EXP_2; + case WEAPON_ORE_3 -> WEAPON_ORE_EXP_3; + default -> 0; + }; + } - public void upgradeAvatar(Player player, long guid, int itemId, int count) { - Avatar avatar = player.getAvatars().getAvatarByGuid(guid); - - // Sanity checks - if (avatar == null) { - return; - } - - AvatarPromoteData promoteData = GameData.getAvatarPromoteData(avatar.getAvatarData().getAvatarPromoteId(), avatar.getPromoteLevel()); - if (promoteData == null) { - return; - } - - // Calc exp - int expGain = switch(itemId) { - case AVATAR_BOOK_1 -> AVATAR_BOOK_EXP_1 * count; - case AVATAR_BOOK_2 -> AVATAR_BOOK_EXP_2 * count; - case AVATAR_BOOK_3 -> AVATAR_BOOK_EXP_3 * count; - default -> 0; - }; - - // Sanity check - if (expGain <= 0) { - return; - } + // Try + int maxLevel = promoteData.getUnlockMaxLevel(); + int level = weapon.getLevel(); + int exp = weapon.getExp(); + int reqExp = GameData.getWeaponExpRequired(weapon.getItemData().getRankLevel(), level); - // Payment check - int moraCost = expGain / 5; - ItemParamData[] costItems = new ItemParamData[] {new ItemParamData(itemId, count), new ItemParamData(202, moraCost)}; - if (!player.getInventory().payItems(costItems)) { - return; - } - - // Level up - upgradeAvatar(player, avatar, promoteData, expGain); - } + while (expGain > 0 && reqExp > 0 && level < maxLevel) { + // Do calculations + int toGain = Math.min(expGain, reqExp - exp); + exp += toGain; + expGain -= toGain; + // Level up + if (exp >= reqExp) { + // Exp + exp = 0; + level += 1; + // Set req exp + reqExp = GameData.getWeaponExpRequired(weapon.getItemData().getRankLevel(), level); + } + } - public void upgradeAvatar(Player player, Avatar avatar, int expGain) { - AvatarPromoteData promoteData = GameData.getAvatarPromoteData(avatar.getAvatarData().getAvatarPromoteId(), avatar.getPromoteLevel()); - if (promoteData == null) { - return; - } - - upgradeAvatar(player, avatar, promoteData, expGain); - } + return getLeftoverOres(expGain); + } - public void upgradeAvatar(Player player, Avatar avatar, AvatarPromoteData promoteData, int expGain) { - int maxLevel = promoteData.getUnlockMaxLevel(); - int level = avatar.getLevel(); - int oldLevel = level; - int exp = avatar.getExp(); - int reqExp = GameData.getAvatarLevelExpRequired(level); - while (expGain > 0 && reqExp > 0 && level < maxLevel) { - // Do calculations - int toGain = Math.min(expGain, reqExp - exp); - exp += toGain; - expGain -= toGain; - // Level up - if (exp >= reqExp) { - // Exp - exp = 0; - level += 1; - // Set req exp - reqExp = GameData.getAvatarLevelExpRequired(level); - } - } + public void upgradeWeapon(Player player, long targetGuid, List foodWeaponGuidList, List itemParamList) { + GameItem weapon = player.getInventory().getItemByGuid(targetGuid); - // Old map for packet - Map oldPropMap = avatar.getFightProperties(); - if (oldLevel != level) { - // Deep copy if level has changed - oldPropMap = avatar.getFightProperties().int2FloatEntrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); - } - - // Done - avatar.setLevel(level); - avatar.setExp(exp); - avatar.recalcStats(); - avatar.save(); - - // TODO Send entity prop update packet to world - - // Packets - player.sendPacket(new PacketAvatarPropNotify(avatar)); - player.sendPacket(new PacketAvatarUpgradeRsp(avatar, oldLevel, oldPropMap)); - } + // Sanity checks + if (weapon == null || weapon.getItemType() != ItemType.ITEM_WEAPON) { + return; + } - public void upgradeAvatarFetterLevel(Player player, Avatar avatar, int expGain) { - // May work. Not test. - int maxLevel = 10; // Keep it until I think of a more "elegant" way - int level = avatar.getFetterLevel(); - int exp = avatar.getFetterExp(); - int reqExp = GameData.getAvatarFetterLevelExpRequired(level); + WeaponPromoteData promoteData = GameData.getWeaponPromoteData(weapon.getItemData().getWeaponPromoteId(), weapon.getPromoteLevel()); + if (promoteData == null) { + return; + } - while (expGain > 0 && reqExp > 0 && level < maxLevel) { - int toGain = Math.min(expGain, reqExp - exp); - exp += toGain; - expGain -= toGain; - if (exp >= reqExp) { - exp = 0; - level += 1; - reqExp = GameData.getAvatarFetterLevelExpRequired(level); - } - } - - avatar.setFetterLevel(level); - avatar.setFetterExp(exp); - avatar.save(); - - player.sendPacket(new PacketAvatarPropNotify(avatar)); - player.sendPacket(new PacketAvatarFetterDataNotify(avatar)); - } + // Get exp gain + int expGain = 0, expGainFree = 0; + List foodWeapons = new ArrayList(); + for (long guid : foodWeaponGuidList) { + GameItem food = player.getInventory().getItemByGuid(guid); + if (food == null || !food.isDestroyable()) { + continue; + } + expGain += food.getItemData().getWeaponBaseExp(); + if (food.getTotalExp() > 0) { + expGainFree += (food.getTotalExp() * 4) / 5; // No tax :D + } + foodWeapons.add(food); + } + List payList = new ArrayList(); + for (ItemParam param : itemParamList) { + int amount = param.getCount(); // Previously this capped to inventory amount, but rejecting the payment makes more sense for an invalid order + int gain = amount * switch (param.getItemId()) { + case WEAPON_ORE_1 -> WEAPON_ORE_EXP_1; + case WEAPON_ORE_2 -> WEAPON_ORE_EXP_2; + case WEAPON_ORE_3 -> WEAPON_ORE_EXP_3; + default -> 0; + }; + expGain += gain; + payList.add(new ItemParamData(param.getItemId(), amount)); + } - public void upgradeAvatarSkill(Player player, long guid, int skillId) { - // Sanity checks - Avatar avatar = player.getAvatars().getAvatarByGuid(guid); - if (avatar == null) { - return; - } - - // Make sure avatar has skill - if (!avatar.getSkillLevelMap().containsKey(skillId)) { - return; - } - - AvatarSkillData skillData = GameData.getAvatarSkillDataMap().get(skillId); - if (skillData == null) { - return; - } - - // Get data for next skill level - int currentLevel = avatar.getSkillLevelMap().get(skillId); - int nextLevel = currentLevel + 1; - int proudSkillId = (skillData.getProudSkillGroupId() * 100) + nextLevel; - - // Capped at level 10 talent - if (nextLevel > 10) { - return; - } - - // Proud skill data - ProudSkillData proudSkill = GameData.getProudSkillDataMap().get(proudSkillId); - if (proudSkill == null) { - return; - } - - // Make sure break level is correct - if (avatar.getPromoteLevel() < proudSkill.getBreakLevel()) { - return; - } - - // Pay materials and mora if possible - List costs = new ArrayList(proudSkill.getCostItems()); // Can this be null? - if (proudSkill.getCoinCost() > 0) { - costs.add(new ItemParamData(202, proudSkill.getCoinCost())); - } - if (!player.getInventory().payItems(costs.toArray(new ItemParamData[0]))) { - return; - } - - // Upgrade skill - avatar.getSkillLevelMap().put(skillId, nextLevel); - avatar.save(); - - // Packet - player.sendPacket(new PacketAvatarSkillChangeNotify(avatar, skillId, currentLevel, nextLevel)); - player.sendPacket(new PacketAvatarSkillUpgradeRsp(avatar, skillId, currentLevel, nextLevel)); - } + // Make sure exp gain is valid + int moraCost = expGain / 10; + expGain += expGainFree; + if (expGain <= 0) { + return; + } - public void unlockAvatarConstellation(Player player, long guid) { - // Sanity checks - Avatar avatar = player.getAvatars().getAvatarByGuid(guid); - if (avatar == null) { - return; - } - - // Get talent - int currentTalentLevel = avatar.getCoreProudSkillLevel(); - int nextTalentId = ((avatar.getAvatarId() % 10000000) * 10) + currentTalentLevel + 1; - - if (avatar.getAvatarId() == 10000006) { - // Lisa is special in that her talentId starts with 4 instead of 6. - nextTalentId = 40 + currentTalentLevel + 1; - } - - AvatarTalentData talentData = GameData.getAvatarTalentDataMap().get(nextTalentId); - - if (talentData == null) { - return; - } - - // Pay constellation item if possible - if (!player.getInventory().payItem(talentData.getMainCostItemId(), 1)) { - return; - } - - // Apply + recalc - avatar.getTalentIdList().add(talentData.getId()); - avatar.setCoreProudSkillLevel(currentTalentLevel + 1); + // Confirm payment of materials and mora (assume food weapons are payable afterwards) + payList.add(new ItemParamData(202, moraCost)); + if (!player.getInventory().payItems(payList.toArray(new ItemParamData[0]))) { + return; + } + player.getInventory().removeItems(foodWeapons); - // Packet - player.sendPacket(new PacketAvatarUnlockTalentNotify(avatar, nextTalentId)); - player.sendPacket(new PacketUnlockAvatarTalentRsp(avatar, nextTalentId)); - - // Proud skill bonus map (Extra skills) - OpenConfigEntry entry = GameData.getOpenConfigEntries().get(talentData.getOpenConfig()); - if (entry != null) { - if (entry.getExtraTalentIndex() > 0) { - // Check if new constellation adds +3 to a skill level - avatar.recalcConstellations(); - // Packet - player.sendPacket(new PacketProudSkillExtraLevelNotify(avatar, entry.getExtraTalentIndex())); - } else if (entry.getSkillPointModifiers() != null) { - // Check if new constellation adds skill charges - avatar.recalcConstellations(); - // Packet - for (SkillPointModifier mod : entry.getSkillPointModifiers()) { - player.sendPacket( - new PacketAvatarSkillMaxChargeCountNotify(avatar, mod.getSkillId(), avatar.getSkillExtraChargeMap().getOrDefault(mod.getSkillId(), 0)) - ); - } - } - } - - // Recalc + save avatar - avatar.recalcStats(true); - avatar.save(); - } + // Level up + int maxLevel = promoteData.getUnlockMaxLevel(); + int level = weapon.getLevel(); + int oldLevel = level; + int exp = weapon.getExp(); + int totalExp = weapon.getTotalExp(); + int reqExp = GameData.getWeaponExpRequired(weapon.getItemData().getRankLevel(), level); - public void destroyMaterial(Player player, List list) { - // Return materials - Int2IntOpenHashMap returnMaterialMap = new Int2IntOpenHashMap(); - - for (MaterialInfo info : list) { - // Sanity check - if (info.getCount() <= 0) { - continue; - } - - GameItem item = player.getInventory().getItemByGuid(info.getGuid()); - if (item == null || !item.isDestroyable()) { - continue; - } - - // Remove - int removeAmount = Math.min(info.getCount(), item.getCount()); - player.getInventory().removeItem(item, removeAmount); - - // Delete material return items - if (item.getItemData().getDestroyReturnMaterial().length > 0) { - for (int i = 0; i < item.getItemData().getDestroyReturnMaterial().length; i++) { - returnMaterialMap.addTo(item.getItemData().getDestroyReturnMaterial()[i], item.getItemData().getDestroyReturnMaterialCount()[i]); - } - } - } - - // Give back items - if (returnMaterialMap.size() > 0) { - for (Int2IntMap.Entry e : returnMaterialMap.int2IntEntrySet()) { - player.getInventory().addItem(new GameItem(e.getIntKey(), e.getIntValue())); - } - } - - // Packets - player.sendPacket(new PacketDestroyMaterialRsp(returnMaterialMap)); - } + while (expGain > 0 && reqExp > 0 && level < maxLevel) { + // Do calculations + int toGain = Math.min(expGain, reqExp - exp); + exp += toGain; + totalExp += toGain; + expGain -= toGain; + // Level up + if (exp >= reqExp) { + // Exp + exp = 0; + level += 1; + // Set req exp + reqExp = GameData.getWeaponExpRequired(weapon.getItemData().getRankLevel(), level); + } + } - public GameItem useItem(Player player, long targetGuid, long itemGuid, int count, int optionId) { - Avatar target = player.getAvatars().getAvatarByGuid(targetGuid); - GameItem useItem = player.getInventory().getItemByGuid(itemGuid); - - if (useItem == null) { - return null; - } - - int used = 0; - boolean useSuccess = false; - - // Use - switch (useItem.getItemData().getMaterialType()) { - case MATERIAL_FOOD: - if (useItem.getItemData().getUseTarget().equals("ITEM_USE_TARGET_SPECIFY_DEAD_AVATAR")) { - if (target == null) { - break; - } + List leftovers = getLeftoverOres(expGain); + player.getInventory().addItemParams(leftovers); - used = player.getTeamManager().reviveAvatar(target) ? 1 : 0; - } - break; - case MATERIAL_NOTICE_ADD_HP: - if (useItem.getItemData().getUseTarget().equals("ITEM_USE_TARGET_SPECIFY_ALIVE_AVATAR")) { - if (target == null) { - break; - } + weapon.setLevel(level); + weapon.setExp(exp); + weapon.setTotalExp(totalExp); + weapon.save(); - int[] SatiationParams = useItem.getItemData().getSatiationParams(); - used = player.getTeamManager().healAvatar(target, SatiationParams[0], SatiationParams[1]) ? 1 : 0; - } - break; - case MATERIAL_CONSUME: - // Make sure we have usage data for this material. - if (useItem.getItemData().getItemUse() == null) { - break; - } + // Avatar + if (oldLevel != level) { + Avatar avatar = weapon.getEquipCharacter() > 0 ? player.getAvatars().getAvatarById(weapon.getEquipCharacter()) : null; + if (avatar != null) { + avatar.recalcStats(); + } + } - // Handle forging blueprints. - if (useItem.getItemData().getItemUse().get(0).getUseOp().equals("ITEM_USE_UNLOCK_FORGE")) { - // Unlock. - useSuccess = player.getForgingManager().unlockForgingBlueprint(useItem); - } - // Handle combine diagrams. - if (useItem.getItemData().getItemUse().get(0).getUseOp().equals("ITEM_USE_UNLOCK_COMBINE")) { - // Unlock. - useSuccess = player.getServer().getCombineSystem().unlockCombineDiagram(player, useItem); - } - // Handle cooking recipies. - if (useItem.getItemData().getItemUse().get(0).getUseOp().equals("ITEM_USE_UNLOCK_COOK_RECIPE")) { - // Unlock. - useSuccess = player.getCookingManager().unlockRecipe(useItem); - } - break; - case MATERIAL_FURNITURE_FORMULA: - case MATERIAL_FURNITURE_SUITE_FORMULA: - if (useItem.getItemData().getItemUse() == null) { - break; - } - useSuccess = player.getFurnitureManager().unlockFurnitureOrSuite(useItem); + // Packets + player.sendPacket(new PacketStoreItemChangeNotify(weapon)); + player.sendPacket(new PacketWeaponUpgradeRsp(weapon, oldLevel, leftovers)); + } - break; - case MATERIAL_CONSUME_BATCH_USE: - // Make sure we have usage data for this material. - if (useItem.getItemData().getItemUse() == null) { - break; - } + private List getLeftoverOres(int leftover) { + List leftoverOreList = new ArrayList<>(3); - // Handle fragile/transient resin. - if (useItem.getItemId() == 107009 || useItem.getItemId() == 107012){ - // Add resin to the inventory. - ItemData resinItemData = GameData.getItemDataMap().get(106); - player.getInventory().addItem(new GameItem(resinItemData, 60 * count), ActionReason.PlayerUseItem); + if (leftover < WEAPON_ORE_EXP_1) { + return leftoverOreList; + } - // Set used amount. - used = count; - } - break; - case MATERIAL_CHEST: - List shopChestTableList = player.getServer().getShopSystem().getShopChestData(); - List rewardItemList = new ArrayList<>(); - for (ShopChestTable shopChestTable : shopChestTableList) { - if (shopChestTable.getItemId() != useItem.getItemId()) { - continue; - } + // Get leftovers + int ore3 = leftover / WEAPON_ORE_EXP_3; + leftover = leftover % WEAPON_ORE_EXP_3; + int ore2 = leftover / WEAPON_ORE_EXP_2; + leftover = leftover % WEAPON_ORE_EXP_2; + int ore1 = leftover / WEAPON_ORE_EXP_1; - if (shopChestTable.getContainsItem() == null) { - break; - } + if (ore3 > 0) { + leftoverOreList.add(ItemParam.newBuilder().setItemId(WEAPON_ORE_3).setCount(ore3).build()); + } if (ore2 > 0) { + leftoverOreList.add(ItemParam.newBuilder().setItemId(WEAPON_ORE_2).setCount(ore2).build()); + } if (ore1 > 0) { + leftoverOreList.add(ItemParam.newBuilder().setItemId(WEAPON_ORE_1).setCount(ore1).build()); + } - for (ItemParamData itemParamData : shopChestTable.getContainsItem()) { - ItemData itemData = GameData.getItemDataMap().get(itemParamData.getId()); - if (itemData == null) { - continue; - } - rewardItemList.add(new GameItem(itemData, itemParamData.getCount())); - } + return leftoverOreList; + } - if (!rewardItemList.isEmpty()) { - player.getInventory().addItems(rewardItemList, ActionReason.Shop); - } + public void refineWeapon(Player player, long targetGuid, long feedGuid) { + GameItem weapon = player.getInventory().getItemByGuid(targetGuid); + GameItem feed = player.getInventory().getItemByGuid(feedGuid); - used = 1; - break; - } - break; - case MATERIAL_CHEST_BATCH_USE: - if (optionId < 1) { - break; - } - List shopChestBatchUseTableList = player.getServer().getShopSystem().getShopChestBatchUseData(); - for (ShopChestBatchUseTable shopChestBatchUseTable : shopChestBatchUseTableList) { - if (shopChestBatchUseTable.getItemId() != useItem.getItemId()) { - continue; - } + // Sanity checks + if (weapon == null || feed == null || !feed.isDestroyable()) { + return; + } - if (shopChestBatchUseTable.getOptionItem() == null || optionId > shopChestBatchUseTable.getOptionItem().size()) { - break; - } + if (weapon.getItemData().getAwakenMaterial() == 0) { + if (weapon.getItemType() != ItemType.ITEM_WEAPON || weapon.getItemId() != feed.getItemId()) { + return; + } + } else { + if (weapon.getItemType() != ItemType.ITEM_WEAPON || weapon.getItemData().getAwakenMaterial() != feed.getItemId()) { + return; + } + } - int optionItemId = shopChestBatchUseTable.getOptionItem().get(optionId - 1); - ItemData itemData = GameData.getItemDataMap().get(optionItemId); - if (itemData == null) { - break; - } + if (weapon.getRefinement() >= 4 || weapon.getAffixes() == null || weapon.getAffixes().size() == 0) { + return; + } - player.getInventory().addItem(new GameItem(itemData, count), ActionReason.Shop); + // Calculate + int oldRefineLevel = weapon.getRefinement(); + int targetRefineLevel = Math.min(oldRefineLevel + feed.getRefinement() + 1, 4); + int moraCost = 0; - used = count; - break; - } - break; - default: - break; - } + try { + moraCost = weapon.getItemData().getAwakenCosts()[weapon.getRefinement()]; + } catch (Exception e) { + return; + } - // Welkin - if (useItem.getItemId() == 1202) { - player.rechargeMoonCard(); - used = 1; - } + // Mora check + if (player.getMora() >= moraCost) { + player.setMora(player.getMora() - moraCost); + } else { + return; + } - // If we used at least one item, or one of the methods called here reports using the item successfully, - // we return the item to make UseItemRsp a success. - if (used > 0) { - player.getInventory().removeItem(useItem, used); - return useItem; - } - if (useSuccess) { - return useItem; - } + // Consume weapon + player.getInventory().removeItem(feed, 1); - return null; - } + // Get + weapon.setRefinement(targetRefineLevel); + weapon.save(); + + // Avatar + Avatar avatar = weapon.getEquipCharacter() > 0 ? player.getAvatars().getAvatarById(weapon.getEquipCharacter()) : null; + if (avatar != null) { + avatar.recalcStats(); + } + + // Packets + player.sendPacket(new PacketStoreItemChangeNotify(weapon)); + player.sendPacket(new PacketWeaponAwakenRsp(avatar, weapon, feed, oldRefineLevel)); + } + + public void promoteWeapon(Player player, long targetGuid) { + GameItem weapon = player.getInventory().getItemByGuid(targetGuid); + + if (weapon == null || weapon.getItemType() != ItemType.ITEM_WEAPON) { + return; + } + + int nextPromoteLevel = weapon.getPromoteLevel() + 1; + WeaponPromoteData currentPromoteData = GameData.getWeaponPromoteData(weapon.getItemData().getWeaponPromoteId(), weapon.getPromoteLevel()); + WeaponPromoteData nextPromoteData = GameData.getWeaponPromoteData(weapon.getItemData().getWeaponPromoteId(), nextPromoteLevel); + if (currentPromoteData == null || nextPromoteData == null) { + return; + } + + // Level check + if (weapon.getLevel() != currentPromoteData.getUnlockMaxLevel()) { + return; + } + + // Pay materials and mora if possible + ItemParamData[] costs = nextPromoteData.getCostItems(); // Can this be null? + if (nextPromoteData.getCoinCost() > 0) { + costs = Arrays.copyOf(costs, costs.length + 1); + costs[costs.length-1] = new ItemParamData(202, nextPromoteData.getCoinCost()); + } + if (!player.getInventory().payItems(costs)) { + return; + } + + int oldPromoteLevel = weapon.getPromoteLevel(); + weapon.setPromoteLevel(nextPromoteLevel); + weapon.save(); + + // Avatar + Avatar avatar = weapon.getEquipCharacter() > 0 ? player.getAvatars().getAvatarById(weapon.getEquipCharacter()) : null; + if (avatar != null) { + avatar.recalcStats(); + } + + // Packets + player.sendPacket(new PacketStoreItemChangeNotify(weapon)); + player.sendPacket(new PacketWeaponPromoteRsp(weapon, oldPromoteLevel)); + } + + public void promoteAvatar(Player player, long guid) { + Avatar avatar = player.getAvatars().getAvatarByGuid(guid); + + // Sanity checks + if (avatar == null) { + return; + } + + int nextPromoteLevel = avatar.getPromoteLevel() + 1; + AvatarPromoteData currentPromoteData = GameData.getAvatarPromoteData(avatar.getAvatarData().getAvatarPromoteId(), avatar.getPromoteLevel()); + AvatarPromoteData nextPromoteData = GameData.getAvatarPromoteData(avatar.getAvatarData().getAvatarPromoteId(), nextPromoteLevel); + if (currentPromoteData == null || nextPromoteData == null) { + return; + } + + // Level check + if (avatar.getLevel() != currentPromoteData.getUnlockMaxLevel()) { + return; + } + + // Pay materials and mora if possible + ItemParamData[] costs = nextPromoteData.getCostItems(); // Can this be null? + if (nextPromoteData.getCoinCost() > 0) { + costs = Arrays.copyOf(costs, costs.length + 1); + costs[costs.length-1] = new ItemParamData(202, nextPromoteData.getCoinCost()); + } + if (!player.getInventory().payItems(costs)) { + return; + } + + // Update promote level + avatar.setPromoteLevel(nextPromoteLevel); + + // Update proud skills + AvatarSkillDepotData skillDepot = GameData.getAvatarSkillDepotDataMap().get(avatar.getSkillDepotId()); + + if (skillDepot != null && skillDepot.getInherentProudSkillOpens() != null) { + for (InherentProudSkillOpens openData : skillDepot.getInherentProudSkillOpens()) { + if (openData.getProudSkillGroupId() == 0) { + continue; + } + if (openData.getNeedAvatarPromoteLevel() == avatar.getPromoteLevel()) { + int proudSkillId = (openData.getProudSkillGroupId() * 100) + 1; + if (GameData.getProudSkillDataMap().containsKey(proudSkillId)) { + avatar.getProudSkillList().add(proudSkillId); + player.sendPacket(new PacketProudSkillChangeNotify(avatar)); + } + } + } + } + + // Packets + player.sendPacket(new PacketAvatarPropNotify(avatar)); + player.sendPacket(new PacketAvatarPromoteRsp(avatar)); + + // TODO Send entity prop update packet to world + avatar.recalcStats(true); + avatar.save(); + } + + public void upgradeAvatar(Player player, long guid, int itemId, int count) { + Avatar avatar = player.getAvatars().getAvatarByGuid(guid); + + // Sanity checks + if (avatar == null) { + return; + } + + AvatarPromoteData promoteData = GameData.getAvatarPromoteData(avatar.getAvatarData().getAvatarPromoteId(), avatar.getPromoteLevel()); + if (promoteData == null) { + return; + } + + // Calc exp + int expGain = switch (itemId) { + case AVATAR_BOOK_1 -> AVATAR_BOOK_EXP_1 * count; + case AVATAR_BOOK_2 -> AVATAR_BOOK_EXP_2 * count; + case AVATAR_BOOK_3 -> AVATAR_BOOK_EXP_3 * count; + default -> 0; + }; + + // Sanity check + if (expGain <= 0) { + return; + } + + // Payment check + int moraCost = expGain / 5; + ItemParamData[] costItems = new ItemParamData[] {new ItemParamData(itemId, count), new ItemParamData(202, moraCost)}; + if (!player.getInventory().payItems(costItems)) { + return; + } + + // Level up + upgradeAvatar(player, avatar, promoteData, expGain); + } + + public void upgradeAvatar(Player player, Avatar avatar, int expGain) { + AvatarPromoteData promoteData = GameData.getAvatarPromoteData(avatar.getAvatarData().getAvatarPromoteId(), avatar.getPromoteLevel()); + if (promoteData == null) { + return; + } + + upgradeAvatar(player, avatar, promoteData, expGain); + } + + public void upgradeAvatar(Player player, Avatar avatar, AvatarPromoteData promoteData, int expGain) { + int maxLevel = promoteData.getUnlockMaxLevel(); + int level = avatar.getLevel(); + int oldLevel = level; + int exp = avatar.getExp(); + int reqExp = GameData.getAvatarLevelExpRequired(level); + + while (expGain > 0 && reqExp > 0 && level < maxLevel) { + // Do calculations + int toGain = Math.min(expGain, reqExp - exp); + exp += toGain; + expGain -= toGain; + // Level up + if (exp >= reqExp) { + // Exp + exp = 0; + level += 1; + // Set req exp + reqExp = GameData.getAvatarLevelExpRequired(level); + } + } + + // Old map for packet + Map oldPropMap = avatar.getFightProperties(); + if (oldLevel != level) { + // Deep copy if level has changed + oldPropMap = avatar.getFightProperties().int2FloatEntrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); + } + + // Done + avatar.setLevel(level); + avatar.setExp(exp); + avatar.recalcStats(); + avatar.save(); + + // TODO Send entity prop update packet to world + + // Packets + player.sendPacket(new PacketAvatarPropNotify(avatar)); + player.sendPacket(new PacketAvatarUpgradeRsp(avatar, oldLevel, oldPropMap)); + } + + public void upgradeAvatarFetterLevel(Player player, Avatar avatar, int expGain) { + // May work. Not test. + int maxLevel = 10; // Keep it until I think of a more "elegant" way + int level = avatar.getFetterLevel(); + int exp = avatar.getFetterExp(); + int reqExp = GameData.getAvatarFetterLevelExpRequired(level); + + while (expGain > 0 && reqExp > 0 && level < maxLevel) { + int toGain = Math.min(expGain, reqExp - exp); + exp += toGain; + expGain -= toGain; + if (exp >= reqExp) { + exp = 0; + level += 1; + reqExp = GameData.getAvatarFetterLevelExpRequired(level); + } + } + + avatar.setFetterLevel(level); + avatar.setFetterExp(exp); + avatar.save(); + + player.sendPacket(new PacketAvatarPropNotify(avatar)); + player.sendPacket(new PacketAvatarFetterDataNotify(avatar)); + } + + public void upgradeAvatarSkill(Player player, long guid, int skillId) { + // Sanity checks + Avatar avatar = player.getAvatars().getAvatarByGuid(guid); + if (avatar == null) { + return; + } + + // Make sure avatar has skill + if (!avatar.getSkillLevelMap().containsKey(skillId)) { + return; + } + + AvatarSkillData skillData = GameData.getAvatarSkillDataMap().get(skillId); + if (skillData == null) { + return; + } + + // Get data for next skill level + int currentLevel = avatar.getSkillLevelMap().get(skillId); + int nextLevel = currentLevel + 1; + int proudSkillId = (skillData.getProudSkillGroupId() * 100) + nextLevel; + + // Capped at level 10 talent + if (nextLevel > 10) { + return; + } + + // Proud skill data + ProudSkillData proudSkill = GameData.getProudSkillDataMap().get(proudSkillId); + if (proudSkill == null) { + return; + } + + // Make sure break level is correct + if (avatar.getPromoteLevel() < proudSkill.getBreakLevel()) { + return; + } + + // Pay materials and mora if possible + List costs = new ArrayList(proudSkill.getCostItems()); // Can this be null? + if (proudSkill.getCoinCost() > 0) { + costs.add(new ItemParamData(202, proudSkill.getCoinCost())); + } + if (!player.getInventory().payItems(costs.toArray(new ItemParamData[0]))) { + return; + } + + // Upgrade skill + avatar.getSkillLevelMap().put(skillId, nextLevel); + avatar.save(); + + // Packet + player.sendPacket(new PacketAvatarSkillChangeNotify(avatar, skillId, currentLevel, nextLevel)); + player.sendPacket(new PacketAvatarSkillUpgradeRsp(avatar, skillId, currentLevel, nextLevel)); + } + + public void unlockAvatarConstellation(Player player, long guid) { + // Sanity checks + Avatar avatar = player.getAvatars().getAvatarByGuid(guid); + if (avatar == null) { + return; + } + + // Get talent + int currentTalentLevel = avatar.getCoreProudSkillLevel(); + int nextTalentId = ((avatar.getAvatarId() % 10000000) * 10) + currentTalentLevel + 1; + + if (avatar.getAvatarId() == 10000006) { + // Lisa is special in that her talentId starts with 4 instead of 6. + nextTalentId = 40 + currentTalentLevel + 1; + } + + AvatarTalentData talentData = GameData.getAvatarTalentDataMap().get(nextTalentId); + + if (talentData == null) { + return; + } + + // Pay constellation item if possible + if (!player.getInventory().payItem(talentData.getMainCostItemId(), 1)) { + return; + } + + // Apply + recalc + avatar.getTalentIdList().add(talentData.getId()); + avatar.setCoreProudSkillLevel(currentTalentLevel + 1); + + // Packet + player.sendPacket(new PacketAvatarUnlockTalentNotify(avatar, nextTalentId)); + player.sendPacket(new PacketUnlockAvatarTalentRsp(avatar, nextTalentId)); + + // Proud skill bonus map (Extra skills) + OpenConfigEntry entry = GameData.getOpenConfigEntries().get(talentData.getOpenConfig()); + if (entry != null) { + if (entry.getExtraTalentIndex() > 0) { + // Check if new constellation adds +3 to a skill level + avatar.recalcConstellations(); + // Packet + player.sendPacket(new PacketProudSkillExtraLevelNotify(avatar, entry.getExtraTalentIndex())); + } else if (entry.getSkillPointModifiers() != null) { + // Check if new constellation adds skill charges + avatar.recalcConstellations(); + // Packet + for (SkillPointModifier mod : entry.getSkillPointModifiers()) { + player.sendPacket( + new PacketAvatarSkillMaxChargeCountNotify(avatar, mod.getSkillId(), avatar.getSkillExtraChargeMap().getOrDefault(mod.getSkillId(), 0)) + ); + } + } + } + + // Recalc + save avatar + avatar.recalcStats(true); + avatar.save(); + } + + public void destroyMaterial(Player player, List list) { + // Return materials + Int2IntOpenHashMap returnMaterialMap = new Int2IntOpenHashMap(); + + for (MaterialInfo info : list) { + // Sanity check + if (info.getCount() <= 0) { + continue; + } + + GameItem item = player.getInventory().getItemByGuid(info.getGuid()); + if (item == null || !item.isDestroyable()) { + continue; + } + + // Remove + int removeAmount = Math.min(info.getCount(), item.getCount()); + player.getInventory().removeItem(item, removeAmount); + + // Delete material return items + if (item.getItemData().getDestroyReturnMaterial().length > 0) { + for (int i = 0; i < item.getItemData().getDestroyReturnMaterial().length; i++) { + returnMaterialMap.addTo(item.getItemData().getDestroyReturnMaterial()[i], item.getItemData().getDestroyReturnMaterialCount()[i]); + } + } + } + + // Give back items + if (returnMaterialMap.size() > 0) { + for (Int2IntMap.Entry e : returnMaterialMap.int2IntEntrySet()) { + player.getInventory().addItem(new GameItem(e.getIntKey(), e.getIntValue())); + } + } + + // Packets + player.sendPacket(new PacketDestroyMaterialRsp(returnMaterialMap)); + } + + public GameItem useItem(Player player, long targetGuid, long itemGuid, int count, int optionId) { + Avatar target = player.getAvatars().getAvatarByGuid(targetGuid); + GameItem useItem = player.getInventory().getItemByGuid(itemGuid); + + if (useItem == null) { + return null; + } + + int used = 0; + boolean useSuccess = false; + + // Use + switch (useItem.getItemData().getMaterialType()) { + case MATERIAL_FOOD: + if (useItem.getItemData().getUseTarget().equals("ITEM_USE_TARGET_SPECIFY_DEAD_AVATAR")) { + if (target == null) { + break; + } + + used = player.getTeamManager().reviveAvatar(target) ? 1 : 0; + } + break; + case MATERIAL_NOTICE_ADD_HP: + if (useItem.getItemData().getUseTarget().equals("ITEM_USE_TARGET_SPECIFY_ALIVE_AVATAR")) { + if (target == null) { + break; + } + + int[] SatiationParams = useItem.getItemData().getSatiationParams(); + used = player.getTeamManager().healAvatar(target, SatiationParams[0], SatiationParams[1]) ? 1 : 0; + } + break; + case MATERIAL_CONSUME: + // Make sure we have usage data for this material. + if (useItem.getItemData().getItemUse() == null) { + break; + } + + // Handle forging blueprints. + if (useItem.getItemData().getItemUse().get(0).getUseOp().equals("ITEM_USE_UNLOCK_FORGE")) { + // Unlock. + useSuccess = player.getForgingManager().unlockForgingBlueprint(useItem); + } + // Handle combine diagrams. + if (useItem.getItemData().getItemUse().get(0).getUseOp().equals("ITEM_USE_UNLOCK_COMBINE")) { + // Unlock. + useSuccess = player.getServer().getCombineSystem().unlockCombineDiagram(player, useItem); + } + // Handle cooking recipies. + if (useItem.getItemData().getItemUse().get(0).getUseOp().equals("ITEM_USE_UNLOCK_COOK_RECIPE")) { + // Unlock. + useSuccess = player.getCookingManager().unlockRecipe(useItem); + } + break; + case MATERIAL_FURNITURE_FORMULA: + case MATERIAL_FURNITURE_SUITE_FORMULA: + if (useItem.getItemData().getItemUse() == null) { + break; + } + useSuccess = player.getFurnitureManager().unlockFurnitureOrSuite(useItem); + + break; + case MATERIAL_CONSUME_BATCH_USE: + // Make sure we have usage data for this material. + if (useItem.getItemData().getItemUse() == null) { + break; + } + + // Handle fragile/transient resin. + if (useItem.getItemId() == 107009 || useItem.getItemId() == 107012) { + // Add resin to the inventory. + ItemData resinItemData = GameData.getItemDataMap().get(106); + player.getInventory().addItem(new GameItem(resinItemData, 60 * count), ActionReason.PlayerUseItem); + + // Set used amount. + used = count; + } + break; + case MATERIAL_CHEST: + List shopChestTableList = player.getServer().getShopSystem().getShopChestData(); + List rewardItemList = new ArrayList<>(); + for (ShopChestTable shopChestTable : shopChestTableList) { + if (shopChestTable.getItemId() != useItem.getItemId()) { + continue; + } + + if (shopChestTable.getContainsItem() == null) { + break; + } + + for (ItemParamData itemParamData : shopChestTable.getContainsItem()) { + ItemData itemData = GameData.getItemDataMap().get(itemParamData.getId()); + if (itemData == null) { + continue; + } + rewardItemList.add(new GameItem(itemData, itemParamData.getCount())); + } + + if (!rewardItemList.isEmpty()) { + player.getInventory().addItems(rewardItemList, ActionReason.Shop); + } + + used = 1; + break; + } + break; + case MATERIAL_CHEST_BATCH_USE: + if (optionId < 1) { + break; + } + List shopChestBatchUseTableList = player.getServer().getShopSystem().getShopChestBatchUseData(); + for (ShopChestBatchUseTable shopChestBatchUseTable : shopChestBatchUseTableList) { + if (shopChestBatchUseTable.getItemId() != useItem.getItemId()) { + continue; + } + + if (shopChestBatchUseTable.getOptionItem() == null || optionId > shopChestBatchUseTable.getOptionItem().size()) { + break; + } + + int optionItemId = shopChestBatchUseTable.getOptionItem().get(optionId - 1); + ItemData itemData = GameData.getItemDataMap().get(optionItemId); + if (itemData == null) { + break; + } + + player.getInventory().addItem(new GameItem(itemData, count), ActionReason.Shop); + + used = count; + break; + } + break; + default: + break; + } + + // Welkin + if (useItem.getItemId() == 1202) { + player.rechargeMoonCard(); + used = 1; + } + + // If we used at least one item, or one of the methods called here reports using the item successfully, + // we return the item to make UseItemRsp a success. + if (used > 0) { + player.getInventory().removeItem(useItem, used); + return useItem; + } + if (useSuccess) { + return useItem; + } + + return null; + } } diff --git a/src/main/java/emu/grasscutter/game/systems/MultiplayerSystem.java b/src/main/java/emu/grasscutter/game/systems/MultiplayerSystem.java index a3f23a448..71daa2c1b 100644 --- a/src/main/java/emu/grasscutter/game/systems/MultiplayerSystem.java +++ b/src/main/java/emu/grasscutter/game/systems/MultiplayerSystem.java @@ -16,140 +16,140 @@ import emu.grasscutter.server.packet.send.PacketPlayerEnterSceneNotify; public class MultiplayerSystem extends BaseGameSystem { - public MultiplayerSystem(GameServer server) { - super(server); - } + public MultiplayerSystem(GameServer server) { + super(server); + } - public void applyEnterMp(Player player, int targetUid) { - Player target = getServer().getPlayerByUid(targetUid); - if (target == null) { - player.sendPacket(new PacketPlayerApplyEnterMpResultNotify(targetUid, "", false, PlayerApplyEnterMpResultNotifyOuterClass.PlayerApplyEnterMpResultNotify.Reason.REASON_PLAYER_CANNOT_ENTER_MP)); - return; - } - - // Sanity checks - Dont let player join if already in multiplayer - if (player.getWorld().isMultiplayer()) { - return; - } - - /* - if (target.getWorld().isDungeon()) { - player.sendPacket(new PacketPlayerApplyEnterMpResultNotify(targetUid, "", false, PlayerApplyEnterMpReason.SceneCannotEnter)); - return; - } - */ - - // Get request - CoopRequest request = target.getCoopRequests().get(player.getUid()); - - if (request != null && !request.isExpired()) { - // Join request already exists - return; - } - - // Put request in - request = new CoopRequest(player); - target.getCoopRequests().put(player.getUid(), request); - - // Packet - target.sendPacket(new PacketPlayerApplyEnterMpNotify(player)); - } + public void applyEnterMp(Player player, int targetUid) { + Player target = getServer().getPlayerByUid(targetUid); + if (target == null) { + player.sendPacket(new PacketPlayerApplyEnterMpResultNotify(targetUid, "", false, PlayerApplyEnterMpResultNotifyOuterClass.PlayerApplyEnterMpResultNotify.Reason.REASON_PLAYER_CANNOT_ENTER_MP)); + return; + } - public void applyEnterMpReply(Player hostPlayer, int applyUid, boolean isAgreed) { - // Checks - CoopRequest request = hostPlayer.getCoopRequests().get(applyUid); - if (request == null || request.isExpired()) { - return; - } - - // Remove now that we are handling it - Player requester = request.getRequester(); - hostPlayer.getCoopRequests().remove(applyUid); - - // Sanity checks - Dont let the requesting player join if they are already in multiplayer - if (requester.getWorld().isMultiplayer()) { - request.getRequester().sendPacket(new PacketPlayerApplyEnterMpResultNotify(hostPlayer, false, PlayerApplyEnterMpResultNotifyOuterClass.PlayerApplyEnterMpResultNotify.Reason.REASON_PLAYER_CANNOT_ENTER_MP)); - return; - } - - // Response packet - request.getRequester().sendPacket(new PacketPlayerApplyEnterMpResultNotify(hostPlayer, isAgreed, PlayerApplyEnterMpResultNotifyOuterClass.PlayerApplyEnterMpResultNotify.Reason.REASON_PLAYER_JUDGE)); - - // Declined - if (!isAgreed) { - return; - } + // Sanity checks - Dont let player join if already in multiplayer + if (player.getWorld().isMultiplayer()) { + return; + } - // Success - if (!hostPlayer.getWorld().isMultiplayer()) { - // Player not in multiplayer, create multiplayer world - World world = new World(hostPlayer, true); + /* + if (target.getWorld().isDungeon()) { + player.sendPacket(new PacketPlayerApplyEnterMpResultNotify(targetUid, "", false, PlayerApplyEnterMpReason.SceneCannotEnter)); + return; + } + */ - // Add - world.addPlayer(hostPlayer); - - // Rejoin packet - hostPlayer.sendPacket(new PacketPlayerEnterSceneNotify(hostPlayer, hostPlayer, EnterType.ENTER_TYPE_SELF, EnterReason.HostFromSingleToMp, hostPlayer.getScene().getId(), hostPlayer.getPosition())); - } - - // Set scene pos and id of requester to the host player's - requester.getPosition().set(hostPlayer.getPosition()); - requester.getRotation().set(hostPlayer.getRotation()); - requester.setSceneId(hostPlayer.getSceneId()); - - // Make requester join - hostPlayer.getWorld().addPlayer(requester); + // Get request + CoopRequest request = target.getCoopRequests().get(player.getUid()); - // Packet - requester.sendPacket(new PacketPlayerEnterSceneNotify(requester, hostPlayer, EnterType.ENTER_TYPE_OTHER, EnterReason.TeamJoin, hostPlayer.getScene().getId(), hostPlayer.getPosition())); - } - - public boolean leaveCoop(Player player) { - // Make sure player's world is multiplayer - if (!player.getWorld().isMultiplayer()) { - return false; - } - - // Make sure everyone's scene is loaded - for (Player p : player.getWorld().getPlayers()) { - if (p.getSceneLoadState() != SceneLoadState.LOADED) { - return false; - } - } - - // Create new world for player - World world = new World(player); - world.addPlayer(player); - - // Packet - player.sendPacket(new PacketPlayerEnterSceneNotify(player, EnterType.ENTER_TYPE_SELF, EnterReason.TeamBack, player.getScene().getId(), player.getPosition())); - - return true; - } + if (request != null && !request.isExpired()) { + // Join request already exists + return; + } - public boolean kickPlayer(Player player, int targetUid) { - // Make sure player's world is multiplayer and that player is owner - if (!player.getWorld().isMultiplayer() || player.getWorld().getHost() != player) { - return false; - } - - // Get victim and sanity checks - Player victim = player.getServer().getPlayerByUid(targetUid); - - if (victim == null || victim == player) { - return false; - } - - // Make sure victim's scene has loaded - if (victim.getSceneLoadState() != SceneLoadState.LOADED) { - return false; - } - - // Kick - World world = new World(victim); - world.addPlayer(victim); - - victim.sendPacket(new PacketPlayerEnterSceneNotify(victim, EnterType.ENTER_TYPE_SELF, EnterReason.TeamKick, victim.getScene().getId(), victim.getPosition())); - return true; - } + // Put request in + request = new CoopRequest(player); + target.getCoopRequests().put(player.getUid(), request); + + // Packet + target.sendPacket(new PacketPlayerApplyEnterMpNotify(player)); + } + + public void applyEnterMpReply(Player hostPlayer, int applyUid, boolean isAgreed) { + // Checks + CoopRequest request = hostPlayer.getCoopRequests().get(applyUid); + if (request == null || request.isExpired()) { + return; + } + + // Remove now that we are handling it + Player requester = request.getRequester(); + hostPlayer.getCoopRequests().remove(applyUid); + + // Sanity checks - Dont let the requesting player join if they are already in multiplayer + if (requester.getWorld().isMultiplayer()) { + request.getRequester().sendPacket(new PacketPlayerApplyEnterMpResultNotify(hostPlayer, false, PlayerApplyEnterMpResultNotifyOuterClass.PlayerApplyEnterMpResultNotify.Reason.REASON_PLAYER_CANNOT_ENTER_MP)); + return; + } + + // Response packet + request.getRequester().sendPacket(new PacketPlayerApplyEnterMpResultNotify(hostPlayer, isAgreed, PlayerApplyEnterMpResultNotifyOuterClass.PlayerApplyEnterMpResultNotify.Reason.REASON_PLAYER_JUDGE)); + + // Declined + if (!isAgreed) { + return; + } + + // Success + if (!hostPlayer.getWorld().isMultiplayer()) { + // Player not in multiplayer, create multiplayer world + World world = new World(hostPlayer, true); + + // Add + world.addPlayer(hostPlayer); + + // Rejoin packet + hostPlayer.sendPacket(new PacketPlayerEnterSceneNotify(hostPlayer, hostPlayer, EnterType.ENTER_TYPE_SELF, EnterReason.HostFromSingleToMp, hostPlayer.getScene().getId(), hostPlayer.getPosition())); + } + + // Set scene pos and id of requester to the host player's + requester.getPosition().set(hostPlayer.getPosition()); + requester.getRotation().set(hostPlayer.getRotation()); + requester.setSceneId(hostPlayer.getSceneId()); + + // Make requester join + hostPlayer.getWorld().addPlayer(requester); + + // Packet + requester.sendPacket(new PacketPlayerEnterSceneNotify(requester, hostPlayer, EnterType.ENTER_TYPE_OTHER, EnterReason.TeamJoin, hostPlayer.getScene().getId(), hostPlayer.getPosition())); + } + + public boolean leaveCoop(Player player) { + // Make sure player's world is multiplayer + if (!player.getWorld().isMultiplayer()) { + return false; + } + + // Make sure everyone's scene is loaded + for (Player p : player.getWorld().getPlayers()) { + if (p.getSceneLoadState() != SceneLoadState.LOADED) { + return false; + } + } + + // Create new world for player + World world = new World(player); + world.addPlayer(player); + + // Packet + player.sendPacket(new PacketPlayerEnterSceneNotify(player, EnterType.ENTER_TYPE_SELF, EnterReason.TeamBack, player.getScene().getId(), player.getPosition())); + + return true; + } + + public boolean kickPlayer(Player player, int targetUid) { + // Make sure player's world is multiplayer and that player is owner + if (!player.getWorld().isMultiplayer() || player.getWorld().getHost() != player) { + return false; + } + + // Get victim and sanity checks + Player victim = player.getServer().getPlayerByUid(targetUid); + + if (victim == null || victim == player) { + return false; + } + + // Make sure victim's scene has loaded + if (victim.getSceneLoadState() != SceneLoadState.LOADED) { + return false; + } + + // Kick + World world = new World(victim); + world.addPlayer(victim); + + victim.sendPacket(new PacketPlayerEnterSceneNotify(victim, EnterType.ENTER_TYPE_SELF, EnterReason.TeamKick, victim.getScene().getId(), victim.getPosition())); + return true; + } } diff --git a/src/main/java/emu/grasscutter/game/tower/TowerManager.java b/src/main/java/emu/grasscutter/game/tower/TowerManager.java index 19a6d860c..8da97358c 100644 --- a/src/main/java/emu/grasscutter/game/tower/TowerManager.java +++ b/src/main/java/emu/grasscutter/game/tower/TowerManager.java @@ -13,11 +13,11 @@ import java.util.List; import java.util.Map; public class TowerManager extends BasePlayerManager { - + public TowerManager(Player player) { super(player); } - + public TowerData getTowerData() { return getPlayer().getTowerData(); } @@ -26,21 +26,21 @@ public class TowerManager extends BasePlayerManager { return getTowerData().currentFloorId; } - public int getCurrentLevelId(){ + public int getCurrentLevelId() { return getTowerData().currentLevelId + getTowerData().currentLevel; } /** * form 1-3 */ - public int getCurrentLevel(){ + public int getCurrentLevel() { return getTowerData().currentLevel + 1; } private static final List towerDungeonSettleListener = List.of(new TowerDungeonSettleListener()); - + public Map getRecordMap() { Map recordMap = getTowerData().recordMap; - if(recordMap == null || recordMap.size()==0){ + if (recordMap == null || recordMap.size()==0) { recordMap = new HashMap<>(); recordMap.put(1001, new TowerLevelRecord(1001)); getTowerData().recordMap = recordMap; @@ -58,7 +58,7 @@ public class TowerManager extends BasePlayerManager { .map(TowerLevelData::getId) .orElse(0); - if (getTowerData().entryScene == 0){ + if (getTowerData().entryScene == 0) { getTowerData().entryScene = player.getSceneId(); } @@ -88,37 +88,37 @@ public class TowerManager extends BasePlayerManager { player.getSession().send(new PacketTowerLevelStarCondNotify(getTowerData().currentFloorId, getCurrentLevel())); } - public void notifyCurLevelRecordChange(){ + public void notifyCurLevelRecordChange() { player.getSession().send(new PacketTowerCurLevelRecordChangeNotify(getTowerData().currentFloorId, getCurrentLevel())); } - public void notifyCurLevelRecordChangeWhenDone(int stars){ + public void notifyCurLevelRecordChangeWhenDone(int stars) { Map recordMap = getRecordMap(); int currentFloorId = getTowerData().currentFloorId; - if(!recordMap.containsKey(currentFloorId)){ + if (!recordMap.containsKey(currentFloorId)) { recordMap.put(currentFloorId, new TowerLevelRecord(currentFloorId).setLevelStars(getCurrentLevelId(),stars)); - }else{ + }else { recordMap.put(currentFloorId, recordMap.get(currentFloorId).setLevelStars(getCurrentLevelId(),stars)); } getTowerData().currentLevel++; - if(!hasNextLevel()){ + if (!hasNextLevel()) { // set up the next floor recordMap.putIfAbsent(getNextFloorId(), new TowerLevelRecord(getNextFloorId())); player.getSession().send(new PacketTowerCurLevelRecordChangeNotify(getNextFloorId(), 1)); - }else{ + }else { player.getSession().send(new PacketTowerCurLevelRecordChangeNotify(currentFloorId, getCurrentLevel())); } } - public boolean hasNextLevel(){ + public boolean hasNextLevel() { return getTowerData().currentLevel < 3; } public int getNextFloorId() { return player.getServer().getTowerSystem().getNextFloorId(getTowerData().currentFloorId); } - public boolean hasNextFloor(){ + public boolean hasNextFloor() { return player.getServer().getTowerSystem().getNextFloorId(getTowerData().currentFloorId) > 0; } @@ -126,9 +126,9 @@ public class TowerManager extends BasePlayerManager { getTowerData().entryScene = 0; } - public boolean canEnterScheduleFloor(){ + public boolean canEnterScheduleFloor() { Map recordMap = getRecordMap(); - if(!recordMap.containsKey(player.getServer().getTowerSystem().getLastEntranceFloor())){ + if (!recordMap.containsKey(player.getServer().getTowerSystem().getLastEntranceFloor())) { return false; } return recordMap.get(player.getServer().getTowerSystem().getLastEntranceFloor()) diff --git a/src/main/java/emu/grasscutter/game/tower/TowerSystem.java b/src/main/java/emu/grasscutter/game/tower/TowerSystem.java index 2923dfd0b..1282d710a 100644 --- a/src/main/java/emu/grasscutter/game/tower/TowerSystem.java +++ b/src/main/java/emu/grasscutter/game/tower/TowerSystem.java @@ -16,7 +16,7 @@ import java.util.ArrayList; import java.util.List; public class TowerSystem extends BaseGameSystem { - + public TowerSystem(GameServer server) { super(server); this.load(); @@ -24,7 +24,7 @@ public class TowerSystem extends BaseGameSystem { private TowerScheduleConfig towerScheduleConfig; - public synchronized void load(){ + public synchronized void load() { try (Reader fileReader = DataLoader.loadReader("TowerSchedule.json")) { towerScheduleConfig = Grasscutter.getGsonFactory().fromJson(fileReader, TowerScheduleConfig.class); } catch (Exception e) { @@ -36,13 +36,13 @@ public class TowerSystem extends BaseGameSystem { return towerScheduleConfig; } - public TowerScheduleData getCurrentTowerScheduleData(){ + public TowerScheduleData getCurrentTowerScheduleData() { var data = GameData.getTowerScheduleDataMap().get(towerScheduleConfig.getScheduleId()); - if(data == null){ + if (data == null) { Grasscutter.getLogger().error("Could not get current tower schedule data by schedule id {}, please check your resource files", towerScheduleConfig.getScheduleId()); } - + return data; } @@ -56,29 +56,29 @@ public class TowerSystem extends BaseGameSystem { return getCurrentTowerScheduleData().getSchedules().get(0).getFloorList(); } - public int getNextFloorId(int floorId){ + public int getNextFloorId(int floorId) { var entranceFloors = getCurrentTowerScheduleData().getEntranceFloorId(); var scheduleFloors = getScheduleFloors(); var nextId = 0; - + // find in entrance floors first - for(int i=0;i players; - private final Map entities; - private final Set spawnedEntities; - private final Set deadSpawnedEntities; - private final Set loadedBlocks; - private Set loadedGridBlocks; - private boolean dontDestroyWhenEmpty; - - private int autoCloseTime; - private int time; - - private SceneScriptManager scriptManager; - private WorldChallenge challenge; - private List dungeonSettleListeners; - private DungeonData dungeonData; - private int prevScene; // Id of the previous scene - private int prevScenePoint; - private Set npcBornEntrySet; - public Scene(World world, SceneData sceneData) { - this.world = world; - this.sceneData = sceneData; - this.players = new CopyOnWriteArrayList<>(); - this.entities = new ConcurrentHashMap<>(); - - this.time = 8 * 60; - this.prevScene = 3; - - this.spawnedEntities = ConcurrentHashMap.newKeySet(); - this.deadSpawnedEntities = ConcurrentHashMap.newKeySet(); - this.loadedBlocks = ConcurrentHashMap.newKeySet(); - this.loadedGridBlocks = new HashSet<>(); - this.npcBornEntrySet = ConcurrentHashMap.newKeySet(); - this.scriptManager = new SceneScriptManager(this); - } - - public int getId() { - return sceneData.getId(); - } - - public World getWorld() { - return world; - } - - public SceneData getSceneData() { - return this.sceneData; - } - - public SceneType getSceneType() { - return getSceneData().getSceneType(); - } - - public List getPlayers() { - return players; - } - - public int getPlayerCount() { - return this.getPlayers().size(); - } - - public Map getEntities() { - return entities; - } - - public GameEntity getEntityById(int id) { - return this.entities.get(id); - } - - public GameEntity getEntityByConfigId(int configId) { - return this.entities.values().stream() - .filter(x -> x.getConfigId() == configId) - .findFirst() - .orElse(null); - } - /** - * @return the autoCloseTime - */ - public int getAutoCloseTime() { - return autoCloseTime; - } - - /** - * @param autoCloseTime the autoCloseTime to set - */ - public void setAutoCloseTime(int autoCloseTime) { - this.autoCloseTime = autoCloseTime; - } - - public int getTime() { - return time; - } - - public void changeTime(int time) { - this.time = time % 1440; - } - - public int getPrevScene() { - return prevScene; - } - - public void setPrevScene(int prevScene) { - this.prevScene = prevScene; - } - - public int getPrevScenePoint() { - return prevScenePoint; - } - - public void setPrevScenePoint(int prevPoint) { - this.prevScenePoint = prevPoint; - } - - public boolean dontDestroyWhenEmpty() { - return dontDestroyWhenEmpty; - } - - public void setDontDestroyWhenEmpty(boolean dontDestroyWhenEmpty) { - this.dontDestroyWhenEmpty = dontDestroyWhenEmpty; - } - - public Set getLoadedBlocks() { - return loadedBlocks; - } - - public Set getSpawnedEntities() { - return spawnedEntities; - } - - public Set getDeadSpawnedEntities() { - return deadSpawnedEntities; - } - - public SceneScriptManager getScriptManager() { - return scriptManager; - } - - public DungeonData getDungeonData() { - return dungeonData; - } - - public void setDungeonData(DungeonData dungeonData) { - if (dungeonData == null || this.dungeonData != null || this.getSceneType() != SceneType.SCENE_DUNGEON || dungeonData.getSceneId() != this.getId()) { - return; - } - this.dungeonData = dungeonData; - } - - public WorldChallenge getChallenge() { - return challenge; - } - - public void setChallenge(WorldChallenge challenge) { - this.challenge = challenge; - } - - public void addDungeonSettleObserver(DungeonSettleListener dungeonSettleListener){ - if(dungeonSettleListeners == null){ - dungeonSettleListeners = new ArrayList<>(); - } - dungeonSettleListeners.add(dungeonSettleListener); - } - - public List getDungeonSettleObservers() { - return dungeonSettleListeners; - } - - public boolean isInScene(GameEntity entity) { - return this.entities.containsKey(entity.getId()); - } - - public synchronized void addPlayer(Player player) { - // Check if player already in - if (getPlayers().contains(player)) { - return; - } - - // Remove player from prev scene - if (player.getScene() != null) { - player.getScene().removePlayer(player); - } - - // Add - getPlayers().add(player); - player.setSceneId(this.getId()); - player.setScene(this); - - this.setupPlayerAvatars(player); - } - - public synchronized void removePlayer(Player player) { - // Remove from challenge if leaving - if (this.getChallenge() != null && this.getChallenge().inProgress()) { - player.sendPacket(new PacketDungeonChallengeFinishNotify(this.getChallenge())); - } - - // Remove player from scene - getPlayers().remove(player); - player.setScene(null); - - // Remove player avatars - this.removePlayerAvatars(player); - - // Remove player gadgets - for (EntityBaseGadget gadget : player.getTeamManager().getGadgets()) { - this.removeEntity(gadget); - } - - // Deregister scene if not in use - if (this.getPlayerCount() <= 0 && !this.dontDestroyWhenEmpty()) { - this.getWorld().deregisterScene(this); - } - } - - private void setupPlayerAvatars(Player player) { - // Clear entities from old team - player.getTeamManager().getActiveTeam().clear(); - - // Add new entities for player - TeamInfo teamInfo = player.getTeamManager().getCurrentTeamInfo(); - for (int avatarId : teamInfo.getAvatars()) { - EntityAvatar entity = new EntityAvatar(player.getScene(), player.getAvatars().getAvatarById(avatarId)); - player.getTeamManager().getActiveTeam().add(entity); - } - - // Limit character index in case its out of bounds - if (player.getTeamManager().getCurrentCharacterIndex() >= player.getTeamManager().getActiveTeam().size() || player.getTeamManager().getCurrentCharacterIndex() < 0) { - player.getTeamManager().setCurrentCharacterIndex(player.getTeamManager().getCurrentCharacterIndex() - 1); - } - } - - private void removePlayerAvatars(Player player) { - Iterator it = player.getTeamManager().getActiveTeam().iterator(); - while (it.hasNext()) { - this.removeEntity(it.next(), VisionType.VISION_TYPE_REMOVE); - it.remove(); - } - } - - public void spawnPlayer(Player player) { - if (this.isInScene(player.getTeamManager().getCurrentAvatarEntity())) { - return; - } - - if (player.getTeamManager().getCurrentAvatarEntity().getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) <= 0f) { - player.getTeamManager().getCurrentAvatarEntity().setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, 1f); - } - - this.addEntity(player.getTeamManager().getCurrentAvatarEntity()); - - // Notify the client of any extra skill charges - for (EntityAvatar entity : player.getTeamManager().getActiveTeam()) { - if (entity.getAvatar().getSkillExtraChargeMap().size() > 0) { - player.sendPacket(new PacketAvatarSkillInfoNotify(entity.getAvatar())); - } - } - } - - private void addEntityDirectly(GameEntity entity) { - getEntities().put(entity.getId(), entity); - entity.onCreate(); // Call entity create event - } - - public synchronized void addEntity(GameEntity entity) { - this.addEntityDirectly(entity); - this.broadcastPacket(new PacketSceneEntityAppearNotify(entity)); - } - - public synchronized void addEntityToSingleClient(Player player, GameEntity entity) { - this.addEntityDirectly(entity); - player.sendPacket(new PacketSceneEntityAppearNotify(entity)); - - } - public void addEntities(Collection entities){ - addEntities(entities, VisionType.VISION_TYPE_BORN); - } - - public synchronized void addEntities(Collection entities, VisionType visionType) { - if(entities == null || entities.isEmpty()){ - return; - } - for (GameEntity entity : entities) { - this.addEntityDirectly(entity); - } - - this.broadcastPacket(new PacketSceneEntityAppearNotify(entities, visionType)); - } - - private GameEntity removeEntityDirectly(GameEntity entity) { - return getEntities().remove(entity.getId()); - } - - public void removeEntity(GameEntity entity) { - this.removeEntity(entity, VisionType.VISION_TYPE_DIE); - } - - public synchronized void removeEntity(GameEntity entity, VisionType visionType) { - GameEntity removed = this.removeEntityDirectly(entity); - if (removed != null) { - this.broadcastPacket(new PacketSceneEntityDisappearNotify(removed, visionType)); - } - } - public synchronized void removeEntities(List entity, VisionType visionType) { - var toRemove = entity.stream() - .map(this::removeEntityDirectly) - .toList(); - if (toRemove.size() > 0) { - this.broadcastPacket(new PacketSceneEntityDisappearNotify(toRemove, visionType)); - } - } - public synchronized void replaceEntity(EntityAvatar oldEntity, EntityAvatar newEntity) { - this.removeEntityDirectly(oldEntity); - this.addEntityDirectly(newEntity); - this.broadcastPacket(new PacketSceneEntityDisappearNotify(oldEntity, VisionType.VISION_TYPE_REPLACE)); - this.broadcastPacket(new PacketSceneEntityAppearNotify(newEntity, VisionType.VISION_TYPE_REPLACE, oldEntity.getId())); - } - - public void showOtherEntities(Player player) { - List entities = new LinkedList<>(); - GameEntity currentEntity = player.getTeamManager().getCurrentAvatarEntity(); - - for (GameEntity entity : this.getEntities().values()) { - if (entity == currentEntity) { - continue; - } - entities.add(entity); - } - - player.sendPacket(new PacketSceneEntityAppearNotify(entities, VisionType.VISION_TYPE_MEET)); - } - - public void handleAttack(AttackResult result) { - //GameEntity attacker = getEntityById(result.getAttackerId()); - GameEntity target = getEntityById(result.getDefenseId()); - - if (target == null) { - return; - } - - // Godmode check - if (target instanceof EntityAvatar) { - if (((EntityAvatar) target).getPlayer().inGodmode()) { - return; - } - } - - // Sanity check - target.damage(result.getDamage(), result.getAttackerId()); - } - - public void killEntity(GameEntity target) { - killEntity(target, 0); - } - - public void killEntity(GameEntity target, int attackerId) { - GameEntity attacker = null; - - if (attackerId > 0) { - attacker = getEntityById(attackerId); - } - - if (attacker != null) { - // Check codex - if (attacker instanceof EntityClientGadget gadgetAttacker) { - var clientGadgetOwner = getEntityById(gadgetAttacker.getOwnerEntityId()); - if (clientGadgetOwner instanceof EntityAvatar) { - ((EntityClientGadget) attacker).getOwner().getCodex().checkAnimal(target, CodexAnimalData.CodexAnimalUnlockCondition.CODEX_COUNT_TYPE_KILL); - } - } else if (attacker instanceof EntityAvatar avatarAttacker) { - avatarAttacker.getPlayer().getCodex().checkAnimal(target, CodexAnimalData.CodexAnimalUnlockCondition.CODEX_COUNT_TYPE_KILL); - } - } - - // Packet - this.broadcastPacket(new PacketLifeStateChangeNotify(attackerId, target, LifeState.LIFE_DEAD)); - - // Reward drop - if (target instanceof EntityMonster && this.getSceneType() != SceneType.SCENE_DUNGEON) { - getWorld().getServer().getDropSystem().callDrop((EntityMonster) target); - } - - // Remove entity from world - this.removeEntity(target); - - // Death event - target.onDeath(attackerId); - } - - public void onTick() { - // disable script for home - if (this.getSceneType() == SceneType.SCENE_HOME_WORLD || this.getSceneType() == SceneType.SCENE_HOME_ROOM){ - return; - } - if (this.getScriptManager().isInit()) { - this.checkBlocks(); - } else { - // TEMPORARY - this.checkSpawns(); - } - // Triggers - this.scriptManager.checkRegions(); - - if(challenge != null){ - challenge.onCheckTimeOut(); - } + private final World world; + private final SceneData sceneData; + private final List players; + private final Map entities; + private final Set spawnedEntities; + private final Set deadSpawnedEntities; + private final Set loadedBlocks; + private Set loadedGridBlocks; + private boolean dontDestroyWhenEmpty; + + private int autoCloseTime; + private int time; + + private SceneScriptManager scriptManager; + private WorldChallenge challenge; + private List dungeonSettleListeners; + private DungeonData dungeonData; + private int prevScene; // Id of the previous scene + private int prevScenePoint; + private Set npcBornEntrySet; + public Scene(World world, SceneData sceneData) { + this.world = world; + this.sceneData = sceneData; + this.players = new CopyOnWriteArrayList<>(); + this.entities = new ConcurrentHashMap<>(); + + this.time = 8 * 60; + this.prevScene = 3; + + this.spawnedEntities = ConcurrentHashMap.newKeySet(); + this.deadSpawnedEntities = ConcurrentHashMap.newKeySet(); + this.loadedBlocks = ConcurrentHashMap.newKeySet(); + this.loadedGridBlocks = new HashSet<>(); + this.npcBornEntrySet = ConcurrentHashMap.newKeySet(); + this.scriptManager = new SceneScriptManager(this); + } + + public int getId() { + return sceneData.getId(); + } + + public World getWorld() { + return world; + } + + public SceneData getSceneData() { + return this.sceneData; + } + + public SceneType getSceneType() { + return getSceneData().getSceneType(); + } + + public List getPlayers() { + return players; + } + + public int getPlayerCount() { + return this.getPlayers().size(); + } + + public Map getEntities() { + return entities; + } + + public GameEntity getEntityById(int id) { + return this.entities.get(id); + } + + public GameEntity getEntityByConfigId(int configId) { + return this.entities.values().stream() + .filter(x -> x.getConfigId() == configId) + .findFirst() + .orElse(null); + } + /** + * @return the autoCloseTime + */ + public int getAutoCloseTime() { + return autoCloseTime; + } + + /** + * @param autoCloseTime the autoCloseTime to set + */ + public void setAutoCloseTime(int autoCloseTime) { + this.autoCloseTime = autoCloseTime; + } + + public int getTime() { + return time; + } + + public void changeTime(int time) { + this.time = time % 1440; + } + + public int getPrevScene() { + return prevScene; + } + + public void setPrevScene(int prevScene) { + this.prevScene = prevScene; + } + + public int getPrevScenePoint() { + return prevScenePoint; + } + + public void setPrevScenePoint(int prevPoint) { + this.prevScenePoint = prevPoint; + } + + public boolean dontDestroyWhenEmpty() { + return dontDestroyWhenEmpty; + } + + public void setDontDestroyWhenEmpty(boolean dontDestroyWhenEmpty) { + this.dontDestroyWhenEmpty = dontDestroyWhenEmpty; + } + + public Set getLoadedBlocks() { + return loadedBlocks; + } + + public Set getSpawnedEntities() { + return spawnedEntities; + } + + public Set getDeadSpawnedEntities() { + return deadSpawnedEntities; + } + + public SceneScriptManager getScriptManager() { + return scriptManager; + } + + public DungeonData getDungeonData() { + return dungeonData; + } + + public void setDungeonData(DungeonData dungeonData) { + if (dungeonData == null || this.dungeonData != null || this.getSceneType() != SceneType.SCENE_DUNGEON || dungeonData.getSceneId() != this.getId()) { + return; + } + this.dungeonData = dungeonData; + } + + public WorldChallenge getChallenge() { + return challenge; + } + + public void setChallenge(WorldChallenge challenge) { + this.challenge = challenge; + } + + public void addDungeonSettleObserver(DungeonSettleListener dungeonSettleListener) { + if (dungeonSettleListeners == null) { + dungeonSettleListeners = new ArrayList<>(); + } + dungeonSettleListeners.add(dungeonSettleListener); + } + + public List getDungeonSettleObservers() { + return dungeonSettleListeners; + } + + public boolean isInScene(GameEntity entity) { + return this.entities.containsKey(entity.getId()); + } + + public synchronized void addPlayer(Player player) { + // Check if player already in + if (getPlayers().contains(player)) { + return; + } + + // Remove player from prev scene + if (player.getScene() != null) { + player.getScene().removePlayer(player); + } + + // Add + getPlayers().add(player); + player.setSceneId(this.getId()); + player.setScene(this); + + this.setupPlayerAvatars(player); + } + + public synchronized void removePlayer(Player player) { + // Remove from challenge if leaving + if (this.getChallenge() != null && this.getChallenge().inProgress()) { + player.sendPacket(new PacketDungeonChallengeFinishNotify(this.getChallenge())); + } + + // Remove player from scene + getPlayers().remove(player); + player.setScene(null); + + // Remove player avatars + this.removePlayerAvatars(player); + + // Remove player gadgets + for (EntityBaseGadget gadget : player.getTeamManager().getGadgets()) { + this.removeEntity(gadget); + } + + // Deregister scene if not in use + if (this.getPlayerCount() <= 0 && !this.dontDestroyWhenEmpty()) { + this.getWorld().deregisterScene(this); + } + } + + private void setupPlayerAvatars(Player player) { + // Clear entities from old team + player.getTeamManager().getActiveTeam().clear(); + + // Add new entities for player + TeamInfo teamInfo = player.getTeamManager().getCurrentTeamInfo(); + for (int avatarId : teamInfo.getAvatars()) { + EntityAvatar entity = new EntityAvatar(player.getScene(), player.getAvatars().getAvatarById(avatarId)); + player.getTeamManager().getActiveTeam().add(entity); + } + + // Limit character index in case its out of bounds + if (player.getTeamManager().getCurrentCharacterIndex() >= player.getTeamManager().getActiveTeam().size() || player.getTeamManager().getCurrentCharacterIndex() < 0) { + player.getTeamManager().setCurrentCharacterIndex(player.getTeamManager().getCurrentCharacterIndex() - 1); + } + } + + private void removePlayerAvatars(Player player) { + Iterator it = player.getTeamManager().getActiveTeam().iterator(); + while (it.hasNext()) { + this.removeEntity(it.next(), VisionType.VISION_TYPE_REMOVE); + it.remove(); + } + } + + public void spawnPlayer(Player player) { + if (this.isInScene(player.getTeamManager().getCurrentAvatarEntity())) { + return; + } + + if (player.getTeamManager().getCurrentAvatarEntity().getFightProperty(FightProperty.FIGHT_PROP_CUR_HP) <= 0f) { + player.getTeamManager().getCurrentAvatarEntity().setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, 1f); + } + + this.addEntity(player.getTeamManager().getCurrentAvatarEntity()); + + // Notify the client of any extra skill charges + for (EntityAvatar entity : player.getTeamManager().getActiveTeam()) { + if (entity.getAvatar().getSkillExtraChargeMap().size() > 0) { + player.sendPacket(new PacketAvatarSkillInfoNotify(entity.getAvatar())); + } + } + } + + private void addEntityDirectly(GameEntity entity) { + getEntities().put(entity.getId(), entity); + entity.onCreate(); // Call entity create event + } + + public synchronized void addEntity(GameEntity entity) { + this.addEntityDirectly(entity); + this.broadcastPacket(new PacketSceneEntityAppearNotify(entity)); + } + + public synchronized void addEntityToSingleClient(Player player, GameEntity entity) { + this.addEntityDirectly(entity); + player.sendPacket(new PacketSceneEntityAppearNotify(entity)); + + } + public void addEntities(Collection entities) { + addEntities(entities, VisionType.VISION_TYPE_BORN); + } + + public synchronized void addEntities(Collection entities, VisionType visionType) { + if (entities == null || entities.isEmpty()) { + return; + } + for (GameEntity entity : entities) { + this.addEntityDirectly(entity); + } + + this.broadcastPacket(new PacketSceneEntityAppearNotify(entities, visionType)); + } + + private GameEntity removeEntityDirectly(GameEntity entity) { + return getEntities().remove(entity.getId()); + } + + public void removeEntity(GameEntity entity) { + this.removeEntity(entity, VisionType.VISION_TYPE_DIE); + } + + public synchronized void removeEntity(GameEntity entity, VisionType visionType) { + GameEntity removed = this.removeEntityDirectly(entity); + if (removed != null) { + this.broadcastPacket(new PacketSceneEntityDisappearNotify(removed, visionType)); + } + } + public synchronized void removeEntities(List entity, VisionType visionType) { + var toRemove = entity.stream() + .map(this::removeEntityDirectly) + .toList(); + if (toRemove.size() > 0) { + this.broadcastPacket(new PacketSceneEntityDisappearNotify(toRemove, visionType)); + } + } + public synchronized void replaceEntity(EntityAvatar oldEntity, EntityAvatar newEntity) { + this.removeEntityDirectly(oldEntity); + this.addEntityDirectly(newEntity); + this.broadcastPacket(new PacketSceneEntityDisappearNotify(oldEntity, VisionType.VISION_TYPE_REPLACE)); + this.broadcastPacket(new PacketSceneEntityAppearNotify(newEntity, VisionType.VISION_TYPE_REPLACE, oldEntity.getId())); + } + + public void showOtherEntities(Player player) { + List entities = new LinkedList<>(); + GameEntity currentEntity = player.getTeamManager().getCurrentAvatarEntity(); + + for (GameEntity entity : this.getEntities().values()) { + if (entity == currentEntity) { + continue; + } + entities.add(entity); + } + + player.sendPacket(new PacketSceneEntityAppearNotify(entities, VisionType.VISION_TYPE_MEET)); + } + + public void handleAttack(AttackResult result) { + //GameEntity attacker = getEntityById(result.getAttackerId()); + GameEntity target = getEntityById(result.getDefenseId()); + + if (target == null) { + return; + } + + // Godmode check + if (target instanceof EntityAvatar) { + if (((EntityAvatar) target).getPlayer().inGodmode()) { + return; + } + } + + // Sanity check + target.damage(result.getDamage(), result.getAttackerId()); + } + + public void killEntity(GameEntity target) { + killEntity(target, 0); + } + + public void killEntity(GameEntity target, int attackerId) { + GameEntity attacker = null; + + if (attackerId > 0) { + attacker = getEntityById(attackerId); + } + + if (attacker != null) { + // Check codex + if (attacker instanceof EntityClientGadget gadgetAttacker) { + var clientGadgetOwner = getEntityById(gadgetAttacker.getOwnerEntityId()); + if (clientGadgetOwner instanceof EntityAvatar) { + ((EntityClientGadget) attacker).getOwner().getCodex().checkAnimal(target, CodexAnimalData.CodexAnimalUnlockCondition.CODEX_COUNT_TYPE_KILL); + } + } else if (attacker instanceof EntityAvatar avatarAttacker) { + avatarAttacker.getPlayer().getCodex().checkAnimal(target, CodexAnimalData.CodexAnimalUnlockCondition.CODEX_COUNT_TYPE_KILL); + } + } + + // Packet + this.broadcastPacket(new PacketLifeStateChangeNotify(attackerId, target, LifeState.LIFE_DEAD)); + + // Reward drop + if (target instanceof EntityMonster && this.getSceneType() != SceneType.SCENE_DUNGEON) { + getWorld().getServer().getDropSystem().callDrop((EntityMonster) target); + } + + // Remove entity from world + this.removeEntity(target); + + // Death event + target.onDeath(attackerId); + } + + public void onTick() { + // disable script for home + if (this.getSceneType() == SceneType.SCENE_HOME_WORLD || this.getSceneType() == SceneType.SCENE_HOME_ROOM) { + return; + } + if (this.getScriptManager().isInit()) { + this.checkBlocks(); + } else { + // TEMPORARY + this.checkSpawns(); + } + // Triggers + this.scriptManager.checkRegions(); + + if (challenge != null) { + challenge.onCheckTimeOut(); + } checkNpcGroup(); - } + } - public int getEntityLevel(int baseLevel, int worldLevelOverride) { - int level = worldLevelOverride > 0 ? worldLevelOverride + baseLevel - 22 : baseLevel; - level = level >= 100 ? 100 : level; - level = level <= 0 ? 1 : level; + public int getEntityLevel(int baseLevel, int worldLevelOverride) { + int level = worldLevelOverride > 0 ? worldLevelOverride + baseLevel - 22 : baseLevel; + level = level >= 100 ? 100 : level; + level = level <= 0 ? 1 : level; - return level; - } - public void checkNpcGroup(){ + return level; + } + public void checkNpcGroup() { Set npcBornEntries = ConcurrentHashMap.newKeySet(); for (Player player : this.getPlayers()) { npcBornEntries.addAll(loadNpcForPlayer(player)); @@ -458,7 +458,7 @@ public class Scene { .map(SceneNpcBornEntry::getGroupId) .toList(); - if(toUnload.size() > 0){ + if (toUnload.size() > 0) { broadcastPacket(new PacketGroupUnloadNotify(toUnload)); Grasscutter.getLogger().debug("Unload NPC Group {}", toUnload); } @@ -480,342 +480,342 @@ public class Scene { Set visible = new HashSet<>(); for (var block : loadedGridBlocks) { var spawns = spawnLists.get(block); - if(spawns!=null) { + if (spawns!=null) { visible.addAll(spawns); } } - // World level - WorldLevelData worldLevelData = GameData.getWorldLevelDataMap().get(getWorld().getWorldLevel()); - int worldLevelOverride = 0; + // World level + WorldLevelData worldLevelData = GameData.getWorldLevelDataMap().get(getWorld().getWorldLevel()); + int worldLevelOverride = 0; - if (worldLevelData != null) { - worldLevelOverride = worldLevelData.getMonsterLevel(); - } + if (worldLevelData != null) { + worldLevelOverride = worldLevelData.getMonsterLevel(); + } - // Todo - List toAdd = new LinkedList<>(); - List toRemove = new LinkedList<>(); + // Todo + List toAdd = new LinkedList<>(); + List toRemove = new LinkedList<>(); var spawnedEntities = this.getSpawnedEntities(); - for (SpawnDataEntry entry : visible) { - // If spawn entry is in our view and hasnt been spawned/killed yet, we should spawn it - if (!spawnedEntities.contains(entry) && !this.getDeadSpawnedEntities().contains(entry)) { - // Entity object holder - GameEntity entity = null; + for (SpawnDataEntry entry : visible) { + // If spawn entry is in our view and hasnt been spawned/killed yet, we should spawn it + if (!spawnedEntities.contains(entry) && !this.getDeadSpawnedEntities().contains(entry)) { + // Entity object holder + GameEntity entity = null; - // Check if spawn entry is monster or gadget - if (entry.getMonsterId() > 0) { - MonsterData data = GameData.getMonsterDataMap().get(entry.getMonsterId()); - if (data == null) continue; + // Check if spawn entry is monster or gadget + if (entry.getMonsterId() > 0) { + MonsterData data = GameData.getMonsterDataMap().get(entry.getMonsterId()); + if (data == null) continue; - int level = this.getEntityLevel(entry.getLevel(), worldLevelOverride); + int level = this.getEntityLevel(entry.getLevel(), worldLevelOverride); - EntityMonster monster = new EntityMonster(this, data, entry.getPos(), level); - monster.getRotation().set(entry.getRot()); - monster.setGroupId(entry.getGroup().getGroupId()); - monster.setPoseId(entry.getPoseId()); - monster.setConfigId(entry.getConfigId()); - monster.setSpawnEntry(entry); + EntityMonster monster = new EntityMonster(this, data, entry.getPos(), level); + monster.getRotation().set(entry.getRot()); + monster.setGroupId(entry.getGroup().getGroupId()); + monster.setPoseId(entry.getPoseId()); + monster.setConfigId(entry.getConfigId()); + monster.setSpawnEntry(entry); - entity = monster; - } else if (entry.getGadgetId() > 0) { - EntityGadget gadget = new EntityGadget(this, entry.getGadgetId(), entry.getPos(), entry.getRot()); - gadget.setGroupId(entry.getGroup().getGroupId()); - gadget.setConfigId(entry.getConfigId()); - gadget.setSpawnEntry(entry); - int state = entry.getGadgetState(); - if(state>0) { + entity = monster; + } else if (entry.getGadgetId() > 0) { + EntityGadget gadget = new EntityGadget(this, entry.getGadgetId(), entry.getPos(), entry.getRot()); + gadget.setGroupId(entry.getGroup().getGroupId()); + gadget.setConfigId(entry.getConfigId()); + gadget.setSpawnEntry(entry); + int state = entry.getGadgetState(); + if (state>0) { gadget.setState(state); } - gadget.buildContent(); + gadget.buildContent(); - gadget.setFightProperty(FightProperty.FIGHT_PROP_BASE_HP, 99999); - gadget.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, 99999); - gadget.setFightProperty(FightProperty.FIGHT_PROP_MAX_HP, 99999); + gadget.setFightProperty(FightProperty.FIGHT_PROP_BASE_HP, 99999); + gadget.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, 99999); + gadget.setFightProperty(FightProperty.FIGHT_PROP_MAX_HP, 99999); - entity = gadget; - } + entity = gadget; + } - if (entity == null) continue; + if (entity == null) continue; - // Add to scene and spawned list - toAdd.add(entity); + // Add to scene and spawned list + toAdd.add(entity); spawnedEntities.add(entry); - } - } + } + } - for (GameEntity entity : this.getEntities().values()) { - var spawnEntry = entity.getSpawnEntry(); - if (spawnEntry != null && !visible.contains(spawnEntry)) { - toRemove.add(entity); + for (GameEntity entity : this.getEntities().values()) { + var spawnEntry = entity.getSpawnEntry(); + if (spawnEntry != null && !visible.contains(spawnEntry)) { + toRemove.add(entity); spawnedEntities.remove(spawnEntry); - } - } + } + } - if (toAdd.size() > 0) { - toAdd.stream().forEach(this::addEntityDirectly); - this.broadcastPacket(new PacketSceneEntityAppearNotify(toAdd, VisionType.VISION_TYPE_BORN)); - } - if (toRemove.size() > 0) { - toRemove.stream().forEach(this::removeEntityDirectly); - this.broadcastPacket(new PacketSceneEntityDisappearNotify(toRemove, VisionType.VISION_TYPE_REMOVE)); - } - } + if (toAdd.size() > 0) { + toAdd.stream().forEach(this::addEntityDirectly); + this.broadcastPacket(new PacketSceneEntityAppearNotify(toAdd, VisionType.VISION_TYPE_BORN)); + } + if (toRemove.size() > 0) { + toRemove.stream().forEach(this::removeEntityDirectly); + this.broadcastPacket(new PacketSceneEntityDisappearNotify(toRemove, VisionType.VISION_TYPE_REMOVE)); + } + } - public List getPlayerActiveBlocks(Player player){ - // consider the borders' entities of blocks, so we check if contains by index - return SceneIndexManager.queryNeighbors(getScriptManager().getBlocksIndex(), - player.getPosition().toXZDoubleArray(), Grasscutter.getConfig().server.game.loadEntitiesForPlayerRange); - } - public void checkBlocks() { - Set visible = new HashSet<>(); - for (Player player : this.getPlayers()) { - var blocks = getPlayerActiveBlocks(player); - visible.addAll(blocks); - } + public List getPlayerActiveBlocks(Player player) { + // consider the borders' entities of blocks, so we check if contains by index + return SceneIndexManager.queryNeighbors(getScriptManager().getBlocksIndex(), + player.getPosition().toXZDoubleArray(), Grasscutter.getConfig().server.game.loadEntitiesForPlayerRange); + } + public void checkBlocks() { + Set visible = new HashSet<>(); + for (Player player : this.getPlayers()) { + var blocks = getPlayerActiveBlocks(player); + visible.addAll(blocks); + } - Iterator it = this.getLoadedBlocks().iterator(); - while (it.hasNext()) { - SceneBlock block = it.next(); + Iterator it = this.getLoadedBlocks().iterator(); + while (it.hasNext()) { + SceneBlock block = it.next(); - if (!visible.contains(block)) { - it.remove(); + if (!visible.contains(block)) { + it.remove(); - onUnloadBlock(block); - } - } + onUnloadBlock(block); + } + } - for(var block : visible){ - if (!this.getLoadedBlocks().contains(block)) { - this.onLoadBlock(block, this.getPlayers()); - this.getLoadedBlocks().add(block); - }else{ - // dynamic load the groups for players in a loaded block - var toLoad = this.getPlayers().stream() - .filter(p -> block.contains(p.getPosition())) - .map(p -> playerMeetGroups(p, block)) - .flatMap(Collection::stream) - .toList(); - onLoadGroup(toLoad); - } - } + for (var block : visible) { + if (!this.getLoadedBlocks().contains(block)) { + this.onLoadBlock(block, this.getPlayers()); + this.getLoadedBlocks().add(block); + }else { + // dynamic load the groups for players in a loaded block + var toLoad = this.getPlayers().stream() + .filter(p -> block.contains(p.getPosition())) + .map(p -> playerMeetGroups(p, block)) + .flatMap(Collection::stream) + .toList(); + onLoadGroup(toLoad); + } + } - } - public List playerMeetGroups(Player player, SceneBlock block){ - List sceneGroups = SceneIndexManager.queryNeighbors(block.sceneGroupIndex, player.getPosition().toDoubleArray(), - Grasscutter.getConfig().server.game.loadEntitiesForPlayerRange); + } + public List playerMeetGroups(Player player, SceneBlock block) { + List sceneGroups = SceneIndexManager.queryNeighbors(block.sceneGroupIndex, player.getPosition().toDoubleArray(), + Grasscutter.getConfig().server.game.loadEntitiesForPlayerRange); - List groups = sceneGroups.stream() - .filter(group -> !scriptManager.getLoadedGroupSetPerBlock().get(block.id).contains(group)) - .peek(group -> scriptManager.getLoadedGroupSetPerBlock().get(block.id).add(group)) - .toList(); + List groups = sceneGroups.stream() + .filter(group -> !scriptManager.getLoadedGroupSetPerBlock().get(block.id).contains(group)) + .peek(group -> scriptManager.getLoadedGroupSetPerBlock().get(block.id).add(group)) + .toList(); - if (groups.size() == 0) { - return List.of(); - } + if (groups.size() == 0) { + return List.of(); + } - return groups; - } - public void onLoadBlock(SceneBlock block, List players) { - this.getScriptManager().loadBlockFromScript(block); - scriptManager.getLoadedGroupSetPerBlock().put(block.id , new HashSet<>()); + return groups; + } + public void onLoadBlock(SceneBlock block, List players) { + this.getScriptManager().loadBlockFromScript(block); + scriptManager.getLoadedGroupSetPerBlock().put(block.id , new HashSet<>()); - // the groups form here is not added in current scene - var groups = players.stream() - .filter(player -> block.contains(player.getPosition())) - .map(p -> playerMeetGroups(p, block)) - .flatMap(Collection::stream) - .toList(); + // the groups form here is not added in current scene + var groups = players.stream() + .filter(player -> block.contains(player.getPosition())) + .map(p -> playerMeetGroups(p, block)) + .flatMap(Collection::stream) + .toList(); - onLoadGroup(groups); - Grasscutter.getLogger().info("Scene {} Block {} loaded.", this.getId(), block.id); - } + onLoadGroup(groups); + Grasscutter.getLogger().info("Scene {} Block {} loaded.", this.getId(), block.id); + } - public void onLoadGroup(List groups){ - if(groups == null || groups.isEmpty()){ - return; - } - for (SceneGroup group : groups) { - // We load the script files for the groups here - this.getScriptManager().loadGroupFromScript(group); - } + public void onLoadGroup(List groups) { + if (groups == null || groups.isEmpty()) { + return; + } + for (SceneGroup group : groups) { + // We load the script files for the groups here + this.getScriptManager().loadGroupFromScript(group); + } - // Spawn gadgets AFTER triggers are added - // TODO - var entities = new ArrayList(); - for (SceneGroup group : groups) { - if (group.init_config == null) { - continue; - } + // Spawn gadgets AFTER triggers are added + // TODO + var entities = new ArrayList(); + for (SceneGroup group : groups) { + if (group.init_config == null) { + continue; + } - // Load garbages - List garbageGadgets = group.getGarbageGadgets(); + // Load garbages + List garbageGadgets = group.getGarbageGadgets(); - if (garbageGadgets != null) { - entities.addAll(garbageGadgets.stream().map(g -> scriptManager.createGadget(group.id, group.block_id, g)) - .filter(Objects::nonNull) - .toList()); - } + if (garbageGadgets != null) { + entities.addAll(garbageGadgets.stream().map(g -> scriptManager.createGadget(group.id, group.block_id, g)) + .filter(Objects::nonNull) + .toList()); + } - // Load suites - int suite = group.init_config.suite; + // Load suites + int suite = group.init_config.suite; - if (suite == 0 || group.suites == null || group.suites.size() == 0) { - continue; - } + if (suite == 0 || group.suites == null || group.suites.size() == 0) { + continue; + } - // just load the 'init' suite, avoid spawn the suite added by AddExtraGroupSuite etc. - var suiteData = group.getSuiteByIndex(suite); - suiteData.sceneTriggers.forEach(getScriptManager()::registerTrigger); + // just load the 'init' suite, avoid spawn the suite added by AddExtraGroupSuite etc. + var suiteData = group.getSuiteByIndex(suite); + suiteData.sceneTriggers.forEach(getScriptManager()::registerTrigger); - entities.addAll(scriptManager.getGadgetsInGroupSuite(group, suiteData)); - entities.addAll(scriptManager.getMonstersInGroupSuite(group, suiteData)); + entities.addAll(scriptManager.getGadgetsInGroupSuite(group, suiteData)); + entities.addAll(scriptManager.getMonstersInGroupSuite(group, suiteData)); scriptManager.registerRegionInGroupSuite(group, suiteData); - } + } - scriptManager.meetEntities(entities); - //scriptManager.callEvent(EventType.EVENT_GROUP_LOAD, null); - //groups.forEach(g -> scriptManager.callEvent(EventType.EVENT_GROUP_LOAD, null)); - Grasscutter.getLogger().info("Scene {} loaded {} group(s)", this.getId(), groups.size()); - } + scriptManager.meetEntities(entities); + //scriptManager.callEvent(EventType.EVENT_GROUP_LOAD, null); + //groups.forEach(g -> scriptManager.callEvent(EventType.EVENT_GROUP_LOAD, null)); + Grasscutter.getLogger().info("Scene {} loaded {} group(s)", this.getId(), groups.size()); + } - public void onUnloadBlock(SceneBlock block) { - List toRemove = this.getEntities().values().stream() - .filter(e -> e.getBlockId() == block.id).toList(); + public void onUnloadBlock(SceneBlock block) { + List toRemove = this.getEntities().values().stream() + .filter(e -> e.getBlockId() == block.id).toList(); - if (toRemove.size() > 0) { - toRemove.forEach(this::removeEntityDirectly); - this.broadcastPacket(new PacketSceneEntityDisappearNotify(toRemove, VisionType.VISION_TYPE_REMOVE)); - } + if (toRemove.size() > 0) { + toRemove.forEach(this::removeEntityDirectly); + this.broadcastPacket(new PacketSceneEntityDisappearNotify(toRemove, VisionType.VISION_TYPE_REMOVE)); + } - for (SceneGroup group : block.groups.values()) { - if(group.triggers != null){ - group.triggers.values().forEach(getScriptManager()::deregisterTrigger); - } - if(group.regions != null){ + for (SceneGroup group : block.groups.values()) { + if (group.triggers != null) { + group.triggers.values().forEach(getScriptManager()::deregisterTrigger); + } + if (group.regions != null) { group.regions.values().forEach(getScriptManager()::deregisterRegion); - } - } - scriptManager.getLoadedGroupSetPerBlock().remove(block.id); - Grasscutter.getLogger().info("Scene {} Block {} is unloaded.", this.getId(), block.id); - } - // Gadgets + } + } + scriptManager.getLoadedGroupSetPerBlock().remove(block.id); + Grasscutter.getLogger().info("Scene {} Block {} is unloaded.", this.getId(), block.id); + } + // Gadgets - public void onPlayerCreateGadget(EntityClientGadget gadget) { - // Directly add - this.addEntityDirectly(gadget); + public void onPlayerCreateGadget(EntityClientGadget gadget) { + // Directly add + this.addEntityDirectly(gadget); - // Add to owner's gadget list - gadget.getOwner().getTeamManager().getGadgets().add(gadget); + // Add to owner's gadget list + gadget.getOwner().getTeamManager().getGadgets().add(gadget); - // Optimization - if (this.getPlayerCount() == 1 && this.getPlayers().get(0) == gadget.getOwner()) { - return; - } + // Optimization + if (this.getPlayerCount() == 1 && this.getPlayers().get(0) == gadget.getOwner()) { + return; + } - this.broadcastPacketToOthers(gadget.getOwner(), new PacketSceneEntityAppearNotify(gadget)); - } + this.broadcastPacketToOthers(gadget.getOwner(), new PacketSceneEntityAppearNotify(gadget)); + } - public void onPlayerDestroyGadget(int entityId) { - GameEntity entity = getEntities().get(entityId); + public void onPlayerDestroyGadget(int entityId) { + GameEntity entity = getEntities().get(entityId); - if (entity == null || !(entity instanceof EntityClientGadget)) { - return; - } + if (entity == null || !(entity instanceof EntityClientGadget)) { + return; + } - // Get and remove entity - EntityClientGadget gadget = (EntityClientGadget) entity; - this.removeEntityDirectly(gadget); + // Get and remove entity + EntityClientGadget gadget = (EntityClientGadget) entity; + this.removeEntityDirectly(gadget); - // Remove from owner's gadget list - gadget.getOwner().getTeamManager().getGadgets().remove(gadget); + // Remove from owner's gadget list + gadget.getOwner().getTeamManager().getGadgets().remove(gadget); - // Optimization - if (this.getPlayerCount() == 1 && this.getPlayers().get(0) == gadget.getOwner()) { - return; - } + // Optimization + if (this.getPlayerCount() == 1 && this.getPlayers().get(0) == gadget.getOwner()) { + return; + } - this.broadcastPacketToOthers(gadget.getOwner(), new PacketSceneEntityDisappearNotify(gadget, VisionType.VISION_TYPE_DIE)); - } + this.broadcastPacketToOthers(gadget.getOwner(), new PacketSceneEntityDisappearNotify(gadget, VisionType.VISION_TYPE_DIE)); + } - // Broadcasting + // Broadcasting - public void broadcastPacket(BasePacket packet) { - // Send to all players - might have to check if player has been sent data packets - for (Player player : this.getPlayers()) { - player.getSession().send(packet); - } - } + public void broadcastPacket(BasePacket packet) { + // Send to all players - might have to check if player has been sent data packets + for (Player player : this.getPlayers()) { + player.getSession().send(packet); + } + } - public void broadcastPacketToOthers(Player excludedPlayer, BasePacket packet) { - // Optimization - if (this.getPlayerCount() == 1 && this.getPlayers().get(0) == excludedPlayer) { - return; - } - // Send to all players - might have to check if player has been sent data packets - for (Player player : this.getPlayers()) { - if (player == excludedPlayer) { - continue; - } - // Send - player.getSession().send(packet); - } - } + public void broadcastPacketToOthers(Player excludedPlayer, BasePacket packet) { + // Optimization + if (this.getPlayerCount() == 1 && this.getPlayers().get(0) == excludedPlayer) { + return; + } + // Send to all players - might have to check if player has been sent data packets + for (Player player : this.getPlayers()) { + if (player == excludedPlayer) { + continue; + } + // Send + player.getSession().send(packet); + } + } - public void addItemEntity(int itemId, int amount, GameEntity bornForm){ - ItemData itemData = GameData.getItemDataMap().get(itemId); - if (itemData == null) { - return; - } - if (itemData.isEquip()) { - float range = (3f + (.1f * amount)); - for (int i = 0; i < amount; i++) { - Position pos = bornForm.getPosition().clone().addX((float) (Math.random() * range) - (range / 2)).addZ((float) (Math.random() * range) - (range / 2)).addZ(.9f); - EntityItem entity = new EntityItem(this, null, itemData, pos, 1); - addEntity(entity); - } - } else { - EntityItem entity = new EntityItem(this, null, itemData, bornForm.getPosition().clone().addZ(.9f), amount); - addEntity(entity); - } - } - public void loadNpcForPlayerEnter(Player player){ + public void addItemEntity(int itemId, int amount, GameEntity bornForm) { + ItemData itemData = GameData.getItemDataMap().get(itemId); + if (itemData == null) { + return; + } + if (itemData.isEquip()) { + float range = (3f + (.1f * amount)); + for (int i = 0; i < amount; i++) { + Position pos = bornForm.getPosition().clone().addX((float) (Math.random() * range) - (range / 2)).addZ((float) (Math.random() * range) - (range / 2)).addZ(.9f); + EntityItem entity = new EntityItem(this, null, itemData, pos, 1); + addEntity(entity); + } + } else { + EntityItem entity = new EntityItem(this, null, itemData, bornForm.getPosition().clone().addZ(.9f), amount); + addEntity(entity); + } + } + public void loadNpcForPlayerEnter(Player player) { this.npcBornEntrySet.addAll(loadNpcForPlayer(player)); } - private List loadNpcForPlayer(Player player){ - var pos = player.getPosition(); - var data = GameData.getSceneNpcBornData().get(getId()); - if(data == null){ - return List.of(); - } + private List loadNpcForPlayer(Player player) { + var pos = player.getPosition(); + var data = GameData.getSceneNpcBornData().get(getId()); + if (data == null) { + return List.of(); + } - var npcList = SceneIndexManager.queryNeighbors(data.getIndex(), pos.toDoubleArray(), - Grasscutter.getConfig().server.game.loadEntitiesForPlayerRange); + var npcList = SceneIndexManager.queryNeighbors(data.getIndex(), pos.toDoubleArray(), + Grasscutter.getConfig().server.game.loadEntitiesForPlayerRange); - var sceneNpcBornEntries = npcList.stream() + var sceneNpcBornEntries = npcList.stream() .filter(i -> !this.npcBornEntrySet.contains(i)) .toList(); - if(sceneNpcBornEntries.size() > 0){ - this.broadcastPacket(new PacketGroupSuiteNotify(sceneNpcBornEntries)); + if (sceneNpcBornEntries.size() > 0) { + this.broadcastPacket(new PacketGroupSuiteNotify(sceneNpcBornEntries)); Grasscutter.getLogger().debug("Loaded Npc Group Suite {}", sceneNpcBornEntries); - } + } return npcList; - } + } public void loadGroupForQuest(List sceneGroupSuite) { - if(!scriptManager.isInit()){ + if (!scriptManager.isInit()) { return; } sceneGroupSuite.forEach(i -> { var group = scriptManager.getGroupById(i.getGroup()); - if(group == null){ + if (group == null) { return; } var suite = group.getSuiteByIndex(i.getSuite()); - if(suite == null){ + if (suite == null) { return; } scriptManager.addGroupSuite(group, suite); diff --git a/src/main/java/emu/grasscutter/game/world/SpawnDataEntry.java b/src/main/java/emu/grasscutter/game/world/SpawnDataEntry.java index 456197c7c..f4d5efd4f 100644 --- a/src/main/java/emu/grasscutter/game/world/SpawnDataEntry.java +++ b/src/main/java/emu/grasscutter/game/world/SpawnDataEntry.java @@ -7,62 +7,62 @@ import emu.grasscutter.data.GameDepot; import emu.grasscutter.utils.Position; public class SpawnDataEntry { - private transient SpawnGroupEntry group; - private int monsterId; - private int gadgetId; - private int configId; - private int level; - private int poseId; - private int gatherItemId; + private transient SpawnGroupEntry group; + private int monsterId; + private int gadgetId; + private int configId; + private int level; + private int poseId; + private int gatherItemId; private int gadgetState; - private Position pos; - private Position rot; + private Position pos; + private Position rot; - public SpawnGroupEntry getGroup() { - return group; - } + public SpawnGroupEntry getGroup() { + return group; + } - public void setGroup(SpawnGroupEntry group) { - this.group = group; - } + public void setGroup(SpawnGroupEntry group) { + this.group = group; + } - public int getMonsterId() { - return monsterId; - } + public int getMonsterId() { + return monsterId; + } - public int getGadgetId() { - return gadgetId; - } + public int getGadgetId() { + return gadgetId; + } public int getGadgetState() { return gadgetState; } public int getConfigId() { - return configId; - } + return configId; + } - public int getLevel() { - return level; - } + public int getLevel() { + return level; + } - public int getPoseId() { - return poseId; - } + public int getPoseId() { + return poseId; + } - public int getGatherItemId() { - return gatherItemId; - } + public int getGatherItemId() { + return gatherItemId; + } - public Position getPos() { - return pos; - } + public Position getPos() { + return pos; + } - public Position getRot() { - return rot; - } + public Position getRot() { + return rot; + } - public GridBlockId getBlockId(){ + public GridBlockId getBlockId() { int scale = GridBlockId.getScale(gadgetId); return new GridBlockId(group.sceneId,scale, (int)(pos.getX() / GameDepot.BLOCK_SIZE[scale]), @@ -70,32 +70,32 @@ public class SpawnDataEntry { ); } - public static class SpawnGroupEntry { - private int sceneId; - private int groupId; - private int blockId; - private List spawns; + public static class SpawnGroupEntry { + private int sceneId; + private int groupId; + private int blockId; + private List spawns; - public int getSceneId() { - return sceneId; - } + public int getSceneId() { + return sceneId; + } - public int getGroupId() { - return groupId; - } + public int getGroupId() { + return groupId; + } - public int getBlockId() { - return blockId; - } + public int getBlockId() { + return blockId; + } - public void setBlockId(int blockId) { - this.blockId = blockId; - } + public void setBlockId(int blockId) { + this.blockId = blockId; + } - public List getSpawns() { - return spawns; - } - } + public List getSpawns() { + return spawns; + } + } public static class GridBlockId { int sceneId; @@ -133,7 +133,7 @@ public class SpawnDataEntry { return Objects.hash(sceneId, scale, x, z); } - public static GridBlockId[] getAdjacentGridBlockIds(int sceneId, Position pos){ + public static GridBlockId[] getAdjacentGridBlockIds(int sceneId, Position pos) { GridBlockId[] results = new GridBlockId[5*5*GameDepot.BLOCK_SIZE.length]; int t=0; for (int scale = 0; scale < GameDepot.BLOCK_SIZE.length; scale++) { @@ -148,7 +148,7 @@ public class SpawnDataEntry { return results; } - public static int getScale(int gadgetId){ + public static int getScale(int gadgetId) { return 0;//you should implement here,this is index of GameDepot.BLOCK_SIZE } } diff --git a/src/main/java/emu/grasscutter/game/world/World.java b/src/main/java/emu/grasscutter/game/world/World.java index d4bdbfc83..456a07108 100644 --- a/src/main/java/emu/grasscutter/game/world/World.java +++ b/src/main/java/emu/grasscutter/game/world/World.java @@ -31,298 +31,298 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMaps; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; public class World implements Iterable { - private final GameServer server; - private final Player owner; - private final List players; - private final Int2ObjectMap scenes; - - private int levelEntityId; - private int nextEntityId = 0; - private int nextPeerId = 0; - private int worldLevel; + private final GameServer server; + private final Player owner; + private final List players; + private final Int2ObjectMap scenes; - private boolean isMultiplayer; - - public World(Player player) { - this(player, false); - } - - public World(Player player, boolean isMultiplayer) { - this.owner = player; - this.server = player.getServer(); - this.players = Collections.synchronizedList(new ArrayList<>()); - this.scenes = Int2ObjectMaps.synchronize(new Int2ObjectOpenHashMap<>()); - - this.levelEntityId = getNextEntityId(EntityIdType.MPLEVEL); - this.worldLevel = player.getWorldLevel(); - this.isMultiplayer = isMultiplayer; + private int levelEntityId; + private int nextEntityId = 0; + private int nextPeerId = 0; + private int worldLevel; - this.owner.getServer().registerWorld(this); - } - - public Player getHost() { - return owner; - } + private boolean isMultiplayer; - public GameServer getServer() { - return server; - } + public World(Player player) { + this(player, false); + } - public int getLevelEntityId() { - return levelEntityId; - } + public World(Player player, boolean isMultiplayer) { + this.owner = player; + this.server = player.getServer(); + this.players = Collections.synchronizedList(new ArrayList<>()); + this.scenes = Int2ObjectMaps.synchronize(new Int2ObjectOpenHashMap<>()); - public int getHostPeerId() { - if (this.getHost() == null) { - return 0; - } - return this.getHost().getPeerId(); - } - - public int getNextPeerId() { - return ++this.nextPeerId; - } + this.levelEntityId = getNextEntityId(EntityIdType.MPLEVEL); + this.worldLevel = player.getWorldLevel(); + this.isMultiplayer = isMultiplayer; - public int getWorldLevel() { - return worldLevel; - } + this.owner.getServer().registerWorld(this); + } - public void setWorldLevel(int worldLevel) { - this.worldLevel = worldLevel; - } + public Player getHost() { + return owner; + } - public List getPlayers() { - return players; - } - - public Int2ObjectMap getScenes() { - return this.scenes; - } - - public Scene getSceneById(int sceneId) { - // Get scene normally - Scene scene = getScenes().get(sceneId); - if (scene != null) { - return scene; - } - - // Create scene from scene data if it doesnt exist - SceneData sceneData = GameData.getSceneDataMap().get(sceneId); - if (sceneData != null) { - scene = new Scene(this, sceneData); - this.registerScene(scene); - return scene; - } - - return null; - } - - public int getPlayerCount() { - return getPlayers().size(); - } - - public boolean isMultiplayer() { - return isMultiplayer; - } - - public int getNextEntityId(EntityIdType idType) { - return (idType.getId() << 24) + ++this.nextEntityId; - } - - public synchronized void addPlayer(Player player) { - // Check if player already in - if (getPlayers().contains(player)) { - return; - } - - // Remove player from prev world - if (player.getWorld() != null) { - player.getWorld().removePlayer(player); - } - - // Register - player.setWorld(this); - getPlayers().add(player); + public GameServer getServer() { + return server; + } - // Set player variables - player.setPeerId(this.getNextPeerId()); - player.getTeamManager().setEntityId(getNextEntityId(EntityIdType.TEAM)); - - // Copy main team to mp team - if (this.isMultiplayer()) { - player.getTeamManager().getMpTeam().copyFrom(player.getTeamManager().getCurrentSinglePlayerTeamInfo(), player.getTeamManager().getMaxTeamSize()); - player.getTeamManager().setCurrentCharacterIndex(0); - } - - // Add to scene - Scene scene = this.getSceneById(player.getSceneId()); - scene.addPlayer(player); + public int getLevelEntityId() { + return levelEntityId; + } - // Info packet for other players - if (this.getPlayers().size() > 1) { - this.updatePlayerInfos(player); - } - } + public int getHostPeerId() { + if (this.getHost() == null) { + return 0; + } + return this.getHost().getPeerId(); + } - public synchronized void removePlayer(Player player) { - // Remove team entities - player.sendPacket( - new PacketDelTeamEntityNotify( - player.getSceneId(), - getPlayers().stream().map(p -> p.getTeamManager().getEntityId()).collect(Collectors.toList()) - ) - ); - - // Deregister - getPlayers().remove(player); - player.setWorld(null); - - // Remove from scene - Scene scene = this.getSceneById(player.getSceneId()); - scene.removePlayer(player); + public int getNextPeerId() { + return ++this.nextPeerId; + } - // Info packet for other players - if (this.getPlayers().size() > 0) { - this.updatePlayerInfos(player); - } + public int getWorldLevel() { + return worldLevel; + } - // Disband world if host leaves - if (getHost() == player) { - List kicked = new ArrayList<>(this.getPlayers()); - for (Player victim : kicked) { - World world = new World(victim); - world.addPlayer(victim); - - victim.sendPacket(new PacketPlayerEnterSceneNotify(victim, EnterType.ENTER_TYPE_SELF, EnterReason.TeamKick, victim.getSceneId(), victim.getPosition())); - } - } - } - - public void registerScene(Scene scene) { - this.getScenes().put(scene.getId(), scene); - } - - public void deregisterScene(Scene scene) { - this.getScenes().remove(scene.getId()); - } - - public boolean transferPlayerToScene(Player player, int sceneId, Position pos) { - return transferPlayerToScene(player, sceneId, null, pos); - } - - public boolean transferPlayerToScene(Player player, int sceneId, DungeonData data) { - return transferPlayerToScene(player, sceneId, data, null); - } - - public boolean transferPlayerToScene(Player player, int sceneId, DungeonData dungeonData, Position pos) { - if (GameData.getSceneDataMap().get(sceneId) == null) { - return false; - } - - Scene oldScene = null; + public void setWorldLevel(int worldLevel) { + this.worldLevel = worldLevel; + } - if (player.getScene() != null) { - oldScene = player.getScene(); + public List getPlayers() { + return players; + } - // Dont deregister scenes if the player is going to tp back into them - if (oldScene.getId() == sceneId) { - oldScene.setDontDestroyWhenEmpty(true); - } + public Int2ObjectMap getScenes() { + return this.scenes; + } - oldScene.removePlayer(player); - } - - Scene newScene = this.getSceneById(sceneId); - newScene.setDungeonData(dungeonData); - newScene.addPlayer(player); - - // Dungeon - SceneConfig config = newScene.getScriptManager().getConfig(); - if (pos == null && config != null) { - if (config.born_pos != null) { - pos = newScene.getScriptManager().getConfig().born_pos; - } - if (config.born_rot != null) { - player.getRotation().set(config.born_rot); - } - } - - // Set player position - if (pos == null) { - pos = player.getPosition(); - } - - player.getPosition().set(pos); + public Scene getSceneById(int sceneId) { + // Get scene normally + Scene scene = getScenes().get(sceneId); + if (scene != null) { + return scene; + } - if (oldScene != null) { - newScene.setPrevScene(oldScene.getId()); - oldScene.setDontDestroyWhenEmpty(false); - } + // Create scene from scene data if it doesnt exist + SceneData sceneData = GameData.getSceneDataMap().get(sceneId); + if (sceneData != null) { + scene = new Scene(this, sceneData); + this.registerScene(scene); + return scene; + } - // Get enter types - EnterType enterType = EnterType.ENTER_TYPE_JUMP; - EnterReason enterReason = EnterReason.TransPoint; - - if (dungeonData != null) { - enterType = EnterType.ENTER_TYPE_DUNGEON; - enterReason = EnterReason.DungeonEnter; - } else if (oldScene == newScene) { - enterType = EnterType.ENTER_TYPE_GOTO; - } else if (newScene.getSceneType() == SceneType.SCENE_HOME_WORLD) { - // Home - enterReason = EnterReason.EnterHome; - enterType = EnterType.ENTER_TYPE_SELF_HOME; + return null; + } - } - - // Teleport packet - player.sendPacket(new PacketPlayerEnterSceneNotify(player, enterType, enterReason, sceneId, pos)); - return true; - } - - private void updatePlayerInfos(Player paramPlayer) { - for (Player player : getPlayers()) { - // Dont send packets if player is loading in and filter out joining player - if (!player.hasSentAvatarDataNotify() || player.getSceneLoadState().getValue() < SceneLoadState.INIT.getValue() || player == paramPlayer) { - continue; - } - - // Update team of all players since max players has been changed - Probably not the best way to do it - if (this.isMultiplayer()) { - player.getTeamManager().getMpTeam().copyFrom(player.getTeamManager().getMpTeam(), player.getTeamManager().getMaxTeamSize()); - player.getTeamManager().updateTeamEntities(null); - } + public int getPlayerCount() { + return getPlayers().size(); + } - // World player info packets - player.getSession().send(new PacketWorldPlayerInfoNotify(this)); - player.getSession().send(new PacketScenePlayerInfoNotify(this)); - player.getSession().send(new PacketWorldPlayerRTTNotify(this)); - - // Team packets - player.getSession().send(new PacketSyncTeamEntityNotify(player)); - player.getSession().send(new PacketSyncScenePlayTeamEntityNotify(player)); - } - } - - public void broadcastPacket(BasePacket packet) { - // Send to all players - might have to check if player has been sent data packets - for (Player player : this.getPlayers()) { - player.getSession().send(packet); - } - } - - public void onTick() { - for (Scene scene : this.getScenes().values()) { - scene.onTick(); - } - } + public boolean isMultiplayer() { + return isMultiplayer; + } - public void close() { - - } + public int getNextEntityId(EntityIdType idType) { + return (idType.getId() << 24) + ++this.nextEntityId; + } - @Override - public Iterator iterator() { - return getPlayers().iterator(); - } + public synchronized void addPlayer(Player player) { + // Check if player already in + if (getPlayers().contains(player)) { + return; + } + + // Remove player from prev world + if (player.getWorld() != null) { + player.getWorld().removePlayer(player); + } + + // Register + player.setWorld(this); + getPlayers().add(player); + + // Set player variables + player.setPeerId(this.getNextPeerId()); + player.getTeamManager().setEntityId(getNextEntityId(EntityIdType.TEAM)); + + // Copy main team to mp team + if (this.isMultiplayer()) { + player.getTeamManager().getMpTeam().copyFrom(player.getTeamManager().getCurrentSinglePlayerTeamInfo(), player.getTeamManager().getMaxTeamSize()); + player.getTeamManager().setCurrentCharacterIndex(0); + } + + // Add to scene + Scene scene = this.getSceneById(player.getSceneId()); + scene.addPlayer(player); + + // Info packet for other players + if (this.getPlayers().size() > 1) { + this.updatePlayerInfos(player); + } + } + + public synchronized void removePlayer(Player player) { + // Remove team entities + player.sendPacket( + new PacketDelTeamEntityNotify( + player.getSceneId(), + getPlayers().stream().map(p -> p.getTeamManager().getEntityId()).collect(Collectors.toList()) + ) + ); + + // Deregister + getPlayers().remove(player); + player.setWorld(null); + + // Remove from scene + Scene scene = this.getSceneById(player.getSceneId()); + scene.removePlayer(player); + + // Info packet for other players + if (this.getPlayers().size() > 0) { + this.updatePlayerInfos(player); + } + + // Disband world if host leaves + if (getHost() == player) { + List kicked = new ArrayList<>(this.getPlayers()); + for (Player victim : kicked) { + World world = new World(victim); + world.addPlayer(victim); + + victim.sendPacket(new PacketPlayerEnterSceneNotify(victim, EnterType.ENTER_TYPE_SELF, EnterReason.TeamKick, victim.getSceneId(), victim.getPosition())); + } + } + } + + public void registerScene(Scene scene) { + this.getScenes().put(scene.getId(), scene); + } + + public void deregisterScene(Scene scene) { + this.getScenes().remove(scene.getId()); + } + + public boolean transferPlayerToScene(Player player, int sceneId, Position pos) { + return transferPlayerToScene(player, sceneId, null, pos); + } + + public boolean transferPlayerToScene(Player player, int sceneId, DungeonData data) { + return transferPlayerToScene(player, sceneId, data, null); + } + + public boolean transferPlayerToScene(Player player, int sceneId, DungeonData dungeonData, Position pos) { + if (GameData.getSceneDataMap().get(sceneId) == null) { + return false; + } + + Scene oldScene = null; + + if (player.getScene() != null) { + oldScene = player.getScene(); + + // Dont deregister scenes if the player is going to tp back into them + if (oldScene.getId() == sceneId) { + oldScene.setDontDestroyWhenEmpty(true); + } + + oldScene.removePlayer(player); + } + + Scene newScene = this.getSceneById(sceneId); + newScene.setDungeonData(dungeonData); + newScene.addPlayer(player); + + // Dungeon + SceneConfig config = newScene.getScriptManager().getConfig(); + if (pos == null && config != null) { + if (config.born_pos != null) { + pos = newScene.getScriptManager().getConfig().born_pos; + } + if (config.born_rot != null) { + player.getRotation().set(config.born_rot); + } + } + + // Set player position + if (pos == null) { + pos = player.getPosition(); + } + + player.getPosition().set(pos); + + if (oldScene != null) { + newScene.setPrevScene(oldScene.getId()); + oldScene.setDontDestroyWhenEmpty(false); + } + + // Get enter types + EnterType enterType = EnterType.ENTER_TYPE_JUMP; + EnterReason enterReason = EnterReason.TransPoint; + + if (dungeonData != null) { + enterType = EnterType.ENTER_TYPE_DUNGEON; + enterReason = EnterReason.DungeonEnter; + } else if (oldScene == newScene) { + enterType = EnterType.ENTER_TYPE_GOTO; + } else if (newScene.getSceneType() == SceneType.SCENE_HOME_WORLD) { + // Home + enterReason = EnterReason.EnterHome; + enterType = EnterType.ENTER_TYPE_SELF_HOME; + + } + + // Teleport packet + player.sendPacket(new PacketPlayerEnterSceneNotify(player, enterType, enterReason, sceneId, pos)); + return true; + } + + private void updatePlayerInfos(Player paramPlayer) { + for (Player player : getPlayers()) { + // Dont send packets if player is loading in and filter out joining player + if (!player.hasSentAvatarDataNotify() || player.getSceneLoadState().getValue() < SceneLoadState.INIT.getValue() || player == paramPlayer) { + continue; + } + + // Update team of all players since max players has been changed - Probably not the best way to do it + if (this.isMultiplayer()) { + player.getTeamManager().getMpTeam().copyFrom(player.getTeamManager().getMpTeam(), player.getTeamManager().getMaxTeamSize()); + player.getTeamManager().updateTeamEntities(null); + } + + // World player info packets + player.getSession().send(new PacketWorldPlayerInfoNotify(this)); + player.getSession().send(new PacketScenePlayerInfoNotify(this)); + player.getSession().send(new PacketWorldPlayerRTTNotify(this)); + + // Team packets + player.getSession().send(new PacketSyncTeamEntityNotify(player)); + player.getSession().send(new PacketSyncScenePlayTeamEntityNotify(player)); + } + } + + public void broadcastPacket(BasePacket packet) { + // Send to all players - might have to check if player has been sent data packets + for (Player player : this.getPlayers()) { + player.getSession().send(packet); + } + } + + public void onTick() { + for (Scene scene : this.getScenes().values()) { + scene.onTick(); + } + } + + public void close() { + + } + + @Override + public Iterator iterator() { + return getPlayers().iterator(); + } } diff --git a/src/main/java/emu/grasscutter/game/world/WorldDataSystem.java b/src/main/java/emu/grasscutter/game/world/WorldDataSystem.java index 5ec06de79..9251057aa 100644 --- a/src/main/java/emu/grasscutter/game/world/WorldDataSystem.java +++ b/src/main/java/emu/grasscutter/game/world/WorldDataSystem.java @@ -30,7 +30,7 @@ public class WorldDataSystem extends BaseGameSystem { private final Map chestInteractHandlerMap; // chestType-Handler private final Map sceneInvestigationGroupMap; // - public WorldDataSystem(GameServer server){ + public WorldDataSystem(GameServer server) { super(server); this.chestInteractHandlerMap = new HashMap<>(); this.sceneInvestigationGroupMap = new ConcurrentHashMap<>(); @@ -38,15 +38,15 @@ public class WorldDataSystem extends BaseGameSystem { loadChestConfig(); } - public synchronized void loadChestConfig(){ + public synchronized void loadChestConfig() { // set the special chest first chestInteractHandlerMap.put("SceneObj_Chest_Flora", new BossChestInteractHandler()); - try(Reader reader = DataLoader.loadReader("ChestReward.json")) { + try (Reader reader = DataLoader.loadReader("ChestReward.json")) { List chestReward = Grasscutter.getGsonFactory().fromJson( - reader, + reader, TypeToken.getParameterized(List.class, ChestReward.class).getType()); - + chestReward.forEach(reward -> reward.getObjNames().forEach( name -> chestInteractHandlerMap.putIfAbsent(name, new NormalChestInteractHandler(reward)))); @@ -60,21 +60,21 @@ public class WorldDataSystem extends BaseGameSystem { return chestInteractHandlerMap; } - public RewardPreviewData getRewardByBossId(int monsterId){ + public RewardPreviewData getRewardByBossId(int monsterId) { var investigationMonsterData = GameData.getInvestigationMonsterDataMap().values().parallelStream() .filter(imd -> imd.getMonsterIdList() != null && !imd.getMonsterIdList().isEmpty()) .filter(imd -> imd.getMonsterIdList().get(0) == monsterId) .findFirst(); - if(investigationMonsterData.isEmpty()){ + if (investigationMonsterData.isEmpty()) { return null; } return GameData.getRewardPreviewDataMap().get(investigationMonsterData.get().getRewardPreviewId()); } - private SceneGroup getInvestigationGroup(int sceneId, int groupId){ + private SceneGroup getInvestigationGroup(int sceneId, int groupId) { var key = sceneId + "_" + groupId; - if(!sceneInvestigationGroupMap.containsKey(key)){ + if (!sceneInvestigationGroupMap.containsKey(key)) { var group = SceneGroup.of(groupId).load(sceneId); sceneInvestigationGroupMap.putIfAbsent(key, group); return group; @@ -82,7 +82,7 @@ public class WorldDataSystem extends BaseGameSystem { return sceneInvestigationGroupMap.get(key); } - public int getMonsterLevel(SceneMonster monster, World world){ + public int getMonsterLevel(SceneMonster monster, World world) { // Calculate level int level = monster.level; WorldLevelData worldLevelData = GameData.getWorldLevelDataMap().get(world.getWorldLevel()); @@ -98,14 +98,14 @@ public class WorldDataSystem extends BaseGameSystem { var sceneId = imd.getCityData().getSceneId(); var group = getInvestigationGroup(sceneId, groupId); - if(group == null || group.monsters == null){ + if (group == null || group.monsters == null) { return null; } var monster = group.monsters.values().stream() .filter(x -> x.monster_id == monsterId) .findFirst(); - if(monster.isEmpty()){ + if (monster.isEmpty()) { return null; } @@ -122,9 +122,9 @@ public class WorldDataSystem extends BaseGameSystem { .setRefreshInterval(Integer.MAX_VALUE) .setPos(monster.get().pos.toProto()); - if("Boss".equals(imd.getMonsterCategory())){ + if ("Boss".equals(imd.getMonsterCategory())) { var bossChest = group.searchBossChestInGroup(); - if(bossChest.isPresent()){ + if (bossChest.isPresent()) { builder.setResin(bossChest.get().resin); builder.setBossChestNum(bossChest.get().take_num); } @@ -132,9 +132,9 @@ public class WorldDataSystem extends BaseGameSystem { return builder.build(); } - public List getInvestigationMonstersByCityId(Player player, int cityId){ + public List getInvestigationMonstersByCityId(Player player, int cityId) { var cityData = GameData.getCityDataMap().get(cityId); - if(cityData == null){ + if (cityData == null) { Grasscutter.getLogger().warn("City not exist {}", cityId); return List.of(); } diff --git a/src/main/java/emu/grasscutter/net/packet/BasePacket.java b/src/main/java/emu/grasscutter/net/packet/BasePacket.java index 12009ffd3..ff40b8ee0 100644 --- a/src/main/java/emu/grasscutter/net/packet/BasePacket.java +++ b/src/main/java/emu/grasscutter/net/packet/BasePacket.java @@ -8,134 +8,134 @@ import emu.grasscutter.net.proto.PacketHeadOuterClass.PacketHead; import emu.grasscutter.utils.Crypto; public class BasePacket { - private static final int const1 = 17767; // 0x4567 - private static final int const2 = -30293; // 0x89ab - - private int opcode; - private boolean shouldBuildHeader = false; + private static final int const1 = 17767; // 0x4567 + private static final int const2 = -30293; // 0x89ab - private byte[] header; - private byte[] data; - - // Encryption - private boolean useDispatchKey; - public boolean shouldEncrypt = true; - - public BasePacket(int opcode) { - this.opcode = opcode; - } - - public BasePacket(int opcode, int clientSequence) { - this.opcode = opcode; - this.buildHeader(clientSequence); - } - - public BasePacket(int opcode, boolean buildHeader) { - this.opcode = opcode; - this.shouldBuildHeader = buildHeader; - } + private int opcode; + private boolean shouldBuildHeader = false; - public int getOpcode() { - return opcode; - } + private byte[] header; + private byte[] data; - public void setOpcode(int opcode) { - this.opcode = opcode; - } + // Encryption + private boolean useDispatchKey; + public boolean shouldEncrypt = true; - public boolean useDispatchKey() { - return useDispatchKey; - } + public BasePacket(int opcode) { + this.opcode = opcode; + } - public void setUseDispatchKey(boolean useDispatchKey) { - this.useDispatchKey = useDispatchKey; - } + public BasePacket(int opcode, int clientSequence) { + this.opcode = opcode; + this.buildHeader(clientSequence); + } - public byte[] getHeader() { - return header; - } + public BasePacket(int opcode, boolean buildHeader) { + this.opcode = opcode; + this.shouldBuildHeader = buildHeader; + } - public void setHeader(byte[] header) { - this.header = header; - } + public int getOpcode() { + return opcode; + } - public boolean shouldBuildHeader() { - return shouldBuildHeader; - } + public void setOpcode(int opcode) { + this.opcode = opcode; + } - public byte[] getData() { - return data; - } + public boolean useDispatchKey() { + return useDispatchKey; + } - public void setData(byte[] data) { - this.data = data; - } - - public void setData(GeneratedMessageV3 proto) { - this.data = proto.toByteArray(); - } - - @SuppressWarnings("rawtypes") - public void setData(GeneratedMessageV3.Builder proto) { - this.data = proto.build().toByteArray(); - } - - public BasePacket buildHeader(int clientSequence) { - if (this.getHeader() != null && clientSequence == 0) { - return this; - } - setHeader(PacketHead.newBuilder().setClientSequenceId(clientSequence).setSentMs(System.currentTimeMillis()).build().toByteArray()); - return this; - } - - public byte[] build() { - if (getHeader() == null) { - this.header = new byte[0]; - } - - if (getData() == null) { - this.data = new byte[0]; - } - - ByteArrayOutputStream baos = new ByteArrayOutputStream(2 + 2 + 2 + 4 + getHeader().length + getData().length + 2); - - this.writeUint16(baos, const1); - this.writeUint16(baos, opcode); - this.writeUint16(baos, header.length); - this.writeUint32(baos, data.length); - this.writeBytes(baos, header); - this.writeBytes(baos, data); - this.writeUint16(baos, const2); - - byte[] packet = baos.toByteArray(); - - if (this.shouldEncrypt) { - Crypto.xor(packet, this.useDispatchKey() ? Crypto.DISPATCH_KEY : Crypto.ENCRYPT_KEY); - } + public void setUseDispatchKey(boolean useDispatchKey) { + this.useDispatchKey = useDispatchKey; + } - return packet; - } - - public void writeUint16(ByteArrayOutputStream baos, int i) { - // Unsigned short + public byte[] getHeader() { + return header; + } + + public void setHeader(byte[] header) { + this.header = header; + } + + public boolean shouldBuildHeader() { + return shouldBuildHeader; + } + + public byte[] getData() { + return data; + } + + public void setData(byte[] data) { + this.data = data; + } + + public void setData(GeneratedMessageV3 proto) { + this.data = proto.toByteArray(); + } + + @SuppressWarnings("rawtypes") + public void setData(GeneratedMessageV3.Builder proto) { + this.data = proto.build().toByteArray(); + } + + public BasePacket buildHeader(int clientSequence) { + if (this.getHeader() != null && clientSequence == 0) { + return this; + } + setHeader(PacketHead.newBuilder().setClientSequenceId(clientSequence).setSentMs(System.currentTimeMillis()).build().toByteArray()); + return this; + } + + public byte[] build() { + if (getHeader() == null) { + this.header = new byte[0]; + } + + if (getData() == null) { + this.data = new byte[0]; + } + + ByteArrayOutputStream baos = new ByteArrayOutputStream(2 + 2 + 2 + 4 + getHeader().length + getData().length + 2); + + this.writeUint16(baos, const1); + this.writeUint16(baos, opcode); + this.writeUint16(baos, header.length); + this.writeUint32(baos, data.length); + this.writeBytes(baos, header); + this.writeBytes(baos, data); + this.writeUint16(baos, const2); + + byte[] packet = baos.toByteArray(); + + if (this.shouldEncrypt) { + Crypto.xor(packet, this.useDispatchKey() ? Crypto.DISPATCH_KEY : Crypto.ENCRYPT_KEY); + } + + return packet; + } + + public void writeUint16(ByteArrayOutputStream baos, int i) { + // Unsigned short baos.write((byte) ((i >>> 8) & 0xFF)); baos.write((byte) (i & 0xFF)); } - - public void writeUint32(ByteArrayOutputStream baos, int i) { - // Unsigned int (long) + + public void writeUint32(ByteArrayOutputStream baos, int i) { + // Unsigned int (long) baos.write((byte) ((i >>> 24) & 0xFF)); baos.write((byte) ((i >>> 16) & 0xFF)); baos.write((byte) ((i >>> 8) & 0xFF)); baos.write((byte) (i & 0xFF)); } - - public void writeBytes(ByteArrayOutputStream baos, byte[] bytes) { - try { - baos.write(bytes); - } catch (IOException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - } + + public void writeBytes(ByteArrayOutputStream baos, byte[] bytes) { + try { + baos.write(bytes); + } catch (IOException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } } diff --git a/src/main/java/emu/grasscutter/net/packet/PacketOpcodes.java b/src/main/java/emu/grasscutter/net/packet/PacketOpcodes.java index 3d79a196d..6ae8f8d95 100644 --- a/src/main/java/emu/grasscutter/net/packet/PacketOpcodes.java +++ b/src/main/java/emu/grasscutter/net/packet/PacketOpcodes.java @@ -1854,4 +1854,4 @@ public class PacketOpcodes { public static final int WorldRoutineTypeCloseNotify = 3502; public static final int WorldRoutineTypeRefreshNotify = 3525; -} \ No newline at end of file +} diff --git a/src/main/java/emu/grasscutter/net/packet/PacketOpcodesUtils.java b/src/main/java/emu/grasscutter/net/packet/PacketOpcodesUtils.java index fc6c5dba0..ac915b2a4 100644 --- a/src/main/java/emu/grasscutter/net/packet/PacketOpcodesUtils.java +++ b/src/main/java/emu/grasscutter/net/packet/PacketOpcodesUtils.java @@ -22,7 +22,7 @@ public class PacketOpcodesUtils { PacketOpcodes.WindSeedClientNotify, PacketOpcodes.PlayerLuaShellNotify ); - + public static final Set LOOP_PACKETS = Set.of( PacketOpcodes.PingReq, PacketOpcodes.PingRsp, @@ -30,39 +30,39 @@ public class PacketOpcodesUtils { PacketOpcodes.UnionCmdNotify, PacketOpcodes.QueryPathReq ); - - static { - opcodeMap = new Int2ObjectOpenHashMap(); - Field[] fields = PacketOpcodes.class.getFields(); + static { + opcodeMap = new Int2ObjectOpenHashMap(); - for (Field f : fields) { - if(f.getType().equals(int.class)) { - try { - opcodeMap.put(f.getInt(null), f.getName()); - } catch (Exception e) { - e.printStackTrace(); - } - } - } - } + Field[] fields = PacketOpcodes.class.getFields(); - public static String getOpcodeName(int opcode) { - if (opcode <= 0) return "UNKNOWN"; - return opcodeMap.getOrDefault(opcode, "UNKNOWN"); - } + for (Field f : fields) { + if (f.getType().equals(int.class)) { + try { + opcodeMap.put(f.getInt(null), f.getName()); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + } - public static void dumpPacketIds() { - try (FileWriter writer = new FileWriter("./PacketIds_" + GameConstants.VERSION + ".json")) { - // Create sorted tree map - Map packetIds = opcodeMap.int2ObjectEntrySet().stream() - .filter(e -> e.getIntKey() > 0) - .collect(Collectors.toMap(Int2ObjectMap.Entry::getIntKey, Int2ObjectMap.Entry::getValue, (k, v) -> v, TreeMap::new)); - // Write to file - writer.write(Grasscutter.getGsonFactory().toJson(packetIds)); - Grasscutter.getLogger().info("Dumped packet ids."); - } catch (IOException e) { - e.printStackTrace(); - } - } + public static String getOpcodeName(int opcode) { + if (opcode <= 0) return "UNKNOWN"; + return opcodeMap.getOrDefault(opcode, "UNKNOWN"); + } + + public static void dumpPacketIds() { + try (FileWriter writer = new FileWriter("./PacketIds_" + GameConstants.VERSION + ".json")) { + // Create sorted tree map + Map packetIds = opcodeMap.int2ObjectEntrySet().stream() + .filter(e -> e.getIntKey() > 0) + .collect(Collectors.toMap(Int2ObjectMap.Entry::getIntKey, Int2ObjectMap.Entry::getValue, (k, v) -> v, TreeMap::new)); + // Write to file + writer.write(Grasscutter.getGsonFactory().toJson(packetIds)); + Grasscutter.getLogger().info("Dumped packet ids."); + } catch (IOException e) { + e.printStackTrace(); + } + } } diff --git a/src/main/java/emu/grasscutter/plugin/Plugin.java b/src/main/java/emu/grasscutter/plugin/Plugin.java index d14ad5c51..fdc27514a 100644 --- a/src/main/java/emu/grasscutter/plugin/Plugin.java +++ b/src/main/java/emu/grasscutter/plugin/Plugin.java @@ -17,7 +17,7 @@ import java.net.URLClassLoader; */ public abstract class Plugin { private final ServerHook server = ServerHook.getInstance(); - + private PluginIdentifier identifier; private URLClassLoader classLoader; private File dataFolder; @@ -25,22 +25,22 @@ public abstract class Plugin { /** * This method is reflected into. - * + * * Set plugin variables. * @param identifier The plugin's identifier. */ private void initializePlugin(PluginIdentifier identifier, URLClassLoader classLoader) { - if(this.identifier != null) { + if (this.identifier != null) { Grasscutter.getLogger().warn(this.identifier.name + " had a reinitialization attempt."); return; } - + this.identifier = identifier; this.classLoader = classLoader; this.dataFolder = new File(PLUGIN(), identifier.name); this.logger = LoggerFactory.getLogger(identifier.name); - - if(!this.dataFolder.exists() && !this.dataFolder.mkdirs()) { + + if (!this.dataFolder.exists() && !this.dataFolder.mkdirs()) { Grasscutter.getLogger().warn("Failed to create plugin data folder for " + this.identifier.name); return; } @@ -50,7 +50,7 @@ public abstract class Plugin { * The plugin's identifier instance. * @return An instance of {@link PluginIdentifier}. */ - public final PluginIdentifier getIdentifier(){ + public final PluginIdentifier getIdentifier() { return this.identifier; } @@ -115,7 +115,7 @@ public abstract class Plugin { public final Logger getLogger() { return this.logger; } - + /* Called when the plugin is first loaded. */ public void onLoad() { } /* Called after (most of) the server enables. */ diff --git a/src/main/java/emu/grasscutter/plugin/PluginManager.java b/src/main/java/emu/grasscutter/plugin/PluginManager.java index 6de30da38..f55e0a6fe 100644 --- a/src/main/java/emu/grasscutter/plugin/PluginManager.java +++ b/src/main/java/emu/grasscutter/plugin/PluginManager.java @@ -72,7 +72,7 @@ public final class PluginManager { List dependencies = new ArrayList<>(); // Initialize all plugins. - for(var plugin : plugins) { + for (var plugin : plugins) { try { URL url = plugin.toURI().toURL(); try (URLClassLoader loader = new URLClassLoader(new URL[]{url})) { @@ -109,7 +109,7 @@ public final class PluginManager { fileReader.close(); // Check if the plugin has alternate dependencies. - if(pluginConfig.loadAfter != null && pluginConfig.loadAfter.length > 0) { + if (pluginConfig.loadAfter != null && pluginConfig.loadAfter.length > 0) { // Add the plugin to a "load later" list. dependencies.add(new PluginData( pluginInstance, PluginIdentifier.fromPluginConfig(pluginConfig), @@ -131,9 +131,9 @@ public final class PluginManager { // Load plugins with dependencies. int depth = 0; final int maxDepth = 30; - while(!dependencies.isEmpty()) { + while (!dependencies.isEmpty()) { // Check if the depth is too high. - if(depth >= maxDepth) { + if (depth >= maxDepth) { Grasscutter.getLogger().error("Failed to load plugins with dependencies."); break; } @@ -143,7 +143,7 @@ public final class PluginManager { var pluginData = dependencies.get(0); // Check if the plugin's dependencies are loaded. - if(!this.plugins.keySet().containsAll(List.of(pluginData.getDependencies()))) { + if (!this.plugins.keySet().containsAll(List.of(pluginData.getDependencies()))) { depth++; // Increase depth counter. continue; // Continue to next plugin. } diff --git a/src/main/java/emu/grasscutter/plugin/api/PlayerHook.java b/src/main/java/emu/grasscutter/plugin/api/PlayerHook.java index 5410241a3..0b91ede33 100644 --- a/src/main/java/emu/grasscutter/plugin/api/PlayerHook.java +++ b/src/main/java/emu/grasscutter/plugin/api/PlayerHook.java @@ -19,13 +19,13 @@ public final class PlayerHook { private final Player player; /** - * Hooks into the player. + * Hooks into the player. * @param player The player to hook into. */ public PlayerHook(Player player) { this.player = player; } - + /** * Kicks a player from the server. * TODO: Refactor to kick using a packet. @@ -82,7 +82,7 @@ public final class PlayerHook { */ public void teleport(Position position) { this.player.getPosition().set(position); - this.player.sendPacket(new PacketPlayerEnterSceneNotify(this.player, + this.player.sendPacket(new PacketPlayerEnterSceneNotify(this.player, EnterType.ENTER_TYPE_JUMP, EnterReason.TransPoint, this.player.getSceneId(), position )); @@ -111,4 +111,4 @@ public final class PlayerHook { public Avatar getCurrentAvatar() { return this.getCurrentAvatarEntity().getAvatar(); } -} \ No newline at end of file +} diff --git a/src/main/java/emu/grasscutter/scripts/data/SceneBlock.java b/src/main/java/emu/grasscutter/scripts/data/SceneBlock.java index 48903f68b..d8f969e04 100644 --- a/src/main/java/emu/grasscutter/scripts/data/SceneBlock.java +++ b/src/main/java/emu/grasscutter/scripts/data/SceneBlock.java @@ -22,61 +22,61 @@ import java.util.stream.Collectors; @ToString @Setter public class SceneBlock { - public int id; - public Position max; - public Position min; + public int id; + public Position max; + public Position min; - public int sceneId; - public Map groups; - public RTree sceneGroupIndex; + public int sceneId; + public Map groups; + public RTree sceneGroupIndex; - private transient boolean loaded; // Not an actual variable in the scripts either + private transient boolean loaded; // Not an actual variable in the scripts either - public boolean isLoaded() { - return this.loaded; - } + public boolean isLoaded() { + return this.loaded; + } - public void setLoaded(boolean loaded) { - this.loaded = loaded; - } + public void setLoaded(boolean loaded) { + this.loaded = loaded; + } - public boolean contains(Position pos) { - return pos.getX() <= this.max.getX() && pos.getX() >= this.min.getX() && - pos.getZ() <= this.max.getZ() && pos.getZ() >= this.min.getZ(); - } + public boolean contains(Position pos) { + return pos.getX() <= this.max.getX() && pos.getX() >= this.min.getX() && + pos.getZ() <= this.max.getZ() && pos.getZ() >= this.min.getZ(); + } - public SceneBlock load(int sceneId, Bindings bindings){ - if(this.loaded){ - return this; - } - this.sceneId = sceneId; + public SceneBlock load(int sceneId, Bindings bindings) { + if (this.loaded) { + return this; + } + this.sceneId = sceneId; this.setLoaded(true); - CompiledScript cs = ScriptLoader.getScriptByPath( - SCRIPT("Scene/" + sceneId + "/scene" + sceneId + "_block" + this.id + "." + ScriptLoader.getScriptType())); + CompiledScript cs = ScriptLoader.getScriptByPath( + SCRIPT("Scene/" + sceneId + "/scene" + sceneId + "_block" + this.id + "." + ScriptLoader.getScriptType())); - if (cs == null) { - return null; - } + if (cs == null) { + return null; + } - // Eval script - try { - cs.eval(bindings); + // Eval script + try { + cs.eval(bindings); - // Set groups + // Set groups this.groups = ScriptLoader.getSerializer().toList(SceneGroup.class, bindings.get("groups")).stream() - .collect(Collectors.toMap(x -> x.id, y -> y)); + .collect(Collectors.toMap(x -> x.id, y -> y)); this.groups.values().forEach(g -> g.block_id = this.id); - this.sceneGroupIndex = SceneIndexManager.buildIndex(3, this.groups.values(), g -> g.pos.toPoint()); - } catch (ScriptException exception) { + this.sceneGroupIndex = SceneIndexManager.buildIndex(3, this.groups.values(), g -> g.pos.toPoint()); + } catch (ScriptException exception) { Grasscutter.getLogger().error("An error occurred while loading block " + this.id + " in scene " + sceneId, exception); - } - Grasscutter.getLogger().debug("Successfully loaded block {} in scene {}.", this.id, sceneId); - return this; - } + } + Grasscutter.getLogger().debug("Successfully loaded block {} in scene {}.", this.id, sceneId); + return this; + } - public Rectangle toRectangle() { - return Rectangle.create(this.min.toXZDoubleArray(), this.max.toXZDoubleArray()); - } -} \ No newline at end of file + public Rectangle toRectangle() { + return Rectangle.create(this.min.toXZDoubleArray(), this.max.toXZDoubleArray()); + } +} diff --git a/src/main/java/emu/grasscutter/scripts/data/SceneGroup.java b/src/main/java/emu/grasscutter/scripts/data/SceneGroup.java index 507f80c34..163ce94c8 100644 --- a/src/main/java/emu/grasscutter/scripts/data/SceneGroup.java +++ b/src/main/java/emu/grasscutter/scripts/data/SceneGroup.java @@ -21,93 +21,93 @@ import java.util.stream.Collectors; @ToString @Setter public class SceneGroup { - public transient int block_id; // Not an actual variable in the scripts but we will keep it here for reference + public transient int block_id; // Not an actual variable in the scripts but we will keep it here for reference - public int id; - public int refresh_id; - public Position pos; + public int id; + public int refresh_id; + public Position pos; - public Map monsters; // - public Map gadgets; // - public Map triggers; + public Map monsters; // + public Map gadgets; // + public Map triggers; public Map regions; - public List suites; - public List variables; + public List suites; + public List variables; - public SceneBusiness business; - public SceneGarbage garbages; - public SceneInitConfig init_config; + public SceneBusiness business; + public SceneGarbage garbages; + public SceneInitConfig init_config; - private transient boolean loaded; // Not an actual variable in the scripts either - private transient CompiledScript script; - private transient Bindings bindings; - public static SceneGroup of(int groupId) { - var group = new SceneGroup(); - group.id = groupId; - return group; - } + private transient boolean loaded; // Not an actual variable in the scripts either + private transient CompiledScript script; + private transient Bindings bindings; + public static SceneGroup of(int groupId) { + var group = new SceneGroup(); + group.id = groupId; + return group; + } - public boolean isLoaded() { - return this.loaded; - } + public boolean isLoaded() { + return this.loaded; + } - public void setLoaded(boolean loaded) { - this.loaded = loaded; - } + public void setLoaded(boolean loaded) { + this.loaded = loaded; + } - public int getBusinessType() { - return this.business == null ? 0 : this.business.type; - } + public int getBusinessType() { + return this.business == null ? 0 : this.business.type; + } - public List getGarbageGadgets() { - return this.garbages == null ? null : this.garbages.gadgets; - } + public List getGarbageGadgets() { + return this.garbages == null ? null : this.garbages.gadgets; + } - public CompiledScript getScript() { - return this.script; - } + public CompiledScript getScript() { + return this.script; + } - public SceneSuite getSuiteByIndex(int index) { - return this.suites.get(index - 1); - } + public SceneSuite getSuiteByIndex(int index) { + return this.suites.get(index - 1); + } - public Bindings getBindings() { - return this.bindings; - } + public Bindings getBindings() { + return this.bindings; + } - public synchronized SceneGroup load(int sceneId){ - if(this.loaded){ - return this; - } - // Set flag here so if there is no script, we don't call this function over and over again. + public synchronized SceneGroup load(int sceneId) { + if (this.loaded) { + return this; + } + // Set flag here so if there is no script, we don't call this function over and over again. this.setLoaded(true); - this.bindings = ScriptLoader.getEngine().createBindings(); + this.bindings = ScriptLoader.getEngine().createBindings(); - CompiledScript cs = ScriptLoader.getScriptByPath( - SCRIPT("Scene/" + sceneId + "/scene" + sceneId + "_group" + this.id + "." + ScriptLoader.getScriptType())); + CompiledScript cs = ScriptLoader.getScriptByPath( + SCRIPT("Scene/" + sceneId + "/scene" + sceneId + "_group" + this.id + "." + ScriptLoader.getScriptType())); - if (cs == null) { - return this; - } + if (cs == null) { + return this; + } - this.script = cs; + this.script = cs; - // Eval script - try { - cs.eval(this.bindings); + // Eval script + try { + cs.eval(this.bindings); - // Set + // Set this.monsters = ScriptLoader.getSerializer().toList(SceneMonster.class, this.bindings.get("monsters")).stream() - .collect(Collectors.toMap(x -> x.config_id, y -> y)); + .collect(Collectors.toMap(x -> x.config_id, y -> y)); this.monsters.values().forEach(m -> m.group = this); this.gadgets = ScriptLoader.getSerializer().toList(SceneGadget.class, this.bindings.get("gadgets")).stream() - .collect(Collectors.toMap(x -> x.config_id, y -> y)); + .collect(Collectors.toMap(x -> x.config_id, y -> y)); this.gadgets.values().forEach(m -> m.group = this); this.triggers = ScriptLoader.getSerializer().toList(SceneTrigger.class, this.bindings.get("triggers")).stream() - .collect(Collectors.toMap(x -> x.name, y -> y)); + .collect(Collectors.toMap(x -> x.name, y -> y)); this.triggers.values().forEach(t -> t.currentGroup = this); this.suites = ScriptLoader.getSerializer().toList(SceneSuite.class, this.bindings.get("suites")); @@ -117,35 +117,35 @@ public class SceneGroup { this.init_config = ScriptLoader.getSerializer().toObject(SceneInitConfig.class, this.bindings.get("init_config")); - // Garbages // TODO: fix properly later - Object garbagesValue = this.bindings.get("garbages"); - if (garbagesValue instanceof LuaValue garbagesTable) { + // Garbages // TODO: fix properly later + Object garbagesValue = this.bindings.get("garbages"); + if (garbagesValue instanceof LuaValue garbagesTable) { this.garbages = new SceneGarbage(); - if (garbagesTable.checktable().get("gadgets") != LuaValue.NIL) { + if (garbagesTable.checktable().get("gadgets") != LuaValue.NIL) { this.garbages.gadgets = ScriptLoader.getSerializer().toList(SceneGadget.class, garbagesTable.checktable().get("gadgets").checktable()); this.garbages.gadgets.forEach(m -> m.group = this); - } - } + } + } - // Add variables to suite - this.variables = ScriptLoader.getSerializer().toList(SceneVar.class, this.bindings.get("variables")); + // Add variables to suite + this.variables = ScriptLoader.getSerializer().toList(SceneVar.class, this.bindings.get("variables")); - // Add monsters and gadgets to suite + // Add monsters and gadgets to suite this.suites.forEach(i -> i.init(this)); - } catch (ScriptException e) { - Grasscutter.getLogger().error("An error occurred while loading group " + this.id + " in scene " + sceneId + ".", e); - } + } catch (ScriptException e) { + Grasscutter.getLogger().error("An error occurred while loading group " + this.id + " in scene " + sceneId + ".", e); + } - Grasscutter.getLogger().debug("Successfully loaded group {} in scene {}.", this.id, sceneId); - return this; - } + Grasscutter.getLogger().debug("Successfully loaded group {} in scene {}.", this.id, sceneId); + return this; + } - public Optional searchBossChestInGroup() { - return this.gadgets.values().stream() - .filter(g -> g.boss_chest != null && g.boss_chest.monster_config_id > 0) - .map(g -> g.boss_chest) - .findFirst(); - } + public Optional searchBossChestInGroup() { + return this.gadgets.values().stream() + .filter(g -> g.boss_chest != null && g.boss_chest.monster_config_id > 0) + .map(g -> g.boss_chest) + .findFirst(); + } } diff --git a/src/main/java/emu/grasscutter/scripts/data/SceneMeta.java b/src/main/java/emu/grasscutter/scripts/data/SceneMeta.java index efb6744fe..5d8a14dfd 100644 --- a/src/main/java/emu/grasscutter/scripts/data/SceneMeta.java +++ b/src/main/java/emu/grasscutter/scripts/data/SceneMeta.java @@ -33,7 +33,7 @@ public class SceneMeta { return new SceneMeta().load(sceneId); } - public SceneMeta load(int sceneId){ + public SceneMeta load(int sceneId) { // Get compiled script if cached CompiledScript cs = ScriptLoader.getScriptByPath( SCRIPT("Scene/" + sceneId + "/scene" + sceneId + "." + ScriptLoader.getScriptType())); diff --git a/src/main/java/emu/grasscutter/server/game/BaseGameSystem.java b/src/main/java/emu/grasscutter/server/game/BaseGameSystem.java index 536e90575..3fd3db05c 100644 --- a/src/main/java/emu/grasscutter/server/game/BaseGameSystem.java +++ b/src/main/java/emu/grasscutter/server/game/BaseGameSystem.java @@ -2,11 +2,11 @@ package emu.grasscutter.server.game; public abstract class BaseGameSystem { protected final GameServer server; - + public BaseGameSystem(GameServer server) { this.server = server; } - + public GameServer getServer() { return this.server; } diff --git a/src/main/java/emu/grasscutter/server/game/GameServer.java b/src/main/java/emu/grasscutter/server/game/GameServer.java index f115b2c3b..7eb25a67c 100644 --- a/src/main/java/emu/grasscutter/server/game/GameServer.java +++ b/src/main/java/emu/grasscutter/server/game/GameServer.java @@ -51,97 +51,97 @@ import static emu.grasscutter.utils.Language.translate; public final class GameServer extends KcpServer { // Game server base private final InetSocketAddress address; - private final GameServerPacketHandler packetHandler; + private final GameServerPacketHandler packetHandler; private final Map players; private final Set worlds; // Server systems - private final InventorySystem inventorySystem; - private final GachaSystem gachaSystem; - private final ShopSystem shopSystem; - private final MultiplayerSystem multiplayerSystem; - private final DungeonSystem dungeonSystem; - private final ExpeditionSystem expeditionSystem; - private final DropSystem dropSystem; - private final WorldDataSystem worldDataSystem; - private final BattlePassSystem battlePassSystem; - private final CombineManger combineSystem; - private final TowerSystem towerSystem; - private final AnnouncementSystem announcementSystem; - private final QuestSystem questSystem; - - // Extra - private final ServerTaskScheduler scheduler; + private final InventorySystem inventorySystem; + private final GachaSystem gachaSystem; + private final ShopSystem shopSystem; + private final MultiplayerSystem multiplayerSystem; + private final DungeonSystem dungeonSystem; + private final ExpeditionSystem expeditionSystem; + private final DropSystem dropSystem; + private final WorldDataSystem worldDataSystem; + private final BattlePassSystem battlePassSystem; + private final CombineManger combineSystem; + private final TowerSystem towerSystem; + private final AnnouncementSystem announcementSystem; + private final QuestSystem questSystem; + + // Extra + private final ServerTaskScheduler scheduler; private final CommandMap commandMap; private final TaskMap taskMap; - - private ChatManagerHandler chatManager; - public GameServer() { - this(getAdapterInetSocketAddress()); - } + private ChatManagerHandler chatManager; - public GameServer(InetSocketAddress address) { - ChannelConfig channelConfig = new ChannelConfig(); - channelConfig.nodelay(true, 40, 2, true); - channelConfig.setMtu(1400); - channelConfig.setSndwnd(256); - channelConfig.setRcvwnd(256); - channelConfig.setTimeoutMillis(30 * 1000);//30s - channelConfig.setUseConvChannel(true); - channelConfig.setAckNoDelay(false); + public GameServer() { + this(getAdapterInetSocketAddress()); + } - this.init(GameSessionManager.getListener(),channelConfig,address); + public GameServer(InetSocketAddress address) { + ChannelConfig channelConfig = new ChannelConfig(); + channelConfig.nodelay(true, 40, 2, true); + channelConfig.setMtu(1400); + channelConfig.setSndwnd(256); + channelConfig.setRcvwnd(256); + channelConfig.setTimeoutMillis(30 * 1000);//30s + channelConfig.setUseConvChannel(true); + channelConfig.setAckNoDelay(false); - DungeonChallenge.initialize(); - EnergyManager.initialize(); - StaminaManager.initialize(); - CookingManager.initialize(); - CombineManger.initialize(); + this.init(GameSessionManager.getListener(),channelConfig,address); - // Game Server base - this.address = address; - this.packetHandler = new GameServerPacketHandler(PacketHandler.class); - this.players = new ConcurrentHashMap<>(); - this.worlds = Collections.synchronizedSet(new HashSet<>()); - - // Extra - this.scheduler = new ServerTaskScheduler(); - this.commandMap = new CommandMap(true); + DungeonChallenge.initialize(); + EnergyManager.initialize(); + StaminaManager.initialize(); + CookingManager.initialize(); + CombineManger.initialize(); + + // Game Server base + this.address = address; + this.packetHandler = new GameServerPacketHandler(PacketHandler.class); + this.players = new ConcurrentHashMap<>(); + this.worlds = Collections.synchronizedSet(new HashSet<>()); + + // Extra + this.scheduler = new ServerTaskScheduler(); + this.commandMap = new CommandMap(true); this.taskMap = new TaskMap(true); - // Create game systems - this.inventorySystem = new InventorySystem(this); - this.gachaSystem = new GachaSystem(this); - this.shopSystem = new ShopSystem(this); - this.multiplayerSystem = new MultiplayerSystem(this); - this.dungeonSystem = new DungeonSystem(this); - this.dropSystem = new DropSystem(this); - this.expeditionSystem = new ExpeditionSystem(this); - this.combineSystem = new CombineManger(this); - this.towerSystem = new TowerSystem(this); - this.worldDataSystem = new WorldDataSystem(this); - this.battlePassSystem = new BattlePassSystem(this); - this.announcementSystem = new AnnouncementSystem(this); - this.questSystem = new QuestSystem(this); - - // Chata manager - this.chatManager = new ChatManager(this); - - // Hook into shutdown event. - Runtime.getRuntime().addShutdownHook(new Thread(this::onServerShutdown)); - } - + // Create game systems + this.inventorySystem = new InventorySystem(this); + this.gachaSystem = new GachaSystem(this); + this.shopSystem = new ShopSystem(this); + this.multiplayerSystem = new MultiplayerSystem(this); + this.dungeonSystem = new DungeonSystem(this); + this.dropSystem = new DropSystem(this); + this.expeditionSystem = new ExpeditionSystem(this); + this.combineSystem = new CombineManger(this); + this.towerSystem = new TowerSystem(this); + this.worldDataSystem = new WorldDataSystem(this); + this.battlePassSystem = new BattlePassSystem(this); + this.announcementSystem = new AnnouncementSystem(this); + this.questSystem = new QuestSystem(this); + + // Chata manager + this.chatManager = new ChatManager(this); + + // Hook into shutdown event. + Runtime.getRuntime().addShutdownHook(new Thread(this::onServerShutdown)); + } + @Deprecated public ChatManagerHandler getChatManager() { return chatManager; } - + @Deprecated public void setChatManager(ChatManagerHandler chatManager) { this.chatManager = chatManager; } - + public ChatManagerHandler getChatSystem() { return chatManager; } @@ -150,71 +150,71 @@ public final class GameServer extends KcpServer { this.chatManager = chatManager; } - private static InetSocketAddress getAdapterInetSocketAddress(){ - InetSocketAddress inetSocketAddress; - if(GAME_INFO.bindAddress.equals("")){ - inetSocketAddress=new InetSocketAddress(GAME_INFO.bindPort); - }else{ - inetSocketAddress=new InetSocketAddress( - GAME_INFO.bindAddress, - GAME_INFO.bindPort - ); - } - return inetSocketAddress; - } + private static InetSocketAddress getAdapterInetSocketAddress() { + InetSocketAddress inetSocketAddress; + if (GAME_INFO.bindAddress.equals("")) { + inetSocketAddress=new InetSocketAddress(GAME_INFO.bindPort); + }else { + inetSocketAddress=new InetSocketAddress( + GAME_INFO.bindAddress, + GAME_INFO.bindPort + ); + } + return inetSocketAddress; + } - public void registerPlayer(Player player) { - getPlayers().put(player.getUid(), player); - } + public void registerPlayer(Player player) { + getPlayers().put(player.getUid(), player); + } - public Player getPlayerByUid(int id) { - return this.getPlayerByUid(id, false); - } + public Player getPlayerByUid(int id) { + return this.getPlayerByUid(id, false); + } - public Player getPlayerByUid(int id, boolean allowOfflinePlayers) { - // Console check - if (id == GameConstants.SERVER_CONSOLE_UID) { - return null; - } + public Player getPlayerByUid(int id, boolean allowOfflinePlayers) { + // Console check + if (id == GameConstants.SERVER_CONSOLE_UID) { + return null; + } - // Get from online players - Player player = this.getPlayers().get(id); + // Get from online players + Player player = this.getPlayers().get(id); - if (!allowOfflinePlayers) { - return player; - } + if (!allowOfflinePlayers) { + return player; + } - // Check database if character isnt here - if (player == null) { - player = DatabaseHelper.getPlayerByUid(id); - } + // Check database if character isnt here + if (player == null) { + player = DatabaseHelper.getPlayerByUid(id); + } - return player; - } + return player; + } - public Player getPlayerByAccountId(String accountId) { - Optional playerOpt = getPlayers().values().stream().filter(player -> player.getAccount().getId().equals(accountId)).findFirst(); - return playerOpt.orElse(null); - } + public Player getPlayerByAccountId(String accountId) { + Optional playerOpt = getPlayers().values().stream().filter(player -> player.getAccount().getId().equals(accountId)).findFirst(); + return playerOpt.orElse(null); + } - public SocialDetail.Builder getSocialDetailByUid(int id) { - // Get from online players - Player player = this.getPlayerByUid(id, true); + public SocialDetail.Builder getSocialDetailByUid(int id) { + // Get from online players + Player player = this.getPlayerByUid(id, true); - if (player == null) { - return null; - } + if (player == null) { + return null; + } - return player.getSocialDetail(); - } + return player.getSocialDetail(); + } - public Account getAccountByName(String username) { - Optional playerOpt = getPlayers().values().stream().filter(player -> player.getAccount().getUsername().equals(username)).findFirst(); - if (playerOpt.isPresent()) { - return playerOpt.get().getAccount(); - } - return DatabaseHelper.getAccountByName(username); - } + public Account getAccountByName(String username) { + Optional playerOpt = getPlayers().values().stream().filter(player -> player.getAccount().getUsername().equals(username)).findFirst(); + if (playerOpt.isPresent()) { + return playerOpt.get().getAccount(); + } + return DatabaseHelper.getAccountByName(username); + } public synchronized void onTick() { var tickStart = Instant.now(); @@ -244,43 +244,43 @@ public final class GameServer extends KcpServer { event.call(); } - public void registerWorld(World world) { - this.getWorlds().add(world); - } + public void registerWorld(World world) { + this.getWorlds().add(world); + } - public void deregisterWorld(World world) { - // TODO Auto-generated method stub + public void deregisterWorld(World world) { + // TODO Auto-generated method stub - } + } - public void start() { - // Schedule game loop. - Timer gameLoop = new Timer(); - gameLoop.scheduleAtFixedRate(new TimerTask() { - @Override - public void run() { - try { - onTick(); - } catch (Exception e) { - Grasscutter.getLogger().error(translate("messages.game.game_update_error"), e); - } - } - }, new Date(), 1000L); - Grasscutter.getLogger().info(translate("messages.status.free_software")); - Grasscutter.getLogger().info(translate("messages.game.port_bind", Integer.toString(address.getPort()))); - ServerStartEvent event = new ServerStartEvent(ServerEvent.Type.GAME, OffsetDateTime.now()); - event.call(); - } + public void start() { + // Schedule game loop. + Timer gameLoop = new Timer(); + gameLoop.scheduleAtFixedRate(new TimerTask() { + @Override + public void run() { + try { + onTick(); + } catch (Exception e) { + Grasscutter.getLogger().error(translate("messages.game.game_update_error"), e); + } + } + }, new Date(), 1000L); + Grasscutter.getLogger().info(translate("messages.status.free_software")); + Grasscutter.getLogger().info(translate("messages.game.port_bind", Integer.toString(address.getPort()))); + ServerStartEvent event = new ServerStartEvent(ServerEvent.Type.GAME, OffsetDateTime.now()); + event.call(); + } - public void onServerShutdown() { - ServerStopEvent event = new ServerStopEvent(ServerEvent.Type.GAME, OffsetDateTime.now()); event.call(); + public void onServerShutdown() { + ServerStopEvent event = new ServerStopEvent(ServerEvent.Type.GAME, OffsetDateTime.now()); event.call(); - // Kick and save all players - List list = new ArrayList<>(this.getPlayers().size()); - list.addAll(this.getPlayers().values()); + // Kick and save all players + List list = new ArrayList<>(this.getPlayers().size()); + list.addAll(this.getPlayers().values()); - for (Player player : list) { - player.getSession().close(); - } - } + for (Player player : list) { + player.getSession().close(); + } + } } diff --git a/src/main/java/emu/grasscutter/server/game/GameServerPacketHandler.java b/src/main/java/emu/grasscutter/server/game/GameServerPacketHandler.java index 7a8c4b8b1..94fe3e232 100644 --- a/src/main/java/emu/grasscutter/server/game/GameServerPacketHandler.java +++ b/src/main/java/emu/grasscutter/server/game/GameServerPacketHandler.java @@ -18,84 +18,84 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; @SuppressWarnings("unchecked") public class GameServerPacketHandler { - private final Int2ObjectMap handlers; + private final Int2ObjectMap handlers; - public GameServerPacketHandler(Class handlerClass) { - this.handlers = new Int2ObjectOpenHashMap<>(); + public GameServerPacketHandler(Class handlerClass) { + this.handlers = new Int2ObjectOpenHashMap<>(); - this.registerHandlers(handlerClass); - } + this.registerHandlers(handlerClass); + } - public void registerPacketHandler(Class handlerClass) { - try { - Opcodes opcode = handlerClass.getAnnotation(Opcodes.class); + public void registerPacketHandler(Class handlerClass) { + try { + Opcodes opcode = handlerClass.getAnnotation(Opcodes.class); - if (opcode == null || opcode.disabled() || opcode.value() <= 0) { - return; - } + if (opcode == null || opcode.disabled() || opcode.value() <= 0) { + return; + } - PacketHandler packetHandler = handlerClass.getDeclaredConstructor().newInstance(); + PacketHandler packetHandler = handlerClass.getDeclaredConstructor().newInstance(); - this.handlers.put(opcode.value(), packetHandler); - } catch (Exception e) { - e.printStackTrace(); - } - } + this.handlers.put(opcode.value(), packetHandler); + } catch (Exception e) { + e.printStackTrace(); + } + } - public void registerHandlers(Class handlerClass) { - Reflections reflections = new Reflections("emu.grasscutter.server.packet"); - Set handlerClasses = reflections.getSubTypesOf(handlerClass); + public void registerHandlers(Class handlerClass) { + Reflections reflections = new Reflections("emu.grasscutter.server.packet"); + Set handlerClasses = reflections.getSubTypesOf(handlerClass); - for (Object obj : handlerClasses) { - this.registerPacketHandler((Class) obj); - } + for (Object obj : handlerClasses) { + this.registerPacketHandler((Class) obj); + } - // Debug - Grasscutter.getLogger().debug("Registered " + this.handlers.size() + " " + handlerClass.getSimpleName() + "s"); - } + // Debug + Grasscutter.getLogger().debug("Registered " + this.handlers.size() + " " + handlerClass.getSimpleName() + "s"); + } - public void handle(GameSession session, int opcode, byte[] header, byte[] payload) { - PacketHandler handler = this.handlers.get(opcode); + public void handle(GameSession session, int opcode, byte[] header, byte[] payload) { + PacketHandler handler = this.handlers.get(opcode); - if (handler != null) { - try { - // Make sure session is ready for packets - SessionState state = session.getState(); + if (handler != null) { + try { + // Make sure session is ready for packets + SessionState state = session.getState(); - if (opcode == PacketOpcodes.PingReq) { - // Always continue if packet is ping request - } else if (opcode == PacketOpcodes.GetPlayerTokenReq) { - if (state != SessionState.WAITING_FOR_TOKEN) { - return; - } - } else if (opcode == PacketOpcodes.PlayerLoginReq) { - if (state != SessionState.WAITING_FOR_LOGIN) { - return; - } - } else if (opcode == PacketOpcodes.SetPlayerBornDataReq) { - if (state != SessionState.PICKING_CHARACTER) { - return; - } - } else { - if (state != SessionState.ACTIVE) { - return; - } - } + if (opcode == PacketOpcodes.PingReq) { + // Always continue if packet is ping request + } else if (opcode == PacketOpcodes.GetPlayerTokenReq) { + if (state != SessionState.WAITING_FOR_TOKEN) { + return; + } + } else if (opcode == PacketOpcodes.PlayerLoginReq) { + if (state != SessionState.WAITING_FOR_LOGIN) { + return; + } + } else if (opcode == PacketOpcodes.SetPlayerBornDataReq) { + if (state != SessionState.PICKING_CHARACTER) { + return; + } + } else { + if (state != SessionState.ACTIVE) { + return; + } + } - // Invoke event. - ReceivePacketEvent event = new ReceivePacketEvent(session, opcode, payload); event.call(); - if(!event.isCanceled()) // If event is not canceled, continue. - handler.handle(session, header, event.getPacketData()); - } catch (Exception ex) { - // TODO Remove this when no more needed - ex.printStackTrace(); - } - return; // Packet successfully handled - } + // Invoke event. + ReceivePacketEvent event = new ReceivePacketEvent(session, opcode, payload); event.call(); + if (!event.isCanceled()) // If event is not canceled, continue. + handler.handle(session, header, event.getPacketData()); + } catch (Exception ex) { + // TODO Remove this when no more needed + ex.printStackTrace(); + } + return; // Packet successfully handled + } - // Log unhandled packets - if (GAME_INFO.logPackets == ServerDebugMode.MISSING) { - Grasscutter.getLogger().info("Unhandled packet (" + opcode + "): " + emu.grasscutter.net.packet.PacketOpcodesUtils.getOpcodeName(opcode)); - } - } + // Log unhandled packets + if (GAME_INFO.logPackets == ServerDebugMode.MISSING) { + Grasscutter.getLogger().info("Unhandled packet (" + opcode + "): " + emu.grasscutter.net.packet.PacketOpcodesUtils.getOpcodeName(opcode)); + } + } } diff --git a/src/main/java/emu/grasscutter/server/game/GameSession.java b/src/main/java/emu/grasscutter/server/game/GameSession.java index 5d184853c..9d43b0324 100644 --- a/src/main/java/emu/grasscutter/server/game/GameSession.java +++ b/src/main/java/emu/grasscutter/server/game/GameSession.java @@ -21,108 +21,108 @@ import static emu.grasscutter.config.Configuration.*; import static emu.grasscutter.utils.Language.translate; public class GameSession implements GameSessionManager.KcpChannel { - private final GameServer server; - private GameSessionManager.KcpTunnel tunnel; + private final GameServer server; + private GameSessionManager.KcpTunnel tunnel; - private Account account; - private Player player; + private Account account; + private Player player; - private boolean useSecretKey; - private SessionState state; + private boolean useSecretKey; + private SessionState state; - private int clientTime; - private long lastPingTime; - private int lastClientSeq = 10; + private int clientTime; + private long lastPingTime; + private int lastClientSeq = 10; - public GameSession(GameServer server) { - this.server = server; - this.state = SessionState.WAITING_FOR_TOKEN; - this.lastPingTime = System.currentTimeMillis(); - } + public GameSession(GameServer server) { + this.server = server; + this.state = SessionState.WAITING_FOR_TOKEN; + this.lastPingTime = System.currentTimeMillis(); + } - public GameServer getServer() { - return server; - } + public GameServer getServer() { + return server; + } - public InetSocketAddress getAddress() { - try{ - return tunnel.getAddress(); - }catch (Throwable ignore){ - return null; - } - } + public InetSocketAddress getAddress() { + try { + return tunnel.getAddress(); + }catch (Throwable ignore) { + return null; + } + } - public boolean useSecretKey() { - return useSecretKey; - } + public boolean useSecretKey() { + return useSecretKey; + } - public Account getAccount() { - return account; - } + public Account getAccount() { + return account; + } - public void setAccount(Account account) { - this.account = account; - } + public void setAccount(Account account) { + this.account = account; + } - public String getAccountId() { - return this.getAccount().getId(); - } + public String getAccountId() { + return this.getAccount().getId(); + } - public Player getPlayer() { - return player; - } + public Player getPlayer() { + return player; + } - public synchronized void setPlayer(Player player) { - this.player = player; - this.player.setSession(this); - this.player.setAccount(this.getAccount()); - } + public synchronized void setPlayer(Player player) { + this.player = player; + this.player.setSession(this); + this.player.setAccount(this.getAccount()); + } - public SessionState getState() { - return state; - } + public SessionState getState() { + return state; + } - public void setState(SessionState state) { - this.state = state; - } + public void setState(SessionState state) { + this.state = state; + } - public boolean isLoggedIn() { - return this.getPlayer() != null; - } + public boolean isLoggedIn() { + return this.getPlayer() != null; + } - public void setUseSecretKey(boolean useSecretKey) { - this.useSecretKey = useSecretKey; - } + public void setUseSecretKey(boolean useSecretKey) { + this.useSecretKey = useSecretKey; + } - public int getClientTime() { - return this.clientTime; - } + public int getClientTime() { + return this.clientTime; + } - public long getLastPingTime() { - return lastPingTime; - } + public long getLastPingTime() { + return lastPingTime; + } - public void updateLastPingTime(int clientTime) { - this.clientTime = clientTime; - this.lastPingTime = System.currentTimeMillis(); - } + public void updateLastPingTime(int clientTime) { + this.clientTime = clientTime; + this.lastPingTime = System.currentTimeMillis(); + } - public int getNextClientSequence() { - return ++lastClientSeq; - } + public int getNextClientSequence() { + return ++lastClientSeq; + } public void replayPacket(int opcode, String name) { - String filePath = PACKET(name); - File p = new File(filePath); + String filePath = PACKET(name); + File p = new File(filePath); - if (!p.exists()) return; + if (!p.exists()) return; - byte[] packet = FileUtils.read(p); + byte[] packet = FileUtils.read(p); - BasePacket basePacket = new BasePacket(opcode); - basePacket.setData(packet); + BasePacket basePacket = new BasePacket(opcode); + basePacket.setData(packet); - send(basePacket); + send(basePacket); } public void logPacket( String sendOrRecv, int opcode, byte[] payload) { @@ -130,162 +130,162 @@ public class GameSession implements GameSessionManager.KcpChannel { System.out.println(Utils.bytesToHex(payload)); } public void send(BasePacket packet) { - // Test - if (packet.getOpcode() <= 0) { - Grasscutter.getLogger().warn("Tried to send packet with missing cmd id!"); - return; - } + // Test + if (packet.getOpcode() <= 0) { + Grasscutter.getLogger().warn("Tried to send packet with missing cmd id!"); + return; + } - // DO NOT REMOVE (unless we find a way to validate code before sending to client which I don't think we can) - // Stop WindSeedClientNotify from being sent for security purposes. - if(PacketOpcodesUtils.BANNED_PACKETS.contains(packet.getOpcode())) { - return; - } + // DO NOT REMOVE (unless we find a way to validate code before sending to client which I don't think we can) + // Stop WindSeedClientNotify from being sent for security purposes. + if (PacketOpcodesUtils.BANNED_PACKETS.contains(packet.getOpcode())) { + return; + } - // Header - if (packet.shouldBuildHeader()) { - packet.buildHeader(this.getNextClientSequence()); - } + // Header + if (packet.shouldBuildHeader()) { + packet.buildHeader(this.getNextClientSequence()); + } - // Log - switch (GAME_INFO.logPackets) { - case ALL -> { - if (!PacketOpcodesUtils.LOOP_PACKETS.contains(packet.getOpcode())) { + // Log + switch (GAME_INFO.logPackets) { + case ALL -> { + if (!PacketOpcodesUtils.LOOP_PACKETS.contains(packet.getOpcode())) { logPacket("SEND", packet.getOpcode(), packet.getData()); } - } - case WHITELIST-> { - if (SERVER.debugWhitelist.contains(packet.getOpcode())) { - logPacket("SEND", packet.getOpcode(), packet.getData()); - } - } - case BLACKLIST-> { + } + case WHITELIST-> { + if (SERVER.debugWhitelist.contains(packet.getOpcode())) { + logPacket("SEND", packet.getOpcode(), packet.getData()); + } + } + case BLACKLIST-> { if (!SERVER.debugBlacklist.contains(packet.getOpcode())) { logPacket("SEND", packet.getOpcode(), packet.getData()); } } - default -> {} - } + default -> {} + } - // Invoke event. - SendPacketEvent event = new SendPacketEvent(this, packet); event.call(); - if(!event.isCanceled()) { // If event is not cancelled, continue. - tunnel.writeData(event.getPacket().build()); - } + // Invoke event. + SendPacketEvent event = new SendPacketEvent(this, packet); event.call(); + if (!event.isCanceled()) { // If event is not cancelled, continue. + tunnel.writeData(event.getPacket().build()); + } } - @Override - public void onConnected(GameSessionManager.KcpTunnel tunnel) { - this.tunnel = tunnel; - Grasscutter.getLogger().info(translate("messages.game.connect", this.getAddress().toString())); - } + @Override + public void onConnected(GameSessionManager.KcpTunnel tunnel) { + this.tunnel = tunnel; + Grasscutter.getLogger().info(translate("messages.game.connect", this.getAddress().toString())); + } - @Override - public void handleReceive(byte[] bytes) { - // Decrypt and turn back into a packet - Crypto.xor(bytes, useSecretKey() ? Crypto.ENCRYPT_KEY : Crypto.DISPATCH_KEY); - ByteBuf packet = Unpooled.wrappedBuffer(bytes); + @Override + public void handleReceive(byte[] bytes) { + // Decrypt and turn back into a packet + Crypto.xor(bytes, useSecretKey() ? Crypto.ENCRYPT_KEY : Crypto.DISPATCH_KEY); + ByteBuf packet = Unpooled.wrappedBuffer(bytes); - // Log - //logPacket(packet); - // Handle - try { - boolean allDebug = GAME_INFO.logPackets == ServerDebugMode.ALL; - while (packet.readableBytes() > 0) { - // Length - if (packet.readableBytes() < 12) { - return; - } - // Packet sanity check - int const1 = packet.readShort(); - if (const1 != 17767) { - if(allDebug){ - Grasscutter.getLogger().error("Bad Data Package Received: got {} ,expect 17767",const1); - } - return; // Bad packet - } - // Data - int opcode = packet.readShort(); - int headerLength = packet.readShort(); - int payloadLength = packet.readInt(); - byte[] header = new byte[headerLength]; - byte[] payload = new byte[payloadLength]; + // Log + //logPacket(packet); + // Handle + try { + boolean allDebug = GAME_INFO.logPackets == ServerDebugMode.ALL; + while (packet.readableBytes() > 0) { + // Length + if (packet.readableBytes() < 12) { + return; + } + // Packet sanity check + int const1 = packet.readShort(); + if (const1 != 17767) { + if (allDebug) { + Grasscutter.getLogger().error("Bad Data Package Received: got {} ,expect 17767",const1); + } + return; // Bad packet + } + // Data + int opcode = packet.readShort(); + int headerLength = packet.readShort(); + int payloadLength = packet.readInt(); + byte[] header = new byte[headerLength]; + byte[] payload = new byte[payloadLength]; - packet.readBytes(header); - packet.readBytes(payload); - // Sanity check #2 - int const2 = packet.readShort(); - if (const2 != -30293) { - if(allDebug){ - Grasscutter.getLogger().error("Bad Data Package Received: got {} ,expect -30293",const2); - } - return; // Bad packet - } - - // Log packet - switch (GAME_INFO.logPackets) { - case ALL -> { - if (!PacketOpcodesUtils.LOOP_PACKETS.contains(opcode)) { + packet.readBytes(header); + packet.readBytes(payload); + // Sanity check #2 + int const2 = packet.readShort(); + if (const2 != -30293) { + if (allDebug) { + Grasscutter.getLogger().error("Bad Data Package Received: got {} ,expect -30293",const2); + } + return; // Bad packet + } + + // Log packet + switch (GAME_INFO.logPackets) { + case ALL -> { + if (!PacketOpcodesUtils.LOOP_PACKETS.contains(opcode)) { logPacket("RECV",opcode, payload); } - } - case WHITELIST-> { - if (SERVER.debugWhitelist.contains(opcode)) { - logPacket("RECV",opcode, payload); - } - } - case BLACKLIST-> { - if (!(SERVER.debugBlacklist.contains(opcode))) { - logPacket("RECV",opcode, payload); - } - } - default -> {} - } + } + case WHITELIST-> { + if (SERVER.debugWhitelist.contains(opcode)) { + logPacket("RECV",opcode, payload); + } + } + case BLACKLIST-> { + if (!(SERVER.debugBlacklist.contains(opcode))) { + logPacket("RECV",opcode, payload); + } + } + default -> {} + } - // Handle - getServer().getPacketHandler().handle(this, opcode, header, payload); - } - } catch (Exception e) { - e.printStackTrace(); - } finally { - //byteBuf.release(); //Needn't - packet.release(); - } - } + // Handle + getServer().getPacketHandler().handle(this, opcode, header, payload); + } + } catch (Exception e) { + e.printStackTrace(); + } finally { + //byteBuf.release(); //Needn't + packet.release(); + } + } - @Override - public void handleClose() { - setState(SessionState.INACTIVE); - //send disconnection pack in case of reconnection - Grasscutter.getLogger().info(translate("messages.game.disconnect", this.getAddress().toString())); - // Save after disconnecting - if (this.isLoggedIn()) { - Player player = getPlayer(); - // Call logout event. - player.onLogout(); - } - try { - send(new BasePacket(PacketOpcodes.ServerDisconnectClientNotify)); - }catch (Throwable ignore){ - Grasscutter.getLogger().warn("closing {} error",getAddress().getAddress().getHostAddress()); - } - tunnel = null; - } + @Override + public void handleClose() { + setState(SessionState.INACTIVE); + //send disconnection pack in case of reconnection + Grasscutter.getLogger().info(translate("messages.game.disconnect", this.getAddress().toString())); + // Save after disconnecting + if (this.isLoggedIn()) { + Player player = getPlayer(); + // Call logout event. + player.onLogout(); + } + try { + send(new BasePacket(PacketOpcodes.ServerDisconnectClientNotify)); + }catch (Throwable ignore) { + Grasscutter.getLogger().warn("closing {} error",getAddress().getAddress().getHostAddress()); + } + tunnel = null; + } - public void close() { - tunnel.close(); - } + public void close() { + tunnel.close(); + } - public boolean isActive() { - return getState() == SessionState.ACTIVE; - } + public boolean isActive() { + return getState() == SessionState.ACTIVE; + } - public enum SessionState { - INACTIVE, - WAITING_FOR_TOKEN, - WAITING_FOR_LOGIN, - PICKING_CHARACTER, - ACTIVE - } + public enum SessionState { + INACTIVE, + WAITING_FOR_TOKEN, + WAITING_FOR_LOGIN, + PICKING_CHARACTER, + ACTIVE + } } diff --git a/src/main/java/emu/grasscutter/server/http/HttpServer.java b/src/main/java/emu/grasscutter/server/http/HttpServer.java index a4a0e704a..7058493de 100644 --- a/src/main/java/emu/grasscutter/server/http/HttpServer.java +++ b/src/main/java/emu/grasscutter/server/http/HttpServer.java @@ -30,22 +30,22 @@ public final class HttpServer { this.express = new Express(config -> { // Set the Express HTTP server. config.server(HttpServer::createServer); - + // Configure encryption/HTTPS/SSL. config.enforceSsl = HTTP_ENCRYPTION.useEncryption; - + // Configure HTTP policies. - if(HTTP_POLICIES.cors.enabled) { + if (HTTP_POLICIES.cors.enabled) { var allowedOrigins = HTTP_POLICIES.cors.allowedOrigins; if (allowedOrigins.length > 0) config.enableCorsForOrigin(allowedOrigins); else config.enableCorsForAllOrigins(); } - + // Configure debug logging. - if(DISPATCH_INFO.logRequests == ServerDebugMode.ALL) + if (DISPATCH_INFO.logRequests == ServerDebugMode.ALL) config.enableDevLogging(); - + // Disable compression on static files. config.precompressStaticFiles = false; }); @@ -60,26 +60,26 @@ public final class HttpServer { Server server = new Server(); ServerConnector serverConnector = new ServerConnector(server); - - if(HTTP_ENCRYPTION.useEncryption) { + + if (HTTP_ENCRYPTION.useEncryption) { var sslContextFactory = new SslContextFactory.Server(); var keystoreFile = new File(HTTP_ENCRYPTION.keystore); - - if(!keystoreFile.exists()) { + + if (!keystoreFile.exists()) { HTTP_ENCRYPTION.useEncryption = false; HTTP_ENCRYPTION.useInRouting = false; - + Grasscutter.getLogger().warn(translate("messages.dispatch.keystore.no_keystore_error")); } else try { sslContextFactory.setKeyStorePath(keystoreFile.getPath()); sslContextFactory.setKeyStorePassword(HTTP_ENCRYPTION.keystorePassword); } catch (Exception ignored) { Grasscutter.getLogger().warn(translate("messages.dispatch.keystore.password_error")); - + try { sslContextFactory.setKeyStorePath(keystoreFile.getPath()); sslContextFactory.setKeyStorePassword("123456"); - + Grasscutter.getLogger().warn(translate("messages.dispatch.keystore.default_password")); } catch (Exception exception) { Grasscutter.getLogger().warn(translate("messages.dispatch.keystore.general_error"), exception); @@ -88,10 +88,10 @@ public final class HttpServer { serverConnector = new ServerConnector(server, sslContextFactory); } } - + serverConnector.setPort(HTTP_INFO.bindPort); server.setConnectors(new ServerConnector[]{serverConnector}); - + return server; } @@ -112,9 +112,9 @@ public final class HttpServer { public HttpServer addRouter(Class router, Object... args) { // Get all constructor parameters. Class[] types = new Class[args.length]; - for(var argument : args) + for (var argument : args) types[args.length - 1] = argument.getClass(); - + try { // Create a router instance & apply routes. var constructor = router.getDeclaredConstructor(types); // Get the constructor. var routerInstance = constructor.newInstance(args); // Create instance. @@ -130,9 +130,9 @@ public final class HttpServer { */ public void start() throws UnsupportedEncodingException { // Attempt to start the HTTP server. - if(HTTP_INFO.bindAddress.equals("")){ + if (HTTP_INFO.bindAddress.equals("")) { this.express.listen(HTTP_INFO.bindPort); - }else{ + }else { this.express.listen(HTTP_INFO.bindAddress, HTTP_INFO.bindPort); } @@ -147,7 +147,7 @@ public final class HttpServer { @Override public void applyRoutes(Express express, Javalin handle) { express.get("/", (request, response) -> { File file = new File(HTTP_STATIC_FILES.indexFile); - if(!file.exists()) + if (!file.exists()) response.send(""" @@ -173,19 +173,19 @@ public final class HttpServer { public static class UnhandledRequestRouter implements Router { @Override public void applyRoutes(Express express, Javalin handle) { handle.error(404, context -> { - if(DISPATCH_INFO.logRequests == ServerDebugMode.MISSING) + if (DISPATCH_INFO.logRequests == ServerDebugMode.MISSING) Grasscutter.getLogger().info(translate("messages.dispatch.unhandled_request_error", context.method(), context.url())); context.contentType("text/html"); - + File file = new File(HTTP_STATIC_FILES.errorFile); - if(!file.exists()) + if (!file.exists()) context.result(""" - + diff --git a/src/main/java/emu/grasscutter/server/http/dispatch/RegionHandler.java b/src/main/java/emu/grasscutter/server/http/dispatch/RegionHandler.java index e9af92cb3..790191540 100644 --- a/src/main/java/emu/grasscutter/server/http/dispatch/RegionHandler.java +++ b/src/main/java/emu/grasscutter/server/http/dispatch/RegionHandler.java @@ -60,7 +60,7 @@ public final class RegionHandler implements Router { List usedNames = new ArrayList<>(); // List to check for potential naming conflicts. var configuredRegions = new ArrayList<>(List.of(DISPATCH_INFO.regions)); - if(SERVER.runMode != ServerRunMode.HYBRID && configuredRegions.size() == 0) { + if (SERVER.runMode != ServerRunMode.HYBRID && configuredRegions.size() == 0) { Grasscutter.getLogger().error("[Dispatch] There are no game servers available. Exiting due to unplayable state."); System.exit(1); } else if (configuredRegions.size() == 0) @@ -136,11 +136,11 @@ public final class RegionHandler implements Router { // Get region data. String regionData = "CAESGE5vdCBGb3VuZCB2ZXJzaW9uIGNvbmZpZw=="; if (request.query().values().size() > 0) { - if(region != null) + if (region != null) regionData = region.getBase64(); } - if( versionName.contains("2.7.5") || versionName.contains("2.8.")) { + if ( versionName.contains("2.7.5") || versionName.contains("2.8.")) { try { QueryCurrentRegionEvent event = new QueryCurrentRegionEvent(regionData); event.call(); @@ -227,4 +227,4 @@ public final class RegionHandler implements Router { public static QueryCurrRegionHttpRsp getCurrentRegion() { return SERVER.runMode == ServerRunMode.HYBRID ? regions.get("os_usa").getRegionQuery() : null; } -} \ No newline at end of file +} diff --git a/src/main/java/emu/grasscutter/server/http/handlers/AnnouncementsHandler.java b/src/main/java/emu/grasscutter/server/http/handlers/AnnouncementsHandler.java index f2c04be7e..69ebc6b96 100644 --- a/src/main/java/emu/grasscutter/server/http/handlers/AnnouncementsHandler.java +++ b/src/main/java/emu/grasscutter/server/http/handlers/AnnouncementsHandler.java @@ -39,14 +39,14 @@ public final class AnnouncementsHandler implements Router { express.get("/hk4e/announcement/*", AnnouncementsHandler::getPageResources); } - + private static void getAnnouncement(Request request, Response response) { String data = ""; if (Objects.equals(request.baseUrl(), "/common/hk4e_global/announcement/api/getAnnContent")) { try { data = FileUtils.readToString(DataLoader.load("GameAnnouncement.json")); } catch (Exception e) { - if(e.getClass() == IOException.class) { + if (e.getClass() == IOException.class) { Grasscutter.getLogger().info("Unable to read file 'GameAnnouncementList.json'. \n" + e); } } @@ -54,7 +54,7 @@ public final class AnnouncementsHandler implements Router { try { data = FileUtils.readToString(DataLoader.load("GameAnnouncementList.json")); } catch (Exception e) { - if(e.getClass() == IOException.class) { + if (e.getClass() == IOException.class) { Grasscutter.getLogger().info("Unable to read file 'GameAnnouncementList.json'. \n" + e); } } @@ -76,9 +76,9 @@ public final class AnnouncementsHandler implements Router { .replace("{{SYSTEM_TIME}}", String.valueOf(System.currentTimeMillis())); response.send("{\"retcode\":0,\"message\":\"OK\",\"data\": " + data + "}"); } - + private static void getPageResources(Request request, Response response) { - try(InputStream filestream = DataLoader.load(request.path())) { + try (InputStream filestream = DataLoader.load(request.path())) { String possibleFilename = Utils.toFilePath(DATA(request.path())); MediaType fromExtension = MediaType.getByExtension(possibleFilename.substring(possibleFilename.lastIndexOf(".") + 1)); diff --git a/src/main/java/emu/grasscutter/server/http/handlers/GachaHandler.java b/src/main/java/emu/grasscutter/server/http/handlers/GachaHandler.java index 7c42555ae..38548b1d6 100644 --- a/src/main/java/emu/grasscutter/server/http/handlers/GachaHandler.java +++ b/src/main/java/emu/grasscutter/server/http/handlers/GachaHandler.java @@ -30,14 +30,14 @@ import static emu.grasscutter.utils.Language.translate; */ public final class GachaHandler implements Router { public static final String gachaMappings = DATA(Utils.toFilePath("gacha/mappings.js")); - + @Override public void applyRoutes(Express express, Javalin handle) { express.get("/gacha", GachaHandler::gachaRecords); express.get("/gacha/details", GachaHandler::gachaDetails); - + express.useStaticFallback("/gacha/mappings", gachaMappings, Location.EXTERNAL); } - + private static void gachaRecords(Request request, Response response) { File recordsTemplate = new File(Utils.toFilePath(DATA("gacha/records.html"))); if (!recordsTemplate.exists()) { @@ -48,7 +48,7 @@ public final class GachaHandler implements Router { String sessionKey = request.query("s"); Account account = DatabaseHelper.getAccountBySessionKey(sessionKey); - if(account == null) { + if (account == null) { response.status(403).send("Requested account was not found"); return; } @@ -59,9 +59,9 @@ public final class GachaHandler implements Router { } int page = 0, gachaType = 0; - if(request.query("p") != null) + if (request.query("p") != null) page = Integer.parseInt(request.query("p")); - if(request.query("gachaType") != null) + if (request.query("gachaType") != null) gachaType = Integer.parseInt(request.query("gachaType")); String records = DatabaseHelper.getGachaRecords(player.getUid(), page, gachaType).toString(); @@ -76,7 +76,7 @@ public final class GachaHandler implements Router { .replace("{{LANGUAGE}}", Utils.getLanguageCode(account.getLocale())); response.send(template); } - + private static void gachaDetails(Request request, Response response) { File detailsTemplate = new File(Utils.toFilePath(DATA("gacha/details.html"))); if (!detailsTemplate.exists()) { @@ -87,7 +87,7 @@ public final class GachaHandler implements Router { String sessionKey = request.query("s"); Account account = DatabaseHelper.getAccountBySessionKey(sessionKey); - if(account == null) { + if (account == null) { response.status(403).send("Requested account was not found"); return; } diff --git a/src/main/java/emu/grasscutter/server/http/handlers/GenericHandler.java b/src/main/java/emu/grasscutter/server/http/handlers/GenericHandler.java index 664bbed60..4c32d3d2a 100644 --- a/src/main/java/emu/grasscutter/server/http/handlers/GenericHandler.java +++ b/src/main/java/emu/grasscutter/server/http/handlers/GenericHandler.java @@ -25,7 +25,7 @@ public final class GenericHandler implements Router { // api-account-os.hoyoverse.com express.post("/account/risky/api/check", new HttpJsonResponse("{\"retcode\":0,\"message\":\"OK\",\"data\":{\"id\":\"none\",\"action\":\"ACTION_NONE\",\"geetest\":null}}")); - + // sdk-os-static.hoyoverse.com express.get("/combo/box/api/config/sdk/combo", new HttpJsonResponse("{\"retcode\":0,\"message\":\"OK\",\"data\":{\"vals\":{\"disable_email_bind_skip\":\"false\",\"email_bind_remind_interval\":\"7\",\"email_bind_remind\":\"true\"}}}")); // hk4e-sdk-os-static.hoyoverse.com @@ -35,7 +35,7 @@ public final class GenericHandler implements Router { // Test api? // abtest-api-data-sg.hoyoverse.com express.post("/data_abtest_api/config/experiment/list", new HttpJsonResponse("{\"retcode\":0,\"success\":true,\"message\":\"\",\"data\":[{\"code\":1000,\"type\":2,\"config_id\":\"14\",\"period_id\":\"6036_99\",\"version\":\"1\",\"configs\":{\"cardType\":\"old\"}}]}")); - + // log-upload-os.mihoyo.com express.all("/log/sdk/upload", new HttpJsonResponse("{\"code\":0}")); express.all("/sdk/upload", new HttpJsonResponse("{\"code\":0}")); @@ -45,10 +45,10 @@ public final class GenericHandler implements Router { // webstatic-sea.hoyoverse.com express.get("/admin/mi18n/plat_oversea/*", new WebStaticVersionResponse()); - + express.get("/status/server", GenericHandler::serverStatus); } - + private static void serverStatus(Request request, Response response) { int playerCount = Grasscutter.getGameServer().getPlayers().size(); int maxPlayer = ACCOUNT.maxPlayer; diff --git a/src/main/java/emu/grasscutter/server/http/objects/HttpJsonResponse.java b/src/main/java/emu/grasscutter/server/http/objects/HttpJsonResponse.java index 147259161..327445f22 100644 --- a/src/main/java/emu/grasscutter/server/http/objects/HttpJsonResponse.java +++ b/src/main/java/emu/grasscutter/server/http/objects/HttpJsonResponse.java @@ -14,30 +14,30 @@ import static emu.grasscutter.config.Configuration.*; import static emu.grasscutter.utils.Language.translate; public final class HttpJsonResponse implements HttpContextHandler { - private final String response; - private final String[] missingRoutes = { // TODO: When http requests for theses routes are found please remove it from this list and update the route request type in the DispatchServer - "/common/hk4e_global/announcement/api/getAlertPic", - "/common/hk4e_global/announcement/api/getAlertAnn", - "/common/hk4e_global/announcement/api/getAnnList", - "/common/hk4e_global/announcement/api/getAnnContent", - "/hk4e_global/mdk/shopwindow/shopwindow/listPriceTier", - "/log/sdk/upload", - "/sdk/upload", - "/perf/config/verify", - "/log", - "/crash/dataUpload" - }; - - public HttpJsonResponse(String response) { - this.response = response; - } + private final String response; + private final String[] missingRoutes = { // TODO: When http requests for theses routes are found please remove it from this list and update the route request type in the DispatchServer + "/common/hk4e_global/announcement/api/getAlertPic", + "/common/hk4e_global/announcement/api/getAlertAnn", + "/common/hk4e_global/announcement/api/getAnnList", + "/common/hk4e_global/announcement/api/getAnnContent", + "/hk4e_global/mdk/shopwindow/shopwindow/listPriceTier", + "/log/sdk/upload", + "/sdk/upload", + "/perf/config/verify", + "/log", + "/crash/dataUpload" + }; - @Override - public void handle(Request req, Response res) throws IOException { - // Checking for ALL here isn't required as when ALL is enabled enableDevLogging() gets enabled - if(DISPATCH_INFO.logRequests == ServerDebugMode.MISSING && Arrays.stream(missingRoutes).anyMatch(x -> Objects.equals(x, req.baseUrl()))) { - Grasscutter.getLogger().info(translate("messages.dispatch.request", req.ip(), req.method(), req.baseUrl()) + (DISPATCH_INFO.logRequests == ServerDebugMode.MISSING ? "(MISSING)" : "")); - } - res.send(response); - } + public HttpJsonResponse(String response) { + this.response = response; + } + + @Override + public void handle(Request req, Response res) throws IOException { + // Checking for ALL here isn't required as when ALL is enabled enableDevLogging() gets enabled + if (DISPATCH_INFO.logRequests == ServerDebugMode.MISSING && Arrays.stream(missingRoutes).anyMatch(x -> Objects.equals(x, req.baseUrl()))) { + Grasscutter.getLogger().info(translate("messages.dispatch.request", req.ip(), req.method(), req.baseUrl()) + (DISPATCH_INFO.logRequests == ServerDebugMode.MISSING ? "(MISSING)" : "")); + } + res.send(response); + } } diff --git a/src/main/java/emu/grasscutter/server/http/objects/WebStaticVersionResponse.java b/src/main/java/emu/grasscutter/server/http/objects/WebStaticVersionResponse.java index 111451bf8..ec0f973fb 100644 --- a/src/main/java/emu/grasscutter/server/http/objects/WebStaticVersionResponse.java +++ b/src/main/java/emu/grasscutter/server/http/objects/WebStaticVersionResponse.java @@ -27,13 +27,13 @@ public class WebStaticVersionResponse implements HttpContextHandler { } private static void getPageResources(String path, Response response) { - try(InputStream filestream = FileUtils.readResourceAsStream(path)) { + try (InputStream filestream = FileUtils.readResourceAsStream(path)) { MediaType fromExtension = MediaType.getByExtension(path.substring(path.lastIndexOf(".") + 1)); response.type((fromExtension != null) ? fromExtension.getMIME() : "application/octet-stream"); response.send(filestream.readAllBytes()); } catch (Exception e) { - if(DISPATCH_INFO.logRequests == Grasscutter.ServerDebugMode.MISSING) { + if (DISPATCH_INFO.logRequests == Grasscutter.ServerDebugMode.MISSING) { Grasscutter.getLogger().warn("Webstatic File Missing: " + path); } response.status(404); diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarExpeditionGetRewardReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarExpeditionGetRewardReq.java index aaacd7954..835017d59 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarExpeditionGetRewardReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarExpeditionGetRewardReq.java @@ -36,11 +36,11 @@ public class HandlerAvatarExpeditionGetRewardReq extends PacketHandler { if (session.getServer().getExpeditionSystem().getExpeditionRewardDataList().containsKey(expInfo.getExpId())) { for (ExpeditionRewardDataList RewardDataList : session.getServer().getExpeditionSystem().getExpeditionRewardDataList().get(expInfo.getExpId())) { - if(RewardDataList.getHourTime() == expInfo.getHourTime()){ - if(!RewardDataList.getExpeditionRewardData().isEmpty()){ + if (RewardDataList.getHourTime() == expInfo.getHourTime()) { + if (!RewardDataList.getExpeditionRewardData().isEmpty()) { for (ExpeditionRewardData RewardData :RewardDataList.getExpeditionRewardData()) { int num = RewardData.getMinCount(); - if(RewardData.getMinCount() != RewardData.getMaxCount()){ + if (RewardData.getMinCount() != RewardData.getMaxCount()) { num = Utils.randomRange(RewardData.getMinCount(), RewardData.getMaxCount()); } items.add(new GameItem(RewardData.getItemId(), num)); diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarPromoteReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarPromoteReq.java index 5914f98c9..6b2540850 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarPromoteReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarPromoteReq.java @@ -8,13 +8,13 @@ import emu.grasscutter.server.game.GameSession; @Opcodes(PacketOpcodes.AvatarPromoteReq) public class HandlerAvatarPromoteReq extends PacketHandler { - - @Override - public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - AvatarPromoteReq req = AvatarPromoteReq.parseFrom(payload); - - // Ascend avatar - session.getServer().getInventorySystem().promoteAvatar(session.getPlayer(), req.getGuid()); - } + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + AvatarPromoteReq req = AvatarPromoteReq.parseFrom(payload); + + // Ascend avatar + session.getServer().getInventorySystem().promoteAvatar(session.getPlayer(), req.getGuid()); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarSkillUpgradeReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarSkillUpgradeReq.java index 188e754fe..a371a8e83 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarSkillUpgradeReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarSkillUpgradeReq.java @@ -8,13 +8,13 @@ import emu.grasscutter.server.game.GameSession; @Opcodes(PacketOpcodes.AvatarSkillUpgradeReq) public class HandlerAvatarSkillUpgradeReq extends PacketHandler { - - @Override - public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - AvatarSkillUpgradeReq req = AvatarSkillUpgradeReq.parseFrom(payload); - - // Level up avatar talent - session.getServer().getInventorySystem().upgradeAvatarSkill(session.getPlayer(), req.getAvatarGuid(), req.getAvatarSkillId()); - } + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + AvatarSkillUpgradeReq req = AvatarSkillUpgradeReq.parseFrom(payload); + + // Level up avatar talent + session.getServer().getInventorySystem().upgradeAvatarSkill(session.getPlayer(), req.getAvatarGuid(), req.getAvatarSkillId()); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarUpgradeReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarUpgradeReq.java index 93fa0a7a3..e13cec34c 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarUpgradeReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerAvatarUpgradeReq.java @@ -8,18 +8,18 @@ import emu.grasscutter.server.game.GameSession; @Opcodes(PacketOpcodes.AvatarUpgradeReq) public class HandlerAvatarUpgradeReq extends PacketHandler { - - @Override - public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - AvatarUpgradeReq req = AvatarUpgradeReq.parseFrom(payload); - - // Level up avatar - session.getServer().getInventorySystem().upgradeAvatar( - session.getPlayer(), - req.getAvatarGuid(), - req.getItemId(), - req.getCount() - ); - } + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + AvatarUpgradeReq req = AvatarUpgradeReq.parseFrom(payload); + + // Level up avatar + session.getServer().getInventorySystem().upgradeAvatar( + session.getPlayer(), + req.getAvatarGuid(), + req.getItemId(), + req.getCount() + ); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerCalcWeaponUpgradeReturnItemsReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerCalcWeaponUpgradeReturnItemsReq.java index cc7a06e7b..3d26b5432 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerCalcWeaponUpgradeReturnItemsReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerCalcWeaponUpgradeReturnItemsReq.java @@ -12,23 +12,23 @@ import emu.grasscutter.server.packet.send.PacketCalcWeaponUpgradeReturnItemsRsp; @Opcodes(PacketOpcodes.CalcWeaponUpgradeReturnItemsReq) public class HandlerCalcWeaponUpgradeReturnItemsReq extends PacketHandler { - - @Override - public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - CalcWeaponUpgradeReturnItemsReq req = CalcWeaponUpgradeReturnItemsReq.parseFrom(payload); - - List returnOres = session.getServer().getInventorySystem().calcWeaponUpgradeReturnItems( - session.getPlayer(), - req.getTargetWeaponGuid(), - req.getFoodWeaponGuidListList(), - req.getItemParamListList() - ); - - if (returnOres != null) { - session.send(new PacketCalcWeaponUpgradeReturnItemsRsp(req.getTargetWeaponGuid(), returnOres)); - } else { - session.send(new PacketCalcWeaponUpgradeReturnItemsRsp()); - } - } + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + CalcWeaponUpgradeReturnItemsReq req = CalcWeaponUpgradeReturnItemsReq.parseFrom(payload); + + List returnOres = session.getServer().getInventorySystem().calcWeaponUpgradeReturnItems( + session.getPlayer(), + req.getTargetWeaponGuid(), + req.getFoodWeaponGuidListList(), + req.getItemParamListList() + ); + + if (returnOres != null) { + session.send(new PacketCalcWeaponUpgradeReturnItemsRsp(req.getTargetWeaponGuid(), returnOres)); + } else { + session.send(new PacketCalcWeaponUpgradeReturnItemsRsp()); + } + } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerCombineReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerCombineReq.java index b8d80eb3d..cbcd1f038 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerCombineReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerCombineReq.java @@ -24,7 +24,7 @@ public class HandlerCombineReq extends PacketHandler { var result = session.getServer().getCombineSystem() .combineItem(session.getPlayer(), req.getCombineId(), req.getCombineCount()); - if(result == null){ + if (result == null) { return; } @@ -36,7 +36,7 @@ public class HandlerCombineReq extends PacketHandler { toItemParamList(result.getBack()))); } - private List toItemParamList(List list){ + private List toItemParamList(List list) { return list.stream() .map(item -> ItemParamOuterClass.ItemParam.newBuilder() .setItemId(item.getId()) diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerDestroyMaterialReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerDestroyMaterialReq.java index 35626e97a..9a5e63397 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerDestroyMaterialReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerDestroyMaterialReq.java @@ -8,11 +8,11 @@ import emu.grasscutter.server.game.GameSession; @Opcodes(PacketOpcodes.DestroyMaterialReq) public class HandlerDestroyMaterialReq extends PacketHandler { - @Override - public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - DestroyMaterialReq req = DestroyMaterialReq.parseFrom(payload); - - // Delete items - session.getServer().getInventorySystem().destroyMaterial(session.getPlayer(), req.getMaterialListList()); - } + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + DestroyMaterialReq req = DestroyMaterialReq.parseFrom(payload); + + // Delete items + session.getServer().getInventorySystem().destroyMaterial(session.getPlayer(), req.getMaterialListList()); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerDoGachaReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerDoGachaReq.java index 8a69f3edc..e8ad28e10 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerDoGachaReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerDoGachaReq.java @@ -8,10 +8,10 @@ import emu.grasscutter.server.game.GameSession; @Opcodes(PacketOpcodes.DoGachaReq) public class HandlerDoGachaReq extends PacketHandler { - @Override - public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - DoGachaReq req = DoGachaReq.parseFrom(payload); - - session.getServer().getGachaSystem().doPulls(session.getPlayer(), req.getGachaScheduleId(), req.getGachaTimes()); - } + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + DoGachaReq req = DoGachaReq.parseFrom(payload); + + session.getServer().getGachaSystem().doPulls(session.getPlayer(), req.getGachaScheduleId(), req.getGachaTimes()); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerDungeonEntryInfoReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerDungeonEntryInfoReq.java index 006f3c73c..34ad24be7 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerDungeonEntryInfoReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerDungeonEntryInfoReq.java @@ -8,12 +8,12 @@ import emu.grasscutter.server.game.GameSession; @Opcodes(PacketOpcodes.DungeonEntryInfoReq) public class HandlerDungeonEntryInfoReq extends PacketHandler { - - @Override - public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - DungeonEntryInfoReq req = DungeonEntryInfoReq.parseFrom(payload); - - session.getServer().getDungeonSystem().getEntryInfo(session.getPlayer(), req.getPointId()); - } + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + DungeonEntryInfoReq req = DungeonEntryInfoReq.parseFrom(payload); + + session.getServer().getDungeonSystem().getEntryInfo(session.getPlayer(), req.getPointId()); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetGachaInfoReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetGachaInfoReq.java index afa4c9612..085952b93 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetGachaInfoReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetGachaInfoReq.java @@ -11,10 +11,10 @@ import emu.grasscutter.server.packet.send.PacketGetGachaInfoRsp; @Opcodes(PacketOpcodes.GetGachaInfoReq) public class HandlerGetGachaInfoReq extends PacketHandler { - - @Override - public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - session.send(new PacketGetGachaInfoRsp(session.getServer().getGachaSystem(), session.getPlayer())); - } + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + session.send(new PacketGetGachaInfoRsp(session.getServer().getGachaSystem(), session.getPlayer())); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetInvestigationMonsterReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetInvestigationMonsterReq.java index f3ca23ce0..27a2f6cf6 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetInvestigationMonsterReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetInvestigationMonsterReq.java @@ -9,16 +9,16 @@ import emu.grasscutter.server.packet.send.PacketGetInvestigationMonsterRsp; @Opcodes(PacketOpcodes.GetInvestigationMonsterReq) public class HandlerGetInvestigationMonsterReq extends PacketHandler { - - @Override - public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - var req = GetInvestigationMonsterReqOuterClass.GetInvestigationMonsterReq.parseFrom(payload); - session.send(new PacketGetInvestigationMonsterRsp( - session.getPlayer(), - session.getServer().getWorldDataSystem(), - req.getCityIdListList())); + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + var req = GetInvestigationMonsterReqOuterClass.GetInvestigationMonsterReq.parseFrom(payload); - } + session.send(new PacketGetInvestigationMonsterRsp( + session.getPlayer(), + session.getServer().getWorldDataSystem(), + req.getCityIdListList())); + + } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetPlayerTokenReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetPlayerTokenReq.java index c73019a9a..0b54a4f9a 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetPlayerTokenReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerGetPlayerTokenReq.java @@ -27,77 +27,77 @@ import java.security.Signature; @Opcodes(PacketOpcodes.GetPlayerTokenReq) public class HandlerGetPlayerTokenReq extends PacketHandler { - @Override - public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - GetPlayerTokenReq req = GetPlayerTokenReq.parseFrom(payload); + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + GetPlayerTokenReq req = GetPlayerTokenReq.parseFrom(payload); - // Authenticate - Account account = DatabaseHelper.getAccountById(req.getAccountUid()); - if (account == null || !account.getToken().equals(req.getAccountToken())) { - return; - } + // Authenticate + Account account = DatabaseHelper.getAccountById(req.getAccountUid()); + if (account == null || !account.getToken().equals(req.getAccountToken())) { + return; + } - // Set account - session.setAccount(account); + // Set account + session.setAccount(account); - // Check if player object exists in server - // NOTE: CHECKING MUST SITUATED HERE (BEFORE getPlayerByUid)! because to save firstly ,to load secondly !!! - // TODO - optimize - boolean kicked = false; - Player exists = Grasscutter.getGameServer().getPlayerByAccountId(account.getId()); - if (exists != null) { - GameSession existsSession = exists.getSession(); - if (existsSession != session) {// No self-kicking - exists.onLogout();//must save immediately , or the below will load old data - existsSession.close(); - Grasscutter.getLogger().warn("Player {} was kicked due to duplicated login", account.getUsername()); - kicked = true; - } - } + // Check if player object exists in server + // NOTE: CHECKING MUST SITUATED HERE (BEFORE getPlayerByUid)! because to save firstly ,to load secondly !!! + // TODO - optimize + boolean kicked = false; + Player exists = Grasscutter.getGameServer().getPlayerByAccountId(account.getId()); + if (exists != null) { + GameSession existsSession = exists.getSession(); + if (existsSession != session) {// No self-kicking + exists.onLogout();//must save immediately , or the below will load old data + existsSession.close(); + Grasscutter.getLogger().warn("Player {} was kicked due to duplicated login", account.getUsername()); + kicked = true; + } + } - //NOTE: If there are 5 online players, max count of player is 5, - // a new client want to login by kicking one of them , - // I think it should be allowed - if(!kicked) { - // Max players limit - if (ACCOUNT.maxPlayer > -1 && Grasscutter.getGameServer().getPlayers().size() >= ACCOUNT.maxPlayer) { - session.close(); - return; - } - } + //NOTE: If there are 5 online players, max count of player is 5, + // a new client want to login by kicking one of them , + // I think it should be allowed + if (!kicked) { + // Max players limit + if (ACCOUNT.maxPlayer > -1 && Grasscutter.getGameServer().getPlayers().size() >= ACCOUNT.maxPlayer) { + session.close(); + return; + } + } // Call creation event. PlayerCreationEvent event = new PlayerCreationEvent(session, Player.class); event.call(); - // Get player. - Player player = DatabaseHelper.getPlayerByAccount(account, event.getPlayerClass()); + // Get player. + Player player = DatabaseHelper.getPlayerByAccount(account, event.getPlayerClass()); - if (player == null) { - int nextPlayerUid = DatabaseHelper.getNextPlayerId(session.getAccount().getReservedPlayerUid()); + if (player == null) { + int nextPlayerUid = DatabaseHelper.getNextPlayerId(session.getAccount().getReservedPlayerUid()); - // Create player instance from event. - player = event.getPlayerClass().getDeclaredConstructor(GameSession.class).newInstance(session); + // Create player instance from event. + player = event.getPlayerClass().getDeclaredConstructor(GameSession.class).newInstance(session); - // Save to db - DatabaseHelper.generatePlayerUid(player, nextPlayerUid); - } + // Save to db + DatabaseHelper.generatePlayerUid(player, nextPlayerUid); + } - // Set player object for session - session.setPlayer(player); + // Set player object for session + session.setPlayer(player); - // Checks if the player is banned - if (session.getAccount().isBanned()) { - session.send(new PacketGetPlayerTokenRsp(session, 21, "FORBID_CHEATING_PLUGINS", session.getAccount().getBanEndTime())); - session.close(); - return; - } + // Checks if the player is banned + if (session.getAccount().isBanned()) { + session.send(new PacketGetPlayerTokenRsp(session, 21, "FORBID_CHEATING_PLUGINS", session.getAccount().getBanEndTime())); + session.close(); + return; + } - // Load player from database - player.loadFromDatabase(); + // Load player from database + player.loadFromDatabase(); - // Set session state - session.setUseSecretKey(true); - session.setState(SessionState.WAITING_FOR_LOGIN); + // Set session state + session.setUseSecretKey(true); + session.setState(SessionState.WAITING_FOR_LOGIN); // Only >= 2.7.50 has this if (req.getKeyId() > 0) { diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeUnknown2Req.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeUnknown2Req.java index 517f9c17e..467449067 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeUnknown2Req.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerHomeUnknown2Req.java @@ -8,13 +8,13 @@ import emu.grasscutter.server.packet.send.PacketHomeUnknown2Rsp; @Opcodes(PacketOpcodes.Unk2700_ACILPONNGGK_ClientReq) public class HandlerHomeUnknown2Req extends PacketHandler { - - @Override - public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - /* - * This packet is about the edit mode - */ - session.send(new PacketHomeUnknown2Rsp()); - } + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + /* + * This packet is about the edit mode + */ + session.send(new PacketHomeUnknown2Rsp()); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerApplyEnterMpReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerApplyEnterMpReq.java index e2e1309ad..3e1e7ffb1 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerApplyEnterMpReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerApplyEnterMpReq.java @@ -9,13 +9,13 @@ import emu.grasscutter.server.packet.send.PacketPlayerApplyEnterMpRsp; @Opcodes(PacketOpcodes.PlayerApplyEnterMpReq) public class HandlerPlayerApplyEnterMpReq extends PacketHandler { - - @Override - public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - PlayerApplyEnterMpReq req = PlayerApplyEnterMpReq.parseFrom(payload); - - session.getServer().getMultiplayerSystem().applyEnterMp(session.getPlayer(), req.getTargetUid()); - session.send(new PacketPlayerApplyEnterMpRsp(req.getTargetUid())); - } + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + PlayerApplyEnterMpReq req = PlayerApplyEnterMpReq.parseFrom(payload); + + session.getServer().getMultiplayerSystem().applyEnterMp(session.getPlayer(), req.getTargetUid()); + session.send(new PacketPlayerApplyEnterMpRsp(req.getTargetUid())); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerApplyEnterMpResultReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerApplyEnterMpResultReq.java index 7589190aa..418266468 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerApplyEnterMpResultReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerApplyEnterMpResultReq.java @@ -9,13 +9,13 @@ import emu.grasscutter.server.packet.send.PacketPlayerApplyEnterMpResultRsp; @Opcodes(PacketOpcodes.PlayerApplyEnterMpResultReq) public class HandlerPlayerApplyEnterMpResultReq extends PacketHandler { - - @Override - public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - PlayerApplyEnterMpResultReq req = PlayerApplyEnterMpResultReq.parseFrom(payload); - - session.getServer().getMultiplayerSystem().applyEnterMpReply(session.getPlayer(), req.getApplyUid(), req.getIsAgreed()); - session.send(new PacketPlayerApplyEnterMpResultRsp(req.getApplyUid(), req.getIsAgreed())); - } + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + PlayerApplyEnterMpResultReq req = PlayerApplyEnterMpResultReq.parseFrom(payload); + + session.getServer().getMultiplayerSystem().applyEnterMpReply(session.getPlayer(), req.getApplyUid(), req.getIsAgreed()); + session.send(new PacketPlayerApplyEnterMpResultRsp(req.getApplyUid(), req.getIsAgreed())); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerEnterDungeonReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerEnterDungeonReq.java index 162eec998..f76ff588c 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerEnterDungeonReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerEnterDungeonReq.java @@ -8,13 +8,13 @@ import emu.grasscutter.server.game.GameSession; @Opcodes(PacketOpcodes.PlayerEnterDungeonReq) public class HandlerPlayerEnterDungeonReq extends PacketHandler { - - @Override - public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - // Auto template - PlayerEnterDungeonReq req = PlayerEnterDungeonReq.parseFrom(payload); - - session.getServer().getDungeonSystem().enterDungeon(session.getPlayer(), req.getPointId(), req.getDungeonId()); - } + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + // Auto template + PlayerEnterDungeonReq req = PlayerEnterDungeonReq.parseFrom(payload); + + session.getServer().getDungeonSystem().enterDungeon(session.getPlayer(), req.getPointId(), req.getDungeonId()); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerGetForceQuitBanInfoReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerGetForceQuitBanInfoReq.java index f0b5311a9..7da3bbcb8 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerGetForceQuitBanInfoReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerGetForceQuitBanInfoReq.java @@ -9,17 +9,17 @@ import emu.grasscutter.server.packet.send.PacketPlayerGetForceQuitBanInfoRsp; @Opcodes(PacketOpcodes.PlayerGetForceQuitBanInfoReq) public class HandlerPlayerGetForceQuitBanInfoReq extends PacketHandler { - - @Override - public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - - if (session.getServer().getMultiplayerSystem().leaveCoop(session.getPlayer())) { - // Success - session.send(new PacketPlayerGetForceQuitBanInfoRsp(RetcodeOuterClass.Retcode.RET_SUCC_VALUE)); - } else { - // Fail - session.send(new PacketPlayerGetForceQuitBanInfoRsp(RetcodeOuterClass.Retcode.RET_SVR_ERROR_VALUE)); - } - } + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + + if (session.getServer().getMultiplayerSystem().leaveCoop(session.getPlayer())) { + // Success + session.send(new PacketPlayerGetForceQuitBanInfoRsp(RetcodeOuterClass.Retcode.RET_SUCC_VALUE)); + } else { + // Fail + session.send(new PacketPlayerGetForceQuitBanInfoRsp(RetcodeOuterClass.Retcode.RET_SVR_ERROR_VALUE)); + } + } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerLoginReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerLoginReq.java index 714d3161b..3df671fa5 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerLoginReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerLoginReq.java @@ -18,39 +18,39 @@ import emu.grasscutter.server.packet.send.PacketTakeAchievementRewardReq; @Opcodes(PacketOpcodes.PlayerLoginReq) // Sends initial data packets public class HandlerPlayerLoginReq extends PacketHandler { - @Override - public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - // Check - if (session.getAccount() == null) { - session.close(); - return; - } + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + // Check + if (session.getAccount() == null) { + session.close(); + return; + } - // Parse request - PlayerLoginReq req = PlayerLoginReq.parseFrom(payload); + // Parse request + PlayerLoginReq req = PlayerLoginReq.parseFrom(payload); - // Authenticate session - if (!req.getToken().equals(session.getAccount().getToken())) { - session.close(); - return; - } + // Authenticate session + if (!req.getToken().equals(session.getAccount().getToken())) { + session.close(); + return; + } - // Load character from db - Player player = session.getPlayer(); + // Load character from db + Player player = session.getPlayer(); - // Show opening cutscene if player has no avatars - if (player.getAvatars().getAvatarCount() == 0) { - // Pick character - session.setState(SessionState.PICKING_CHARACTER); - session.send(new BasePacket(PacketOpcodes.DoSetPlayerBornDataNotify)); - } else { - // Login done - session.getPlayer().onLogin(); - } + // Show opening cutscene if player has no avatars + if (player.getAvatars().getAvatarCount() == 0) { + // Pick character + session.setState(SessionState.PICKING_CHARACTER); + session.send(new BasePacket(PacketOpcodes.DoSetPlayerBornDataNotify)); + } else { + // Login done + session.getPlayer().onLogin(); + } - // Final packet to tell client logging in is done - session.send(new PacketPlayerLoginRsp(session)); - session.send(new PacketTakeAchievementRewardReq(session)); - } + // Final packet to tell client logging in is done + session.send(new PacketPlayerLoginRsp(session)); + session.send(new PacketTakeAchievementRewardReq(session)); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerQuitDungeonReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerQuitDungeonReq.java index 9bc450149..a8e483c50 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerQuitDungeonReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPlayerQuitDungeonReq.java @@ -7,10 +7,10 @@ import emu.grasscutter.server.game.GameSession; @Opcodes(PacketOpcodes.PlayerQuitDungeonReq) public class HandlerPlayerQuitDungeonReq extends PacketHandler { - - @Override - public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - session.getPlayer().getServer().getDungeonSystem().exitDungeon(session.getPlayer()); - } + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + session.getPlayer().getServer().getDungeonSystem().exitDungeon(session.getPlayer()); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPullPrivateChatReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPullPrivateChatReq.java index c579d20b0..191d96d31 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPullPrivateChatReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPullPrivateChatReq.java @@ -9,14 +9,14 @@ import emu.grasscutter.server.packet.send.PacketPullPrivateChatRsp; @Opcodes(PacketOpcodes.PullPrivateChatReq) public class HandlerPullPrivateChatReq extends PacketHandler { - - @Override - public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - PullPrivateChatReq req = PullPrivateChatReq.parseFrom(payload); - session.getServer().getChatManager().handlePullPrivateChatReq(session.getPlayer(), req.getTargetUid()); - - // session.send(new PacketPullPrivateChatRsp(req.getTargetUid())); - } + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + PullPrivateChatReq req = PullPrivateChatReq.parseFrom(payload); + + session.getServer().getChatManager().handlePullPrivateChatReq(session.getPlayer(), req.getTargetUid()); + + // session.send(new PacketPullPrivateChatRsp(req.getTargetUid())); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPullRecentChatReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPullRecentChatReq.java index fa5e6ba8a..1db217e2d 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerPullRecentChatReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerPullRecentChatReq.java @@ -8,8 +8,8 @@ import emu.grasscutter.server.packet.send.PacketPullRecentChatRsp; @Opcodes(PacketOpcodes.PullRecentChatReq) public class HandlerPullRecentChatReq extends PacketHandler { - @Override - public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - session.getServer().getChatManager().handlePullRecentChatReq(session.getPlayer()); - } + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + session.getServer().getChatManager().handlePullRecentChatReq(session.getPlayer()); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerQueryPathReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerQueryPathReq.java index 62aad5da8..6ecadee5b 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerQueryPathReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerQueryPathReq.java @@ -11,17 +11,17 @@ import emu.grasscutter.server.packet.send.PacketQueryPathRsp; @Opcodes(PacketOpcodes.QueryPathReq) public class HandlerQueryPathReq extends PacketHandler { - @Override - public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - var req = QueryPathReq.parseFrom(payload); + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + var req = QueryPathReq.parseFrom(payload); /** * It is not the actual work */ - + if (req.getDestinationPosList().size() > 0) { - session.send(new PacketQueryPathRsp(req)); + session.send(new PacketQueryPathRsp(req)); } - } + } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerReliquaryDecomposeReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerReliquaryDecomposeReq.java index a098ef0d6..fae813a8d 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerReliquaryDecomposeReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerReliquaryDecomposeReq.java @@ -8,9 +8,9 @@ import emu.grasscutter.server.game.GameSession; @Opcodes(PacketOpcodes.ReliquaryDecomposeReq) public class HandlerReliquaryDecomposeReq extends PacketHandler { - @Override - public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - ReliquaryDecomposeReq req = ReliquaryDecomposeReq.parseFrom(payload); - session.getServer().getCombineSystem().decomposeReliquaries(session.getPlayer(), req.getConfigId(), req.getTargetCount(), req.getGuidListList()); - } + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + ReliquaryDecomposeReq req = ReliquaryDecomposeReq.parseFrom(payload); + session.getServer().getCombineSystem().decomposeReliquaries(session.getPlayer(), req.getConfigId(), req.getTargetCount(), req.getGuidListList()); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerReliquaryUpgradeReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerReliquaryUpgradeReq.java index 6eb19b7ed..6115ef1fd 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerReliquaryUpgradeReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerReliquaryUpgradeReq.java @@ -8,12 +8,12 @@ import emu.grasscutter.server.game.GameSession; @Opcodes(PacketOpcodes.ReliquaryUpgradeReq) public class HandlerReliquaryUpgradeReq extends PacketHandler { - - @Override - public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - ReliquaryUpgradeReq req = ReliquaryUpgradeReq.parseFrom(payload); - - session.getServer().getInventorySystem().upgradeRelic(session.getPlayer(), req.getTargetReliquaryGuid(), req.getFoodReliquaryGuidListList(), req.getItemParamListList()); - } + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + ReliquaryUpgradeReq req = ReliquaryUpgradeReq.parseFrom(payload); + + session.getServer().getInventorySystem().upgradeRelic(session.getPlayer(), req.getTargetReliquaryGuid(), req.getFoodReliquaryGuidListList(), req.getItemParamListList()); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSceneKickPlayerReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSceneKickPlayerReq.java index fec303b4b..731ead639 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSceneKickPlayerReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSceneKickPlayerReq.java @@ -9,18 +9,18 @@ import emu.grasscutter.server.packet.send.PacketSceneKickPlayerRsp; @Opcodes(PacketOpcodes.SceneKickPlayerReq) public class HandlerSceneKickPlayerReq extends PacketHandler { - - @Override - public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - SceneKickPlayerReq req = SceneKickPlayerReq.parseFrom(payload); - - if (session.getServer().getMultiplayerSystem().kickPlayer(session.getPlayer(), req.getTargetUid())) { - // Success - session.send(new PacketSceneKickPlayerRsp(req.getTargetUid())); - } else { - // Fail - session.send(new PacketSceneKickPlayerRsp()); - } - } + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + SceneKickPlayerReq req = SceneKickPlayerReq.parseFrom(payload); + + if (session.getServer().getMultiplayerSystem().kickPlayer(session.getPlayer(), req.getTargetUid())) { + // Success + session.send(new PacketSceneKickPlayerRsp(req.getTargetUid())); + } else { + // Fail + session.send(new PacketSceneKickPlayerRsp()); + } + } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetEquipLockStateReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetEquipLockStateReq.java index 2467650f9..01b75ee81 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetEquipLockStateReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetEquipLockStateReq.java @@ -8,12 +8,12 @@ import emu.grasscutter.server.game.GameSession; @Opcodes(PacketOpcodes.SetEquipLockStateReq) public class HandlerSetEquipLockStateReq extends PacketHandler { - - @Override - public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - SetEquipLockStateReq req = SetEquipLockStateReq.parseFrom(payload); - - session.getServer().getInventorySystem().lockEquip(session.getPlayer(), req.getTargetEquipGuid(), req.getIsLocked()); - } + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + SetEquipLockStateReq req = SetEquipLockStateReq.parseFrom(payload); + + session.getServer().getInventorySystem().lockEquip(session.getPlayer(), req.getTargetEquipGuid(), req.getIsLocked()); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetOpenStateReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetOpenStateReq.java index f7f259a32..b1268cc50 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetOpenStateReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetOpenStateReq.java @@ -23,4 +23,4 @@ public class HandlerSetOpenStateReq extends PacketHandler { session.send(new PacketSetOpenStateRsp(openState,value)); } -} \ No newline at end of file +} diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetPlayerBornDataReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetPlayerBornDataReq.java index 48ac9151f..1b406ad00 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetPlayerBornDataReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerSetPlayerBornDataReq.java @@ -23,62 +23,62 @@ import java.util.Arrays; @Opcodes(PacketOpcodes.SetPlayerBornDataReq) public class HandlerSetPlayerBornDataReq extends PacketHandler { - - @Override - public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - SetPlayerBornDataReq req = SetPlayerBornDataReq.parseFrom(payload); - - // Sanity checks - int avatarId = req.getAvatarId(); - int startingSkillDepot; - if (avatarId == GameConstants.MAIN_CHARACTER_MALE) { - startingSkillDepot = 504; - } else if (avatarId == GameConstants.MAIN_CHARACTER_FEMALE) { - startingSkillDepot = 704; - } else { - return; - } - - // Make sure resources folder is set - if (!GameData.getAvatarDataMap().containsKey(avatarId)) { - Grasscutter.getLogger().error("No avatar data found! Please check your ExcelBinOutput folder."); - session.close(); - return; - } - - // Get player object - Player player = session.getPlayer(); - player.setNickname(req.getNickName()); - // Create avatar - if (player.getAvatars().getAvatarCount() == 0) { - Avatar mainCharacter = new Avatar(avatarId); - mainCharacter.setSkillDepotData(GameData.getAvatarSkillDepotDataMap().get(startingSkillDepot)); - // Manually handle adding to team - player.addAvatar(mainCharacter, false); - player.setMainCharacterId(avatarId); - player.setHeadImage(avatarId); - player.getTeamManager().getCurrentSinglePlayerTeamInfo().getAvatars().add(mainCharacter.getAvatarId()); - player.save(); // TODO save player team in different object - } else { - return; - } - - // Login done - session.getPlayer().onLogin(); - - // Born resp packet - session.send(new BasePacket(PacketOpcodes.SetPlayerBornDataRsp)); + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + SetPlayerBornDataReq req = SetPlayerBornDataReq.parseFrom(payload); - // Default mail - var welcomeMail = GAME_INFO.joinOptions.welcomeMail; - MailBuilder mailBuilder = new MailBuilder(player.getUid(), new Mail()); - mailBuilder.mail.mailContent.title = welcomeMail.title; - mailBuilder.mail.mailContent.sender = welcomeMail.sender; - // Please credit Grasscutter if changing something here. We don't condone commercial use of the project. - mailBuilder.mail.mailContent.content = welcomeMail.content + "\n"; - mailBuilder.mail.itemList.addAll(Arrays.asList(welcomeMail.items)); - mailBuilder.mail.importance = 1; - player.sendMail(mailBuilder.mail); - } + // Sanity checks + int avatarId = req.getAvatarId(); + int startingSkillDepot; + if (avatarId == GameConstants.MAIN_CHARACTER_MALE) { + startingSkillDepot = 504; + } else if (avatarId == GameConstants.MAIN_CHARACTER_FEMALE) { + startingSkillDepot = 704; + } else { + return; + } + + // Make sure resources folder is set + if (!GameData.getAvatarDataMap().containsKey(avatarId)) { + Grasscutter.getLogger().error("No avatar data found! Please check your ExcelBinOutput folder."); + session.close(); + return; + } + + // Get player object + Player player = session.getPlayer(); + player.setNickname(req.getNickName()); + + // Create avatar + if (player.getAvatars().getAvatarCount() == 0) { + Avatar mainCharacter = new Avatar(avatarId); + mainCharacter.setSkillDepotData(GameData.getAvatarSkillDepotDataMap().get(startingSkillDepot)); + // Manually handle adding to team + player.addAvatar(mainCharacter, false); + player.setMainCharacterId(avatarId); + player.setHeadImage(avatarId); + player.getTeamManager().getCurrentSinglePlayerTeamInfo().getAvatars().add(mainCharacter.getAvatarId()); + player.save(); // TODO save player team in different object + } else { + return; + } + + // Login done + session.getPlayer().onLogin(); + + // Born resp packet + session.send(new BasePacket(PacketOpcodes.SetPlayerBornDataRsp)); + + // Default mail + var welcomeMail = GAME_INFO.joinOptions.welcomeMail; + MailBuilder mailBuilder = new MailBuilder(player.getUid(), new Mail()); + mailBuilder.mail.mailContent.title = welcomeMail.title; + mailBuilder.mail.mailContent.sender = welcomeMail.sender; + // Please credit Grasscutter if changing something here. We don't condone commercial use of the project. + mailBuilder.mail.mailContent.content = welcomeMail.content + "\n"; + mailBuilder.mail.itemList.addAll(Arrays.asList(welcomeMail.items)); + mailBuilder.mail.importance = 1; + player.sendMail(mailBuilder.mail); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerTowerAllDataReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerTowerAllDataReq.java index c9fa5b112..697a7f85c 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerTowerAllDataReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerTowerAllDataReq.java @@ -8,13 +8,13 @@ import emu.grasscutter.server.packet.send.PacketTowerAllDataRsp; @Opcodes(PacketOpcodes.TowerAllDataReq) public class HandlerTowerAllDataReq extends PacketHandler { - - @Override - public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - session.send(new PacketTowerAllDataRsp( - session.getServer().getTowerSystem(), - session.getPlayer().getTowerManager() - )); - } + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + session.send(new PacketTowerAllDataRsp( + session.getServer().getTowerSystem(), + session.getPlayer().getTowerManager() + )); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerUnionCmdNotify.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerUnionCmdNotify.java index 9323ec5b6..daa1b1388 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerUnionCmdNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerUnionCmdNotify.java @@ -13,28 +13,28 @@ import emu.grasscutter.Grasscutter.ServerDebugMode; @Opcodes(PacketOpcodes.UnionCmdNotify) public class HandlerUnionCmdNotify extends PacketHandler { - @Override - public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - UnionCmdNotify req = UnionCmdNotify.parseFrom(payload); - for (UnionCmd cmd : req.getCmdListList()) { + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + UnionCmdNotify req = UnionCmdNotify.parseFrom(payload); + for (UnionCmd cmd : req.getCmdListList()) { int cmdOpcode = cmd.getMessageId(); byte[] cmdPayload = cmd.getBody().toByteArray(); - if(GAME_INFO.logPackets == ServerDebugMode.WHITELIST && SERVER.debugWhitelist.contains(cmd.getMessageId())) { + if (GAME_INFO.logPackets == ServerDebugMode.WHITELIST && SERVER.debugWhitelist.contains(cmd.getMessageId())) { session.logPacket("RECV in Union", cmdOpcode, cmdPayload); } else if (GAME_INFO.logPackets == ServerDebugMode.BLACKLIST && !SERVER.debugBlacklist.contains(cmd.getMessageId())) { session.logPacket("RECV in Union", cmdOpcode, cmdPayload); } //debugLevel ALL ignores UnionCmdNotify, so we will also ignore the contained opcodes session.getServer().getPacketHandler().handle(session, cmd.getMessageId(), EMPTY_BYTE_ARRAY, cmd.getBody().toByteArray()); - } + } - // Update - session.getPlayer().getCombatInvokeHandler().update(session.getPlayer()); - session.getPlayer().getAbilityInvokeHandler().update(session.getPlayer()); + // Update + session.getPlayer().getCombatInvokeHandler().update(session.getPlayer()); + session.getPlayer().getAbilityInvokeHandler().update(session.getPlayer()); // Handle attack results last - while (!session.getPlayer().getAttackResults().isEmpty()) { - session.getPlayer().getScene().handleAttack(session.getPlayer().getAttackResults().poll()); - } - } + while (!session.getPlayer().getAttackResults().isEmpty()) { + session.getPlayer().getScene().handleAttack(session.getPlayer().getAttackResults().poll()); + } + } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerUnlockAvatarTalentReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerUnlockAvatarTalentReq.java index d37df8618..5016017f6 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerUnlockAvatarTalentReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerUnlockAvatarTalentReq.java @@ -8,13 +8,13 @@ import emu.grasscutter.server.game.GameSession; @Opcodes(PacketOpcodes.UnlockAvatarTalentReq) public class HandlerUnlockAvatarTalentReq extends PacketHandler { - - @Override - public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - UnlockAvatarTalentReq req = UnlockAvatarTalentReq.parseFrom(payload); - - // Unlock avatar const - session.getServer().getInventorySystem().unlockAvatarConstellation(session.getPlayer(), req.getAvatarGuid()); - } + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + UnlockAvatarTalentReq req = UnlockAvatarTalentReq.parseFrom(payload); + + // Unlock avatar const + session.getServer().getInventorySystem().unlockAvatarConstellation(session.getPlayer(), req.getAvatarGuid()); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerUseItemReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerUseItemReq.java index 0941dafed..54314959d 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerUseItemReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerUseItemReq.java @@ -10,17 +10,17 @@ import emu.grasscutter.server.packet.send.PacketUseItemRsp; @Opcodes(PacketOpcodes.UseItemReq) public class HandlerUseItemReq extends PacketHandler { - - @Override - public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - UseItemReq req = UseItemReq.parseFrom(payload); - - GameItem useItem = session.getServer().getInventorySystem().useItem(session.getPlayer(), req.getTargetGuid(), req.getGuid(), req.getCount(), req.getOptionIdx()); - if (useItem != null) { - session.send(new PacketUseItemRsp(req.getTargetGuid(), useItem)); - } else { - session.send(new PacketUseItemRsp()); - } - } + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + UseItemReq req = UseItemReq.parseFrom(payload); + + GameItem useItem = session.getServer().getInventorySystem().useItem(session.getPlayer(), req.getTargetGuid(), req.getGuid(), req.getCount(), req.getOptionIdx()); + if (useItem != null) { + session.send(new PacketUseItemRsp(req.getTargetGuid(), useItem)); + } else { + session.send(new PacketUseItemRsp()); + } + } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerWeaponAwakenReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerWeaponAwakenReq.java index 0c9fcd68c..79326554d 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerWeaponAwakenReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerWeaponAwakenReq.java @@ -8,13 +8,13 @@ import emu.grasscutter.server.game.GameSession; @Opcodes(PacketOpcodes.WeaponAwakenReq) public class HandlerWeaponAwakenReq extends PacketHandler { - - @Override - public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - WeaponAwakenReq req = WeaponAwakenReq.parseFrom(payload); - - // Weapon refinement - session.getServer().getInventorySystem().refineWeapon(session.getPlayer(), req.getTargetWeaponGuid(), req.getItemGuid()); - } + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + WeaponAwakenReq req = WeaponAwakenReq.parseFrom(payload); + + // Weapon refinement + session.getServer().getInventorySystem().refineWeapon(session.getPlayer(), req.getTargetWeaponGuid(), req.getItemGuid()); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerWeaponPromoteReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerWeaponPromoteReq.java index bbb50bd5d..19fa03fd6 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerWeaponPromoteReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerWeaponPromoteReq.java @@ -8,13 +8,13 @@ import emu.grasscutter.server.game.GameSession; @Opcodes(PacketOpcodes.WeaponPromoteReq) public class HandlerWeaponPromoteReq extends PacketHandler { - - @Override - public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - WeaponPromoteReq req = WeaponPromoteReq.parseFrom(payload); - - // Ascend weapon - session.getServer().getInventorySystem().promoteWeapon(session.getPlayer(), req.getTargetWeaponGuid()); - } + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + WeaponPromoteReq req = WeaponPromoteReq.parseFrom(payload); + + // Ascend weapon + session.getServer().getInventorySystem().promoteWeapon(session.getPlayer(), req.getTargetWeaponGuid()); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerWeaponUpgradeReq.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerWeaponUpgradeReq.java index 3e531afa6..4744a2f11 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerWeaponUpgradeReq.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerWeaponUpgradeReq.java @@ -8,18 +8,18 @@ import emu.grasscutter.server.game.GameSession; @Opcodes(PacketOpcodes.WeaponUpgradeReq) public class HandlerWeaponUpgradeReq extends PacketHandler { - - @Override - public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { - WeaponUpgradeReq req = WeaponUpgradeReq.parseFrom(payload); - - // Level up weapon - session.getServer().getInventorySystem().upgradeWeapon( - session.getPlayer(), - req.getTargetWeaponGuid(), - req.getFoodWeaponGuidListList(), - req.getItemParamListList() - ); - } + + @Override + public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { + WeaponUpgradeReq req = WeaponUpgradeReq.parseFrom(payload); + + // Level up weapon + session.getServer().getInventorySystem().upgradeWeapon( + session.getPlayer(), + req.getTargetWeaponGuid(), + req.getFoodWeaponGuidListList(), + req.getItemParamListList() + ); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketGetAllMailRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketGetAllMailRsp.java index c6f2b7194..780ca4163 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketGetAllMailRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketGetAllMailRsp.java @@ -32,9 +32,9 @@ public class PacketGetAllMailRsp extends BasePacket { List mailDataList = new ArrayList(); for (Mail message : player.getAllMail()) { - if(message.stateValue == 1) { // Make sure it isn't a gift + if (message.stateValue == 1) { // Make sure it isn't a gift if (message.expireTime > (int) Instant.now().getEpochSecond()) { // Make sure the message isn't expired (The game won't show expired mail, but I don't want to send unnecessary information). - if(mailDataList.size() <= 1000) { // Make sure that there isn't over 1000 messages in the mailbox. (idk what will happen if there is but the game probably won't like it.) + if (mailDataList.size() <= 1000) { // Make sure that there isn't over 1000 messages in the mailbox. (idk what will happen if there is but the game probably won't like it.) MailTextContent.Builder mailTextContent = MailTextContent.newBuilder(); mailTextContent.setTitle(message.mailContent.title); mailTextContent.setContent(message.mailContent.content); diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketGetGachaInfoRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketGetGachaInfoRsp.java index bc1e3f1e3..7e6eb3edd 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketGetGachaInfoRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketGetGachaInfoRsp.java @@ -6,11 +6,11 @@ import emu.grasscutter.net.packet.BasePacket; import emu.grasscutter.net.packet.PacketOpcodes; public class PacketGetGachaInfoRsp extends BasePacket { - - public PacketGetGachaInfoRsp(GachaSystem manager, Player player) { - super(PacketOpcodes.GetGachaInfoRsp); - - this.setData(manager.toProto(player)); - } + + public PacketGetGachaInfoRsp(GachaSystem manager, Player player) { + super(PacketOpcodes.GetGachaInfoRsp); + + this.setData(manager.toProto(player)); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketGetInvestigationMonsterRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketGetInvestigationMonsterRsp.java index 306cbca57..47a26e261 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketGetInvestigationMonsterRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketGetInvestigationMonsterRsp.java @@ -11,15 +11,15 @@ import java.util.List; public class PacketGetInvestigationMonsterRsp extends BasePacket { - public PacketGetInvestigationMonsterRsp(Player player, WorldDataSystem worldDataManager, List cityIdListList) { + public PacketGetInvestigationMonsterRsp(Player player, WorldDataSystem worldDataManager, List cityIdListList) { - super(PacketOpcodes.GetInvestigationMonsterRsp); + super(PacketOpcodes.GetInvestigationMonsterRsp); - var resp = GetInvestigationMonsterRspOuterClass.GetInvestigationMonsterRsp.newBuilder(); + var resp = GetInvestigationMonsterRspOuterClass.GetInvestigationMonsterRsp.newBuilder(); - cityIdListList.forEach(id -> resp.addAllMonsterList(worldDataManager.getInvestigationMonstersByCityId(player, id))); + cityIdListList.forEach(id -> resp.addAllMonsterList(worldDataManager.getInvestigationMonstersByCityId(player, id))); - this.setData(resp.build()); - } + this.setData(resp.build()); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketGetPlayerFriendListRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketGetPlayerFriendListRsp.java index 97a7d4a97..82110ef78 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketGetPlayerFriendListRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketGetPlayerFriendListRsp.java @@ -14,32 +14,32 @@ import emu.grasscutter.net.proto.ProfilePictureOuterClass.ProfilePicture; import emu.grasscutter.net.proto.PlatformTypeOuterClass; public class PacketGetPlayerFriendListRsp extends BasePacket { - - public PacketGetPlayerFriendListRsp(Player player) { - super(PacketOpcodes.GetPlayerFriendListRsp); - - var serverAccount = GAME_INFO.serverAccount; - FriendBrief serverFriend = FriendBrief.newBuilder() - .setUid(GameConstants.SERVER_CONSOLE_UID) - .setNickname(serverAccount.nickName) - .setLevel(serverAccount.adventureRank) - .setProfilePicture(ProfilePicture.newBuilder().setAvatarId(serverAccount.avatarId)) - .setWorldLevel(serverAccount.worldLevel) - .setSignature(serverAccount.signature) - .setLastActiveTime((int) (System.currentTimeMillis() / 1000f)) - .setNameCardId(serverAccount.nameCardId) - .setOnlineState(FriendOnlineState.FRIEND_ONLINE_STATE_ONLINE) - .setParam(1) - .setIsGameSource(true) - .setPlatformType(PlatformTypeOuterClass.PlatformType.PLATFORM_TYPE_PC) - .build(); - - GetPlayerFriendListRsp.Builder proto = GetPlayerFriendListRsp.newBuilder().addFriendList(serverFriend); - - for (Friendship friendship : player.getFriendsList().getFriends().values()) { - proto.addFriendList(friendship.toProto()); - } - this.setData(proto); - } + public PacketGetPlayerFriendListRsp(Player player) { + super(PacketOpcodes.GetPlayerFriendListRsp); + + var serverAccount = GAME_INFO.serverAccount; + FriendBrief serverFriend = FriendBrief.newBuilder() + .setUid(GameConstants.SERVER_CONSOLE_UID) + .setNickname(serverAccount.nickName) + .setLevel(serverAccount.adventureRank) + .setProfilePicture(ProfilePicture.newBuilder().setAvatarId(serverAccount.avatarId)) + .setWorldLevel(serverAccount.worldLevel) + .setSignature(serverAccount.signature) + .setLastActiveTime((int) (System.currentTimeMillis() / 1000f)) + .setNameCardId(serverAccount.nameCardId) + .setOnlineState(FriendOnlineState.FRIEND_ONLINE_STATE_ONLINE) + .setParam(1) + .setIsGameSource(true) + .setPlatformType(PlatformTypeOuterClass.PlatformType.PLATFORM_TYPE_PC) + .build(); + + GetPlayerFriendListRsp.Builder proto = GetPlayerFriendListRsp.newBuilder().addFriendList(serverFriend); + + for (Friendship friendship : player.getFriendsList().getFriends().values()) { + proto.addFriendList(friendship.toProto()); + } + + this.setData(proto); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketGetSceneAreaRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketGetSceneAreaRsp.java index f81efb07a..b4d74741d 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketGetSceneAreaRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketGetSceneAreaRsp.java @@ -9,20 +9,20 @@ import emu.grasscutter.net.proto.CityInfoOuterClass.CityInfo; import emu.grasscutter.net.proto.GetSceneAreaRspOuterClass.GetSceneAreaRsp; public class PacketGetSceneAreaRsp extends BasePacket { - - public PacketGetSceneAreaRsp(int sceneId) { - super(PacketOpcodes.GetSceneAreaRsp); - - this.buildHeader(0); - - GetSceneAreaRsp p = GetSceneAreaRsp.newBuilder() - .setSceneId(sceneId) - .addAllAreaIdList(Arrays.stream(new int[] {1,2,3,4,5,6,7,8,9,10,11,12,13,14,17,18,19,100,101,102,103,200,210,300,400,401,402,403}).boxed().collect(Collectors.toList())) - .addCityInfoList(CityInfo.newBuilder().setCityId(1).setLevel(1).build()) - .addCityInfoList(CityInfo.newBuilder().setCityId(2).setLevel(1).build()) - .addCityInfoList(CityInfo.newBuilder().setCityId(3).setLevel(1).build()) - .build(); - - this.setData(p); - } + + public PacketGetSceneAreaRsp(int sceneId) { + super(PacketOpcodes.GetSceneAreaRsp); + + this.buildHeader(0); + + GetSceneAreaRsp p = GetSceneAreaRsp.newBuilder() + .setSceneId(sceneId) + .addAllAreaIdList(Arrays.stream(new int[] {1,2,3,4,5,6,7,8,9,10,11,12,13,14,17,18,19,100,101,102,103,200,210,300,400,401,402,403}).boxed().collect(Collectors.toList())) + .addCityInfoList(CityInfo.newBuilder().setCityId(1).setLevel(1).build()) + .addCityInfoList(CityInfo.newBuilder().setCityId(2).setLevel(1).build()) + .addCityInfoList(CityInfo.newBuilder().setCityId(3).setLevel(1).build()) + .build(); + + this.setData(p); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketGetShopRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketGetShopRsp.java index 0bee63451..b52d58004 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketGetShopRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketGetShopRsp.java @@ -18,61 +18,61 @@ import java.util.List; import java.util.stream.Collectors; public class PacketGetShopRsp extends BasePacket { - public PacketGetShopRsp(Player inv, int shopType) { - super(PacketOpcodes.GetShopRsp); + public PacketGetShopRsp(Player inv, int shopType) { + super(PacketOpcodes.GetShopRsp); - // TODO: CityReputationLevel - Shop.Builder shop = Shop.newBuilder() - .setShopType(shopType) - .setCityId(1) //mock - .setCityReputationLevel(10); //mock + // TODO: CityReputationLevel + Shop.Builder shop = Shop.newBuilder() + .setShopType(shopType) + .setCityId(1) //mock + .setCityReputationLevel(10); //mock - ShopSystem manager = Grasscutter.getGameServer().getShopSystem(); - if (manager.getShopData().get(shopType) != null) { - List list = manager.getShopData().get(shopType); - List goodsList = new ArrayList<>(); - for (ShopInfo info : list) { - ShopGoods.Builder goods = ShopGoods.newBuilder() - .setGoodsId(info.getGoodsId()) - .setGoodsItem(ItemParamOuterClass.ItemParam.newBuilder().setItemId(info.getGoodsItem().getId()).setCount(info.getGoodsItem().getCount()).build()) - .setScoin(info.getScoin()) - .setHcoin(info.getHcoin()) - .setBuyLimit(info.getBuyLimit()) - .setBeginTime(info.getBeginTime()) - .setEndTime(info.getEndTime()) - .setMinLevel(info.getMinLevel()) - .setMaxLevel(info.getMaxLevel()) - .setMcoin(info.getMcoin()) - .setDisableType(info.getDisableType()) - .setSecondarySheetId(info.getSecondarySheetId()); - if (info.getCostItemList() != null) { - goods.addAllCostItemList(info.getCostItemList().stream().map(x -> ItemParamOuterClass.ItemParam.newBuilder().setItemId(x.getId()).setCount(x.getCount()).build()).collect(Collectors.toList())); - } - if (info.getPreGoodsIdList() != null) { - goods.addAllPreGoodsIdList(info.getPreGoodsIdList()); - } + ShopSystem manager = Grasscutter.getGameServer().getShopSystem(); + if (manager.getShopData().get(shopType) != null) { + List list = manager.getShopData().get(shopType); + List goodsList = new ArrayList<>(); + for (ShopInfo info : list) { + ShopGoods.Builder goods = ShopGoods.newBuilder() + .setGoodsId(info.getGoodsId()) + .setGoodsItem(ItemParamOuterClass.ItemParam.newBuilder().setItemId(info.getGoodsItem().getId()).setCount(info.getGoodsItem().getCount()).build()) + .setScoin(info.getScoin()) + .setHcoin(info.getHcoin()) + .setBuyLimit(info.getBuyLimit()) + .setBeginTime(info.getBeginTime()) + .setEndTime(info.getEndTime()) + .setMinLevel(info.getMinLevel()) + .setMaxLevel(info.getMaxLevel()) + .setMcoin(info.getMcoin()) + .setDisableType(info.getDisableType()) + .setSecondarySheetId(info.getSecondarySheetId()); + if (info.getCostItemList() != null) { + goods.addAllCostItemList(info.getCostItemList().stream().map(x -> ItemParamOuterClass.ItemParam.newBuilder().setItemId(x.getId()).setCount(x.getCount()).build()).collect(Collectors.toList())); + } + if (info.getPreGoodsIdList() != null) { + goods.addAllPreGoodsIdList(info.getPreGoodsIdList()); + } - int currentTs = Utils.getCurrentSeconds(); - ShopLimit currentShopLimit = inv.getGoodsLimit(info.getGoodsId()); - int nextRefreshTime = ShopSystem.getShopNextRefreshTime(info); - if (currentShopLimit != null) { - if (currentShopLimit.getNextRefreshTime() < currentTs) { // second game day - currentShopLimit.setHasBoughtInPeriod(0); - currentShopLimit.setNextRefreshTime(nextRefreshTime); - } - goods.setBoughtNum(currentShopLimit.getHasBoughtInPeriod()); - goods.setNextRefreshTime(currentShopLimit.getNextRefreshTime()); - } else { - inv.addShopLimit(goods.getGoodsId(), 0, nextRefreshTime); // save generated refresh time - goods.setNextRefreshTime(nextRefreshTime); - } + int currentTs = Utils.getCurrentSeconds(); + ShopLimit currentShopLimit = inv.getGoodsLimit(info.getGoodsId()); + int nextRefreshTime = ShopSystem.getShopNextRefreshTime(info); + if (currentShopLimit != null) { + if (currentShopLimit.getNextRefreshTime() < currentTs) { // second game day + currentShopLimit.setHasBoughtInPeriod(0); + currentShopLimit.setNextRefreshTime(nextRefreshTime); + } + goods.setBoughtNum(currentShopLimit.getHasBoughtInPeriod()); + goods.setNextRefreshTime(currentShopLimit.getNextRefreshTime()); + } else { + inv.addShopLimit(goods.getGoodsId(), 0, nextRefreshTime); // save generated refresh time + goods.setNextRefreshTime(nextRefreshTime); + } - goodsList.add(goods.build()); - } - shop.addAllGoodsList(goodsList); - } + goodsList.add(goods.build()); + } + shop.addAllGoodsList(goodsList); + } - inv.save(); - this.setData(GetShopRspOuterClass.GetShopRsp.newBuilder().setShop(shop).build()); - } + inv.save(); + this.setData(GetShopRspOuterClass.GetShopRsp.newBuilder().setShop(shop).build()); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketHomeBasicInfoNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketHomeBasicInfoNotify.java index a55091f32..6216cf2ea 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketHomeBasicInfoNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketHomeBasicInfoNotify.java @@ -10,28 +10,28 @@ import emu.grasscutter.net.proto.VectorOuterClass; public class PacketHomeBasicInfoNotify extends BasePacket { - public PacketHomeBasicInfoNotify(Player player, boolean editMode) { - super(PacketOpcodes.HomeBasicInfoNotify); + public PacketHomeBasicInfoNotify(Player player, boolean editMode) { + super(PacketOpcodes.HomeBasicInfoNotify); - if (player.getCurrentRealmId() <= 0) { - return; - } + if (player.getCurrentRealmId() <= 0) { + return; + } - var proto = HomeBasicInfoNotifyOuterClass.HomeBasicInfoNotify.newBuilder(); + var proto = HomeBasicInfoNotifyOuterClass.HomeBasicInfoNotify.newBuilder(); - var sceneId = player.getCurrentRealmId() + 2000; - var homeScene = player.getHome().getHomeSceneItem(sceneId); + var sceneId = player.getCurrentRealmId() + 2000; + var homeScene = player.getHome().getHomeSceneItem(sceneId); - proto.setBasicInfo(HomeBasicInfoOuterClass.HomeBasicInfo.newBuilder() - .setCurModuleId(player.getCurrentRealmId()) - .setCurRoomSceneId(homeScene.getRoomSceneId()) - .setIsInEditMode(editMode) - .setHomeOwnerUid(player.getUid()) - .setLevel(player.getHome().getLevel()) - .setOwnerNickName(player.getNickname()) - // TODO limit shop - .build()); + proto.setBasicInfo(HomeBasicInfoOuterClass.HomeBasicInfo.newBuilder() + .setCurModuleId(player.getCurrentRealmId()) + .setCurRoomSceneId(homeScene.getRoomSceneId()) + .setIsInEditMode(editMode) + .setHomeOwnerUid(player.getUid()) + .setLevel(player.getHome().getLevel()) + .setOwnerNickName(player.getNickname()) + // TODO limit shop + .build()); - this.setData(proto); - } + this.setData(proto); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketMailChangeNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketMailChangeNotify.java index d0ea5d96b..f8e196265 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketMailChangeNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketMailChangeNotify.java @@ -14,7 +14,7 @@ import java.util.List; public class PacketMailChangeNotify extends BasePacket { public PacketMailChangeNotify(Player player, Mail message) { - this (player, new ArrayList(){{add(message);}}); + this (player, new ArrayList() {{add(message);}}); } public PacketMailChangeNotify(Player player, List mailList) { @@ -60,10 +60,10 @@ public class PacketMailChangeNotify extends BasePacket { } } - if(delMailIdList != null) { + if (delMailIdList != null) { proto.addAllDelMailIdList(delMailIdList); } this.setData(proto.build()); } -} \ No newline at end of file +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketMarkMapRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketMarkMapRsp.java index f904e3892..1492ee914 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketMarkMapRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketMarkMapRsp.java @@ -40,4 +40,4 @@ public class PacketMarkMapRsp extends BasePacket { MarkMapRspOuterClass.MarkMapRsp data = proto.build(); this.setData(data); } -} \ No newline at end of file +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketOpenStateChangeNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketOpenStateChangeNotify.java index fafc5dc8f..902caebcb 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketOpenStateChangeNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketOpenStateChangeNotify.java @@ -16,4 +16,4 @@ public class PacketOpenStateChangeNotify extends BasePacket { this.setData(proto); } -} \ No newline at end of file +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketOpenStateUpdateNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketOpenStateUpdateNotify.java index dc18ba836..cb233ecc6 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketOpenStateUpdateNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketOpenStateUpdateNotify.java @@ -13,20 +13,20 @@ import emu.grasscutter.net.proto.OpenStateUpdateNotifyOuterClass.OpenStateUpdate public class PacketOpenStateUpdateNotify extends BasePacket { public PacketOpenStateUpdateNotify(PlayerOpenStateManager manager) { - super(PacketOpcodes.OpenStateUpdateNotify); + super(PacketOpcodes.OpenStateUpdateNotify); - OpenStateUpdateNotify.Builder proto = OpenStateUpdateNotify.newBuilder(); + OpenStateUpdateNotify.Builder proto = OpenStateUpdateNotify.newBuilder(); - for (OpenState state : OpenState.values()) { - // If the player has an open state stored in their map, then it would always override any default value - if (manager.getOpenStateMap().containsKey(state.getValue())) { - proto.putOpenStateMap(state.getValue(), manager.getOpenState(state)); - } else if (PlayerOpenStateManager.DEV_OPEN_STATES.contains(state)) { - // Add default value here. TODO properly put default values somewhere - proto.putOpenStateMap(state.getValue(), 1); - } - } + for (OpenState state : OpenState.values()) { + // If the player has an open state stored in their map, then it would always override any default value + if (manager.getOpenStateMap().containsKey(state.getValue())) { + proto.putOpenStateMap(state.getValue(), manager.getOpenState(state)); + } else if (PlayerOpenStateManager.DEV_OPEN_STATES.contains(state)) { + // Add default value here. TODO properly put default values somewhere + proto.putOpenStateMap(state.getValue(), 1); + } + } - this.setData(proto); - } + this.setData(proto); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerEnterSceneNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerEnterSceneNotify.java index a74ac4145..461b0bdce 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerEnterSceneNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerEnterSceneNotify.java @@ -11,60 +11,60 @@ import emu.grasscutter.utils.Position; import emu.grasscutter.utils.Utils; public class PacketPlayerEnterSceneNotify extends BasePacket { - - // Login - public PacketPlayerEnterSceneNotify(Player player) { - super(PacketOpcodes.PlayerEnterSceneNotify); - - player.setSceneLoadState(SceneLoadState.LOADING); - player.setEnterSceneToken(Utils.randomRange(1000, 99999)); - PlayerEnterSceneNotify proto = PlayerEnterSceneNotify.newBuilder() - .setSceneId(player.getSceneId()) - .setPos(player.getPosition().toProto()) - .setSceneBeginTime(System.currentTimeMillis()) - .setType(EnterType.ENTER_TYPE_SELF) - .setTargetUid(player.getUid()) - .setEnterSceneToken(player.getEnterSceneToken()) - .setWorldLevel(player.getWorldLevel()) - .setEnterReason(EnterReason.Login.getValue()) - .setIsFirstLoginEnterScene(player.isFirstLoginEnterScene()) - .setWorldType(1) - .setSceneTransaction("3-" + player.getUid() + "-" + (int) (System.currentTimeMillis() / 1000) + "-" + 18402) - .build(); - - this.setData(proto); - } - - public PacketPlayerEnterSceneNotify(Player player, EnterType type, EnterReason reason, int newScene, Position newPos) { - this(player, player, type, reason, newScene, newPos); - } - - // Teleport or go somewhere - public PacketPlayerEnterSceneNotify(Player player, Player target, EnterType type, EnterReason reason, int newScene, Position newPos) { - super(PacketOpcodes.PlayerEnterSceneNotify); - - player.setSceneLoadState(SceneLoadState.LOADING); - player.setEnterSceneToken(Utils.randomRange(1000, 99999)); + // Login + public PacketPlayerEnterSceneNotify(Player player) { + super(PacketOpcodes.PlayerEnterSceneNotify); - PlayerEnterSceneNotify.Builder proto = PlayerEnterSceneNotify.newBuilder() - .setPrevSceneId(player.getSceneId()) - .setPrevPos(player.getPosition().toProto()) - .setSceneId(newScene) - .setPos(newPos.toProto()) - .setSceneBeginTime(System.currentTimeMillis()) - .setType(type) - .setTargetUid(target.getUid()) - .setEnterSceneToken(player.getEnterSceneToken()) - .setWorldLevel(target.getWorld().getWorldLevel()) - .setEnterReason(reason.getValue()) - .setWorldType(1) - .setSceneTransaction(newScene + "-" + target.getUid() + "-" + (int) (System.currentTimeMillis() / 1000) + "-" + 18402); + player.setSceneLoadState(SceneLoadState.LOADING); + player.setEnterSceneToken(Utils.randomRange(1000, 99999)); - for(int i = 0; i < 3000; i++) { - proto.addSceneTagIdList(i); - } + PlayerEnterSceneNotify proto = PlayerEnterSceneNotify.newBuilder() + .setSceneId(player.getSceneId()) + .setPos(player.getPosition().toProto()) + .setSceneBeginTime(System.currentTimeMillis()) + .setType(EnterType.ENTER_TYPE_SELF) + .setTargetUid(player.getUid()) + .setEnterSceneToken(player.getEnterSceneToken()) + .setWorldLevel(player.getWorldLevel()) + .setEnterReason(EnterReason.Login.getValue()) + .setIsFirstLoginEnterScene(player.isFirstLoginEnterScene()) + .setWorldType(1) + .setSceneTransaction("3-" + player.getUid() + "-" + (int) (System.currentTimeMillis() / 1000) + "-" + 18402) + .build(); - this.setData(proto.build()); - } + this.setData(proto); + } + + public PacketPlayerEnterSceneNotify(Player player, EnterType type, EnterReason reason, int newScene, Position newPos) { + this(player, player, type, reason, newScene, newPos); + } + + // Teleport or go somewhere + public PacketPlayerEnterSceneNotify(Player player, Player target, EnterType type, EnterReason reason, int newScene, Position newPos) { + super(PacketOpcodes.PlayerEnterSceneNotify); + + player.setSceneLoadState(SceneLoadState.LOADING); + player.setEnterSceneToken(Utils.randomRange(1000, 99999)); + + PlayerEnterSceneNotify.Builder proto = PlayerEnterSceneNotify.newBuilder() + .setPrevSceneId(player.getSceneId()) + .setPrevPos(player.getPosition().toProto()) + .setSceneId(newScene) + .setPos(newPos.toProto()) + .setSceneBeginTime(System.currentTimeMillis()) + .setType(type) + .setTargetUid(target.getUid()) + .setEnterSceneToken(player.getEnterSceneToken()) + .setWorldLevel(target.getWorld().getWorldLevel()) + .setEnterReason(reason.getValue()) + .setWorldType(1) + .setSceneTransaction(newScene + "-" + target.getUid() + "-" + (int) (System.currentTimeMillis() / 1000) + "-" + 18402); + + for (int i = 0; i < 3000; i++) { + proto.addSceneTagIdList(i); + } + + this.setData(proto.build()); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerLoginRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerLoginRsp.java index a05075460..696e8cd2a 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerLoginRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerLoginRsp.java @@ -21,53 +21,53 @@ import java.util.Objects; public class PacketPlayerLoginRsp extends BasePacket { - private static QueryCurrRegionHttpRspOuterClass.QueryCurrRegionHttpRsp regionCache; + private static QueryCurrRegionHttpRspOuterClass.QueryCurrRegionHttpRsp regionCache; - public PacketPlayerLoginRsp(GameSession session) { - super(PacketOpcodes.PlayerLoginRsp, 1); - - this.setUseDispatchKey(true); + public PacketPlayerLoginRsp(GameSession session) { + super(PacketOpcodes.PlayerLoginRsp, 1); - RegionInfo info; + this.setUseDispatchKey(true); - if (SERVER.runMode == ServerRunMode.GAME_ONLY) { - if (regionCache == null) { - try { - // todo: we might want to push custom config to client - RegionInfo serverRegion = RegionInfo.newBuilder() - .setGateserverIp(lr(GAME_INFO.accessAddress, GAME_INFO.bindAddress)) - .setGateserverPort(lr(GAME_INFO.accessPort, GAME_INFO.bindPort)) - .setSecretKey(ByteString.copyFrom(Crypto.DISPATCH_SEED)) - .build(); + RegionInfo info; - regionCache = QueryCurrRegionHttpRspOuterClass.QueryCurrRegionHttpRsp.newBuilder().setRegionInfo(serverRegion).build(); - } catch (Exception e) { - Grasscutter.getLogger().error("Error while initializing region cache!", e); - } - } + if (SERVER.runMode == ServerRunMode.GAME_ONLY) { + if (regionCache == null) { + try { + // todo: we might want to push custom config to client + RegionInfo serverRegion = RegionInfo.newBuilder() + .setGateserverIp(lr(GAME_INFO.accessAddress, GAME_INFO.bindAddress)) + .setGateserverPort(lr(GAME_INFO.accessPort, GAME_INFO.bindPort)) + .setSecretKey(ByteString.copyFrom(Crypto.DISPATCH_SEED)) + .build(); - info = regionCache.getRegionInfo(); - } else { - info = Objects.requireNonNull(RegionHandler.getCurrentRegion()).getRegionInfo(); - } + regionCache = QueryCurrRegionHttpRspOuterClass.QueryCurrRegionHttpRsp.newBuilder().setRegionInfo(serverRegion).build(); + } catch (Exception e) { + Grasscutter.getLogger().error("Error while initializing region cache!", e); + } + } - PlayerLoginRsp p = PlayerLoginRsp.newBuilder() - .setIsUseAbilityHash(true) // true - .setAbilityHashCode(1844674) // 1844674 - .setGameBiz("hk4e_global") - .setClientDataVersion(info.getClientDataVersion()) - .setClientSilenceDataVersion(info.getClientSilenceDataVersion()) - .setClientMd5(info.getClientDataMd5()) - .setClientSilenceMd5(info.getClientSilenceDataMd5()) - .setResVersionConfig(info.getResVersionConfig()) - .setClientVersionSuffix(info.getClientVersionSuffix()) - .setClientSilenceVersionSuffix(info.getClientSilenceVersionSuffix()) - .setIsScOpen(false) - //.setScInfo(ByteString.copyFrom(new byte[] {})) - .setRegisterCps("mihoyo") - .setCountryCode("US") - .build(); - - this.setData(p.toByteArray()); - } + info = regionCache.getRegionInfo(); + } else { + info = Objects.requireNonNull(RegionHandler.getCurrentRegion()).getRegionInfo(); + } + + PlayerLoginRsp p = PlayerLoginRsp.newBuilder() + .setIsUseAbilityHash(true) // true + .setAbilityHashCode(1844674) // 1844674 + .setGameBiz("hk4e_global") + .setClientDataVersion(info.getClientDataVersion()) + .setClientSilenceDataVersion(info.getClientSilenceDataVersion()) + .setClientMd5(info.getClientDataMd5()) + .setClientSilenceMd5(info.getClientSilenceDataMd5()) + .setResVersionConfig(info.getResVersionConfig()) + .setClientVersionSuffix(info.getClientVersionSuffix()) + .setClientSilenceVersionSuffix(info.getClientSilenceVersionSuffix()) + .setIsScOpen(false) + //.setScInfo(ByteString.copyFrom(new byte[] {})) + .setRegisterCps("mihoyo") + .setCountryCode("US") + .build(); + + this.setData(p.toByteArray()); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerStoreNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerStoreNotify.java index 01c89a4ae..0445d068a 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerStoreNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerStoreNotify.java @@ -11,21 +11,21 @@ import emu.grasscutter.net.proto.PlayerStoreNotifyOuterClass.PlayerStoreNotify; import emu.grasscutter.net.proto.StoreTypeOuterClass.StoreType; public class PacketPlayerStoreNotify extends BasePacket { - - public PacketPlayerStoreNotify(Player player) { - super(PacketOpcodes.PlayerStoreNotify); - - this.buildHeader(2); - - PlayerStoreNotify.Builder p = PlayerStoreNotify.newBuilder() - .setStoreType(StoreType.STORE_TYPE_PACK) - .setWeightLimit(GAME_OPTIONS.inventoryLimits.all); - - for (GameItem item : player.getInventory()) { - Item itemProto = item.toProto(); - p.addItemList(itemProto); - } - - this.setData(p.build()); - } + + public PacketPlayerStoreNotify(Player player) { + super(PacketOpcodes.PlayerStoreNotify); + + this.buildHeader(2); + + PlayerStoreNotify.Builder p = PlayerStoreNotify.newBuilder() + .setStoreType(StoreType.STORE_TYPE_PACK) + .setWeightLimit(GAME_OPTIONS.inventoryLimits.all); + + for (GameItem item : player.getInventory()) { + Item itemProto = item.toProto(); + p.addItemList(itemProto); + } + + this.setData(p.build()); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerWorldSceneInfoListNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerWorldSceneInfoListNotify.java index 51b6fef10..458a09288 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerWorldSceneInfoListNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketPlayerWorldSceneInfoListNotify.java @@ -9,64 +9,64 @@ import emu.grasscutter.net.proto.SceneUnlockInfoOuterClass.SceneUnlockInfo; import static emu.grasscutter.net.proto.PlayerWorldSceneInfoOuterClass.*; public class PacketPlayerWorldSceneInfoListNotify extends BasePacket { - - public PacketPlayerWorldSceneInfoListNotify() { - super(PacketOpcodes.PlayerWorldSceneInfoListNotify); // Rename opcode later - PlayerWorldSceneInfoListNotify.Builder proto = PlayerWorldSceneInfoListNotify.newBuilder() - .addInfoList( - PlayerWorldSceneInfo.newBuilder() - .setSceneId(1) - .setIsLocked(false) - .build() - ) - .addInfoList( - PlayerWorldSceneInfo.newBuilder() - .setSceneId(3) - .setIsLocked(false) - .addSceneTagIdList(102) - .addSceneTagIdList(113) - .addSceneTagIdList(117) - .build() - ) - .addInfoList( - PlayerWorldSceneInfo.newBuilder() - .setSceneId(4) - .setIsLocked(false) - .addSceneTagIdList(106) - .addSceneTagIdList(109) - .addSceneTagIdList(117) - .build() - ) - .addInfoList( - PlayerWorldSceneInfo.newBuilder() - .setSceneId(5) - .setIsLocked(false) - .build() - ) - .addInfoList( - PlayerWorldSceneInfo.newBuilder() - .setSceneId(6) - .setIsLocked(false) - .build() - ) - .addInfoList( - PlayerWorldSceneInfo.newBuilder() - .setSceneId(7) - .setIsLocked(false) - .build() - ); + public PacketPlayerWorldSceneInfoListNotify() { + super(PacketOpcodes.PlayerWorldSceneInfoListNotify); // Rename opcode later - var gaa = PlayerWorldSceneInfo.newBuilder() - .setSceneId(9) - .setIsLocked(false); + PlayerWorldSceneInfoListNotify.Builder proto = PlayerWorldSceneInfoListNotify.newBuilder() + .addInfoList( + PlayerWorldSceneInfo.newBuilder() + .setSceneId(1) + .setIsLocked(false) + .build() + ) + .addInfoList( + PlayerWorldSceneInfo.newBuilder() + .setSceneId(3) + .setIsLocked(false) + .addSceneTagIdList(102) + .addSceneTagIdList(113) + .addSceneTagIdList(117) + .build() + ) + .addInfoList( + PlayerWorldSceneInfo.newBuilder() + .setSceneId(4) + .setIsLocked(false) + .addSceneTagIdList(106) + .addSceneTagIdList(109) + .addSceneTagIdList(117) + .build() + ) + .addInfoList( + PlayerWorldSceneInfo.newBuilder() + .setSceneId(5) + .setIsLocked(false) + .build() + ) + .addInfoList( + PlayerWorldSceneInfo.newBuilder() + .setSceneId(6) + .setIsLocked(false) + .build() + ) + .addInfoList( + PlayerWorldSceneInfo.newBuilder() + .setSceneId(7) + .setIsLocked(false) + .build() + ); - for(int i = 0; i < 3000; i++) { - gaa.addSceneTagIdList(i); - } + var gaa = PlayerWorldSceneInfo.newBuilder() + .setSceneId(9) + .setIsLocked(false); - proto.addInfoList(gaa); + for (int i = 0; i < 3000; i++) { + gaa.addSceneTagIdList(i); + } - this.setData(proto); - } + proto.addInfoList(gaa); + + this.setData(proto); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketPrivateChatNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketPrivateChatNotify.java index 6454b497c..56516f6cc 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketPrivateChatNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketPrivateChatNotify.java @@ -6,45 +6,45 @@ import emu.grasscutter.net.proto.ChatInfoOuterClass.ChatInfo; import emu.grasscutter.net.proto.PrivateChatNotifyOuterClass.PrivateChatNotify; public class PacketPrivateChatNotify extends BasePacket { - private ChatInfo info; + private ChatInfo info; - public PacketPrivateChatNotify(int senderId, int recvId, String message) { - super(PacketOpcodes.PrivateChatNotify); - - ChatInfo info = ChatInfo.newBuilder() - .setTime((int) (System.currentTimeMillis() / 1000)) - .setUid(senderId) - .setToUid(recvId) - .setText(message) - .build(); - this.info = info; + public PacketPrivateChatNotify(int senderId, int recvId, String message) { + super(PacketOpcodes.PrivateChatNotify); - PrivateChatNotify proto = PrivateChatNotify.newBuilder() - .setChatInfo(info) - .build(); - - this.setData(proto); - } - - public PacketPrivateChatNotify(int senderId, int recvId, int emote) { - super(PacketOpcodes.PrivateChatNotify); - - ChatInfo info = ChatInfo.newBuilder() - .setTime((int) (System.currentTimeMillis() / 1000)) - .setUid(senderId) - .setToUid(recvId) - .setIcon(emote) - .build(); - this.info = info; - - PrivateChatNotify proto = PrivateChatNotify.newBuilder() - .setChatInfo(info) - .build(); - - this.setData(proto); - } + ChatInfo info = ChatInfo.newBuilder() + .setTime((int) (System.currentTimeMillis() / 1000)) + .setUid(senderId) + .setToUid(recvId) + .setText(message) + .build(); + this.info = info; - public ChatInfo getChatInfo() { - return this.info; - } + PrivateChatNotify proto = PrivateChatNotify.newBuilder() + .setChatInfo(info) + .build(); + + this.setData(proto); + } + + public PacketPrivateChatNotify(int senderId, int recvId, int emote) { + super(PacketOpcodes.PrivateChatNotify); + + ChatInfo info = ChatInfo.newBuilder() + .setTime((int) (System.currentTimeMillis() / 1000)) + .setUid(senderId) + .setToUid(recvId) + .setIcon(emote) + .build(); + this.info = info; + + PrivateChatNotify proto = PrivateChatNotify.newBuilder() + .setChatInfo(info) + .build(); + + this.setData(proto); + } + + public ChatInfo getChatInfo() { + return this.info; + } } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketPullPrivateChatRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketPullPrivateChatRsp.java index e7f52a5af..3bdf90f6e 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketPullPrivateChatRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketPullPrivateChatRsp.java @@ -9,21 +9,21 @@ import emu.grasscutter.net.proto.PullPrivateChatRspOuterClass.PullPrivateChatRsp import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode; public class PacketPullPrivateChatRsp extends BasePacket { - - public PacketPullPrivateChatRsp(List history) { - super(PacketOpcodes.PullPrivateChatRsp); - PullPrivateChatRsp.Builder builder = PullPrivateChatRsp.newBuilder(); + public PacketPullPrivateChatRsp(List history) { + super(PacketOpcodes.PullPrivateChatRsp); - if (history == null) { - builder.setRetcode(Retcode.RET_FAIL_VALUE); - } - else { - for (var info : history) { - builder.addChatInfo(info); - } - } - - this.setData(builder.build()); - } + PullPrivateChatRsp.Builder builder = PullPrivateChatRsp.newBuilder(); + + if (history == null) { + builder.setRetcode(Retcode.RET_FAIL_VALUE); + } + else { + for (var info : history) { + builder.addChatInfo(info); + } + } + + this.setData(builder.build()); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketPullRecentChatRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketPullRecentChatRsp.java index ac846f8a9..c24f20f5a 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketPullRecentChatRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketPullRecentChatRsp.java @@ -13,12 +13,12 @@ import static emu.grasscutter.config.Configuration.*; import java.util.List; public class PacketPullRecentChatRsp extends BasePacket { - public PacketPullRecentChatRsp(List messages) { - super(PacketOpcodes.PullRecentChatRsp); - - PullRecentChatRsp.Builder proto = PullRecentChatRsp.newBuilder() - .addAllChatInfo(messages); + public PacketPullRecentChatRsp(List messages) { + super(PacketOpcodes.PullRecentChatRsp); - this.setData(proto); - } + PullRecentChatRsp.Builder proto = PullRecentChatRsp.newBuilder() + .addAllChatInfo(messages); + + this.setData(proto); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketSetOpenStateRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketSetOpenStateRsp.java index de94fdc90..939b473c1 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketSetOpenStateRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketSetOpenStateRsp.java @@ -15,4 +15,4 @@ public class PacketSetOpenStateRsp extends BasePacket { this.setData(proto); } -} \ No newline at end of file +} diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketStoreWeightLimitNotify.java b/src/main/java/emu/grasscutter/server/packet/send/PacketStoreWeightLimitNotify.java index 17ccf8865..98cdde1b7 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketStoreWeightLimitNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketStoreWeightLimitNotify.java @@ -8,19 +8,19 @@ import emu.grasscutter.net.proto.StoreTypeOuterClass.StoreType; import emu.grasscutter.net.proto.StoreWeightLimitNotifyOuterClass.StoreWeightLimitNotify; public class PacketStoreWeightLimitNotify extends BasePacket { - - public PacketStoreWeightLimitNotify() { - super(PacketOpcodes.StoreWeightLimitNotify); - StoreWeightLimitNotify p = StoreWeightLimitNotify.newBuilder() - .setStoreType(StoreType.STORE_TYPE_PACK) - .setWeightLimit(INVENTORY_LIMITS.all) - .setWeaponCountLimit(INVENTORY_LIMITS.weapons) - .setReliquaryCountLimit(INVENTORY_LIMITS.relics) - .setMaterialCountLimit(INVENTORY_LIMITS.materials) - .setFurnitureCountLimit(INVENTORY_LIMITS.furniture) - .build(); - - this.setData(p); - } + public PacketStoreWeightLimitNotify() { + super(PacketOpcodes.StoreWeightLimitNotify); + + StoreWeightLimitNotify p = StoreWeightLimitNotify.newBuilder() + .setStoreType(StoreType.STORE_TYPE_PACK) + .setWeightLimit(INVENTORY_LIMITS.all) + .setWeaponCountLimit(INVENTORY_LIMITS.weapons) + .setReliquaryCountLimit(INVENTORY_LIMITS.relics) + .setMaterialCountLimit(INVENTORY_LIMITS.materials) + .setFurnitureCountLimit(INVENTORY_LIMITS.furniture) + .build(); + + this.setData(p); + } } diff --git a/src/main/java/emu/grasscutter/server/packet/send/PacketTowerAllDataRsp.java b/src/main/java/emu/grasscutter/server/packet/send/PacketTowerAllDataRsp.java index e7adf1833..18424f95e 100644 --- a/src/main/java/emu/grasscutter/server/packet/send/PacketTowerAllDataRsp.java +++ b/src/main/java/emu/grasscutter/server/packet/send/PacketTowerAllDataRsp.java @@ -16,49 +16,49 @@ import java.util.stream.Collectors; import java.util.stream.IntStream; public class PacketTowerAllDataRsp extends BasePacket { - - public PacketTowerAllDataRsp(TowerSystem towerScheduleManager, TowerManager towerManager) { - super(PacketOpcodes.TowerAllDataRsp); - var recordList = towerManager.getRecordMap().values().stream() - .map(rec -> TowerFloorRecord.newBuilder() - .setFloorId(rec.getFloorId()) - .setFloorStarRewardProgress(rec.getFloorStarRewardProgress()) - .putAllPassedLevelMap(rec.getPassedLevelMap()) - .addAllPassedLevelRecordList(buildFromPassedLevelMap(rec.getPassedLevelMap())) - .build() - ) - .toList(); + public PacketTowerAllDataRsp(TowerSystem towerScheduleManager, TowerManager towerManager) { + super(PacketOpcodes.TowerAllDataRsp); - var openTimeMap = towerScheduleManager.getScheduleFloors().stream() - .collect(Collectors.toMap(x -> x, - y -> DateHelper.getUnixTime(towerScheduleManager.getTowerScheduleConfig() - .getScheduleStartTime())) - ); + var recordList = towerManager.getRecordMap().values().stream() + .map(rec -> TowerFloorRecord.newBuilder() + .setFloorId(rec.getFloorId()) + .setFloorStarRewardProgress(rec.getFloorStarRewardProgress()) + .putAllPassedLevelMap(rec.getPassedLevelMap()) + .addAllPassedLevelRecordList(buildFromPassedLevelMap(rec.getPassedLevelMap())) + .build() + ) + .toList(); - TowerAllDataRsp proto = TowerAllDataRsp.newBuilder() - .setTowerScheduleId(towerScheduleManager.getCurrentTowerScheduleData().getScheduleId()) - .addAllTowerFloorRecordList(recordList) - .setCurLevelRecord(TowerCurLevelRecord.newBuilder().setIsEmpty(true)) - .setScheduleStartTime(DateHelper.getUnixTime(towerScheduleManager.getTowerScheduleConfig() - .getScheduleStartTime())) - .setNextScheduleChangeTime(DateHelper.getUnixTime(towerScheduleManager.getTowerScheduleConfig() - .getNextScheduleChangeTime())) - .putAllFloorOpenTimeMap(openTimeMap) - .setIsFinishedEntranceFloor(towerManager.canEnterScheduleFloor()) - .build(); - - this.setData(proto); - } + var openTimeMap = towerScheduleManager.getScheduleFloors().stream() + .collect(Collectors.toMap(x -> x, + y -> DateHelper.getUnixTime(towerScheduleManager.getTowerScheduleConfig() + .getScheduleStartTime())) + ); - private List buildFromPassedLevelMap(Map map){ - return map.entrySet().stream() - .map(item -> TowerLevelRecordOuterClass.TowerLevelRecord.newBuilder() - .setLevelId(item.getKey()) - .addAllSatisfiedCondList(IntStream.range(1, item.getValue() + 1).boxed().toList()) - .build()) - .toList(); + TowerAllDataRsp proto = TowerAllDataRsp.newBuilder() + .setTowerScheduleId(towerScheduleManager.getCurrentTowerScheduleData().getScheduleId()) + .addAllTowerFloorRecordList(recordList) + .setCurLevelRecord(TowerCurLevelRecord.newBuilder().setIsEmpty(true)) + .setScheduleStartTime(DateHelper.getUnixTime(towerScheduleManager.getTowerScheduleConfig() + .getScheduleStartTime())) + .setNextScheduleChangeTime(DateHelper.getUnixTime(towerScheduleManager.getTowerScheduleConfig() + .getNextScheduleChangeTime())) + .putAllFloorOpenTimeMap(openTimeMap) + .setIsFinishedEntranceFloor(towerManager.canEnterScheduleFloor()) + .build(); - } + this.setData(proto); + } + + private List buildFromPassedLevelMap(Map map) { + return map.entrySet().stream() + .map(item -> TowerLevelRecordOuterClass.TowerLevelRecord.newBuilder() + .setLevelId(item.getKey()) + .addAllSatisfiedCondList(IntStream.range(1, item.getValue() + 1).boxed().toList()) + .build()) + .toList(); + + } } diff --git a/src/main/java/emu/grasscutter/tools/Tools.java b/src/main/java/emu/grasscutter/tools/Tools.java index c473a145a..e34a68f29 100644 --- a/src/main/java/emu/grasscutter/tools/Tools.java +++ b/src/main/java/emu/grasscutter/tools/Tools.java @@ -31,236 +31,236 @@ import static emu.grasscutter.config.Configuration.*; import static emu.grasscutter.utils.Language.translate; public final class Tools { - public static void createGmHandbook() throws Exception { - ToolsWithLanguageOption.createGmHandbook(getLanguageOption()); - } + public static void createGmHandbook() throws Exception { + ToolsWithLanguageOption.createGmHandbook(getLanguageOption()); + } - public static void createGachaMapping(String location) throws Exception { - ToolsWithLanguageOption.createGachaMapping(location, getLanguageOption()); - } + public static void createGachaMapping(String location) throws Exception { + ToolsWithLanguageOption.createGachaMapping(location, getLanguageOption()); + } - public static List getAvailableLanguage() { - File textMapFolder = new File(RESOURCE("TextMap")); - List availableLangList = new ArrayList<>(); - for (String textMapFileName : Objects.requireNonNull(textMapFolder.list((dir, name) -> name.startsWith("TextMap") && name.endsWith(".json")))) { - availableLangList.add(textMapFileName.replace("TextMap", "").replace(".json", "").toLowerCase()); - } return availableLangList; - } + public static List getAvailableLanguage() { + File textMapFolder = new File(RESOURCE("TextMap")); + List availableLangList = new ArrayList<>(); + for (String textMapFileName : Objects.requireNonNull(textMapFolder.list((dir, name) -> name.startsWith("TextMap") && name.endsWith(".json")))) { + availableLangList.add(textMapFileName.replace("TextMap", "").replace(".json", "").toLowerCase()); + } return availableLangList; + } - public static String getLanguageOption() { - List availableLangList = getAvailableLanguage(); - - // Use system out for better format - if (availableLangList.size() == 1) { - return availableLangList.get(0).toUpperCase(); - } - StringBuilder stagedMessage = new StringBuilder(); - stagedMessage.append("The following languages mappings are available, please select one: [default: EN] \n"); - - StringBuilder groupedLangList = new StringBuilder(">\t"); String input; - int groupedLangCount = 0; - - for (String availableLanguage: availableLangList){ - groupedLangCount++; - groupedLangList.append(availableLanguage).append("\t"); - - if (groupedLangCount == 6) { - stagedMessage.append(groupedLangList).append("\n"); - groupedLangCount = 0; - groupedLangList = new StringBuilder(">\t"); - } - } - - if (groupedLangCount > 0) { - stagedMessage.append(groupedLangList).append("\n"); - } - - stagedMessage.append("\nYour choice:[EN] "); - - input = Grasscutter.getConsole().readLine(stagedMessage.toString()); - if (availableLangList.contains(input.toLowerCase())) { - return input.toUpperCase(); - } - Grasscutter.getLogger().info("Invalid option. Will use EN(English) as fallback"); + public static String getLanguageOption() { + List availableLangList = getAvailableLanguage(); - return "EN"; - } + // Use system out for better format + if (availableLangList.size() == 1) { + return availableLangList.get(0).toUpperCase(); + } + StringBuilder stagedMessage = new StringBuilder(); + stagedMessage.append("The following languages mappings are available, please select one: [default: EN] \n"); + + StringBuilder groupedLangList = new StringBuilder(">\t"); String input; + int groupedLangCount = 0; + + for (String availableLanguage: availableLangList) { + groupedLangCount++; + groupedLangList.append(availableLanguage).append("\t"); + + if (groupedLangCount == 6) { + stagedMessage.append(groupedLangList).append("\n"); + groupedLangCount = 0; + groupedLangList = new StringBuilder(">\t"); + } + } + + if (groupedLangCount > 0) { + stagedMessage.append(groupedLangList).append("\n"); + } + + stagedMessage.append("\nYour choice:[EN] "); + + input = Grasscutter.getConsole().readLine(stagedMessage.toString()); + if (availableLangList.contains(input.toLowerCase())) { + return input.toUpperCase(); + } + Grasscutter.getLogger().info("Invalid option. Will use EN(English) as fallback"); + + return "EN"; + } } final class ToolsWithLanguageOption { - @SuppressWarnings("deprecation") - public static void createGmHandbook(String language) throws Exception { - ResourceLoader.loadAll(); - - Map map; - try (InputStreamReader fileReader = new InputStreamReader(new FileInputStream(Utils.toFilePath(RESOURCE("TextMap/TextMap"+language+".json"))), StandardCharsets.UTF_8)) { - map = Grasscutter.getGsonFactory().fromJson(fileReader, new TypeToken>() {}.getType()); - } - - List list; - String fileName = "./GM Handbook.txt"; - try (PrintWriter writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(fileName), StandardCharsets.UTF_8), false)) { - DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"); - LocalDateTime now = LocalDateTime.now(); - - writer.println("// Grasscutter " + GameConstants.VERSION + " GM Handbook"); - writer.println("// Created " + dtf.format(now) + System.lineSeparator() + System.lineSeparator()); + @SuppressWarnings("deprecation") + public static void createGmHandbook(String language) throws Exception { + ResourceLoader.loadAll(); - CommandMap cmdMap = new CommandMap(true); - List cmdList = new ArrayList<>(cmdMap.getAnnotationsAsList()); + Map map; + try (InputStreamReader fileReader = new InputStreamReader(new FileInputStream(Utils.toFilePath(RESOURCE("TextMap/TextMap"+language+".json"))), StandardCharsets.UTF_8)) { + map = Grasscutter.getGsonFactory().fromJson(fileReader, new TypeToken>() {}.getType()); + } - writer.println("// Commands"); - for (Command cmd : cmdList) { - StringBuilder cmdName = new StringBuilder(cmd.label()); - while (cmdName.length() <= 15) { - cmdName.insert(0, " "); - } - writer.println(cmdName + " : " + translate(cmd.description())); - } - writer.println(); + List list; + String fileName = "./GM Handbook.txt"; + try (PrintWriter writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(fileName), StandardCharsets.UTF_8), false)) { + DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"); + LocalDateTime now = LocalDateTime.now(); - list = new ArrayList<>(GameData.getAvatarDataMap().keySet()); - Collections.sort(list); - - writer.println("// Avatars"); - for (Integer id : list) { - AvatarData data = GameData.getAvatarDataMap().get(id); - writer.println(data.getId() + " : " + map.get(data.getNameTextMapHash())); - } - - writer.println(); - - list = new ArrayList<>(GameData.getItemDataMap().keySet()); - Collections.sort(list); - - writer.println("// Items"); - for (Integer id : list) { - ItemData data = GameData.getItemDataMap().get(id); - writer.println(data.getId() + " : " + map.get(data.getNameTextMapHash())); - } - - writer.println(); - - writer.println("// Scenes"); - list = new ArrayList<>(GameData.getSceneDataMap().keySet()); - Collections.sort(list); - - for (Integer id : list) { - SceneData data = GameData.getSceneDataMap().get(id); - writer.println(data.getId() + " : " + data.getScriptData()); - } - - writer.println(); - - writer.println("// Quests"); - list = new ArrayList<>(GameData.getQuestDataMap().keySet()); - Collections.sort(list); - - for (Integer id : list) { - QuestData data = GameData.getQuestDataMap().get(id); - MainQuestData mainQuest = GameData.getMainQuestDataMap().get(data.getMainId()); - if (mainQuest != null) { - writer.println(data.getId() + " : " + map.get(mainQuest.getTitleTextMapHash()) + " - " + map.get(data.getDescTextMapHash())); - } - } - - writer.println(); - - writer.println("// Monsters"); - list = new ArrayList<>(GameData.getMonsterDataMap().keySet()); - Collections.sort(list); - - for (Integer id : list) { - MonsterData data = GameData.getMonsterDataMap().get(id); - writer.println(data.getId() + " : " + map.get(data.getNameTextMapHash())); - } - } - - Grasscutter.getLogger().info("GM Handbook generated!"); - } + writer.println("// Grasscutter " + GameConstants.VERSION + " GM Handbook"); + writer.println("// Created " + dtf.format(now) + System.lineSeparator() + System.lineSeparator()); - @SuppressWarnings("deprecation") - public static void createGachaMapping(String location, String language) throws Exception { - ResourceLoader.loadResources(); - - Map map; - try (InputStreamReader fileReader = new InputStreamReader(new FileInputStream(Utils.toFilePath(RESOURCE("TextMap/TextMap" + language + ".json"))), StandardCharsets.UTF_8)) { - map = Grasscutter.getGsonFactory().fromJson(fileReader, new TypeToken>() {}.getType()); - } - - List list; + CommandMap cmdMap = new CommandMap(true); + List cmdList = new ArrayList<>(cmdMap.getAnnotationsAsList()); - try (PrintWriter writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(location), StandardCharsets.UTF_8), false)) { - list = new ArrayList<>(GameData.getAvatarDataMap().keySet()); - Collections.sort(list); - - // if the user made choices for language, I assume it's okay to assign his/her selected language to "en-us" - // since it's the fallback language and there will be no difference in the gacha record page. - // The enduser can still modify the `gacha_mappings.js` directly to enable multilingual for the gacha record system. - writer.println("mappings = {\"en-us\": {"); + writer.println("// Commands"); + for (Command cmd : cmdList) { + StringBuilder cmdName = new StringBuilder(cmd.label()); + while (cmdName.length() <= 15) { + cmdName.insert(0, " "); + } + writer.println(cmdName + " : " + translate(cmd.description())); + } + writer.println(); - // Avatars - boolean first = true; - for (Integer id : list) { - AvatarData data = GameData.getAvatarDataMap().get(id); - int avatarID = data.getId(); - if (avatarID >= 11000000) { // skip test avatar - continue; - } - if (first) { // skip adding comma for the first element - first = false; - } else { - writer.print(","); - } - String color = switch (data.getQualityType()) { - case "QUALITY_PURPLE" -> "purple"; - case "QUALITY_ORANGE" -> "yellow"; - default -> "blue"; - }; - // Got the magic number 4233146695 from manually search in the json file - writer.println( - "\"" + (avatarID % 1000 + 1000) + "\" : [\"" - + map.get(data.getNameTextMapHash()) + "(" + map.get(4233146695L)+ ")\", \"" - + color + "\"]"); - } - - writer.println(); - - list = new ArrayList<>(GameData.getItemDataMap().keySet()); - Collections.sort(list); - - // Weapons - for (Integer id : list) { - ItemData data = GameData.getItemDataMap().get(id); - if (data.getId() <= 11101 || data.getId() >= 20000) { - continue; //skip non weapon items - } - String color; + list = new ArrayList<>(GameData.getAvatarDataMap().keySet()); + Collections.sort(list); - switch (data.getRankLevel()){ - case 3: - color = "blue"; - break; - case 4: - color = "purple"; - break; - case 5: - color = "yellow"; - break; - default: - continue; // skip unnecessary entries - } - - // Got the magic number 4231343903 from manually search in the json file + writer.println("// Avatars"); + for (Integer id : list) { + AvatarData data = GameData.getAvatarDataMap().get(id); + writer.println(data.getId() + " : " + map.get(data.getNameTextMapHash())); + } - writer.println(",\"" + data.getId() + - "\" : [\"" + map.get(data.getNameTextMapHash()).replaceAll("\"", "") - + "("+ map.get(4231343903L)+")\",\""+ color + "\"]"); - } - writer.println(",\"200\": \""+map.get(332935371L)+"\", \"301\": \""+ map.get(2272170627L) + "\", \"302\": \""+map.get(2864268523L)+"\""); - writer.println("}\n}"); - } - - Grasscutter.getLogger().info("Mappings generated to " + location + " !"); - } + writer.println(); + + list = new ArrayList<>(GameData.getItemDataMap().keySet()); + Collections.sort(list); + + writer.println("// Items"); + for (Integer id : list) { + ItemData data = GameData.getItemDataMap().get(id); + writer.println(data.getId() + " : " + map.get(data.getNameTextMapHash())); + } + + writer.println(); + + writer.println("// Scenes"); + list = new ArrayList<>(GameData.getSceneDataMap().keySet()); + Collections.sort(list); + + for (Integer id : list) { + SceneData data = GameData.getSceneDataMap().get(id); + writer.println(data.getId() + " : " + data.getScriptData()); + } + + writer.println(); + + writer.println("// Quests"); + list = new ArrayList<>(GameData.getQuestDataMap().keySet()); + Collections.sort(list); + + for (Integer id : list) { + QuestData data = GameData.getQuestDataMap().get(id); + MainQuestData mainQuest = GameData.getMainQuestDataMap().get(data.getMainId()); + if (mainQuest != null) { + writer.println(data.getId() + " : " + map.get(mainQuest.getTitleTextMapHash()) + " - " + map.get(data.getDescTextMapHash())); + } + } + + writer.println(); + + writer.println("// Monsters"); + list = new ArrayList<>(GameData.getMonsterDataMap().keySet()); + Collections.sort(list); + + for (Integer id : list) { + MonsterData data = GameData.getMonsterDataMap().get(id); + writer.println(data.getId() + " : " + map.get(data.getNameTextMapHash())); + } + } + + Grasscutter.getLogger().info("GM Handbook generated!"); + } + + @SuppressWarnings("deprecation") + public static void createGachaMapping(String location, String language) throws Exception { + ResourceLoader.loadResources(); + + Map map; + try (InputStreamReader fileReader = new InputStreamReader(new FileInputStream(Utils.toFilePath(RESOURCE("TextMap/TextMap" + language + ".json"))), StandardCharsets.UTF_8)) { + map = Grasscutter.getGsonFactory().fromJson(fileReader, new TypeToken>() {}.getType()); + } + + List list; + + try (PrintWriter writer = new PrintWriter(new OutputStreamWriter(new FileOutputStream(location), StandardCharsets.UTF_8), false)) { + list = new ArrayList<>(GameData.getAvatarDataMap().keySet()); + Collections.sort(list); + + // if the user made choices for language, I assume it's okay to assign his/her selected language to "en-us" + // since it's the fallback language and there will be no difference in the gacha record page. + // The enduser can still modify the `gacha_mappings.js` directly to enable multilingual for the gacha record system. + writer.println("mappings = {\"en-us\": {"); + + // Avatars + boolean first = true; + for (Integer id : list) { + AvatarData data = GameData.getAvatarDataMap().get(id); + int avatarID = data.getId(); + if (avatarID >= 11000000) { // skip test avatar + continue; + } + if (first) { // skip adding comma for the first element + first = false; + } else { + writer.print(","); + } + String color = switch (data.getQualityType()) { + case "QUALITY_PURPLE" -> "purple"; + case "QUALITY_ORANGE" -> "yellow"; + default -> "blue"; + }; + // Got the magic number 4233146695 from manually search in the json file + writer.println( + "\"" + (avatarID % 1000 + 1000) + "\" : [\"" + + map.get(data.getNameTextMapHash()) + "(" + map.get(4233146695L)+ ")\", \"" + + color + "\"]"); + } + + writer.println(); + + list = new ArrayList<>(GameData.getItemDataMap().keySet()); + Collections.sort(list); + + // Weapons + for (Integer id : list) { + ItemData data = GameData.getItemDataMap().get(id); + if (data.getId() <= 11101 || data.getId() >= 20000) { + continue; //skip non weapon items + } + String color; + + switch (data.getRankLevel()) { + case 3: + color = "blue"; + break; + case 4: + color = "purple"; + break; + case 5: + color = "yellow"; + break; + default: + continue; // skip unnecessary entries + } + + // Got the magic number 4231343903 from manually search in the json file + + writer.println(",\"" + data.getId() + + "\" : [\"" + map.get(data.getNameTextMapHash()).replaceAll("\"", "") + + "("+ map.get(4231343903L)+")\",\""+ color + "\"]"); + } + writer.println(",\"200\": \""+map.get(332935371L)+"\", \"301\": \""+ map.get(2272170627L) + "\", \"302\": \""+map.get(2864268523L)+"\""); + writer.println("}\n}"); + } + + Grasscutter.getLogger().info("Mappings generated to " + location + " !"); + } } diff --git a/src/main/java/emu/grasscutter/utils/ByteHelper.java b/src/main/java/emu/grasscutter/utils/ByteHelper.java index 1f9e408b1..9cd12bafe 100644 --- a/src/main/java/emu/grasscutter/utils/ByteHelper.java +++ b/src/main/java/emu/grasscutter/utils/ByteHelper.java @@ -1,24 +1,24 @@ -package emu.grasscutter.utils; - -public class ByteHelper { - public static byte[] changeBytes(byte[] a) { - byte[] b = new byte[a.length]; - for (int i = 0; i < a.length; i++) { - b[i] = a[a.length - i - 1]; - } - return b; - } - - public static byte[] longToBytes(long x) { - byte[] bytes = new byte[8]; - bytes[0] = (byte) (x >> 56); - bytes[1] = (byte) (x >> 48); - bytes[2] = (byte) (x >> 40); - bytes[3] = (byte) (x >> 32); - bytes[4] = (byte) (x >> 24); - bytes[5] = (byte) (x >> 16); - bytes[6] = (byte) (x >> 8); - bytes[7] = (byte) (x); - return bytes; - } -} \ No newline at end of file +package emu.grasscutter.utils; + +public class ByteHelper { + public static byte[] changeBytes(byte[] a) { + byte[] b = new byte[a.length]; + for (int i = 0; i < a.length; i++) { + b[i] = a[a.length - i - 1]; + } + return b; + } + + public static byte[] longToBytes(long x) { + byte[] bytes = new byte[8]; + bytes[0] = (byte) (x >> 56); + bytes[1] = (byte) (x >> 48); + bytes[2] = (byte) (x >> 40); + bytes[3] = (byte) (x >> 32); + bytes[4] = (byte) (x >> 24); + bytes[5] = (byte) (x >> 16); + bytes[6] = (byte) (x >> 8); + bytes[7] = (byte) (x); + return bytes; + } +} diff --git a/src/main/java/emu/grasscutter/utils/Crypto.java b/src/main/java/emu/grasscutter/utils/Crypto.java index c8a264f48..1ed4fd1bf 100644 --- a/src/main/java/emu/grasscutter/utils/Crypto.java +++ b/src/main/java/emu/grasscutter/utils/Crypto.java @@ -10,25 +10,25 @@ import java.security.spec.X509EncodedKeySpec; import emu.grasscutter.Grasscutter; public final class Crypto { - private static final SecureRandom secureRandom = new SecureRandom(); + private static final SecureRandom secureRandom = new SecureRandom(); - public static byte[] DISPATCH_KEY; - public static byte[] DISPATCH_SEED; + public static byte[] DISPATCH_KEY; + public static byte[] DISPATCH_SEED; - public static byte[] ENCRYPT_KEY; - public static long ENCRYPT_SEED = Long.parseUnsignedLong("11468049314633205968"); - public static byte[] ENCRYPT_SEED_BUFFER = new byte[0]; + public static byte[] ENCRYPT_KEY; + public static long ENCRYPT_SEED = Long.parseUnsignedLong("11468049314633205968"); + public static byte[] ENCRYPT_SEED_BUFFER = new byte[0]; public static PublicKey CUR_OS_ENCRYPT_KEY; public static PublicKey CUR_CN_ENCRYPT_KEY; public static PrivateKey CUR_SIGNING_KEY; - public static void loadKeys() { - DISPATCH_KEY = FileUtils.readResource("/keys/dispatchKey.bin"); - DISPATCH_SEED = FileUtils.readResource("/keys/dispatchSeed.bin"); + public static void loadKeys() { + DISPATCH_KEY = FileUtils.readResource("/keys/dispatchKey.bin"); + DISPATCH_SEED = FileUtils.readResource("/keys/dispatchSeed.bin"); - ENCRYPT_KEY = FileUtils.readResource("/keys/secretKey.bin"); - ENCRYPT_SEED_BUFFER = FileUtils.readResource("/keys/secretKeyBuffer.bin"); + ENCRYPT_KEY = FileUtils.readResource("/keys/secretKey.bin"); + ENCRYPT_SEED_BUFFER = FileUtils.readResource("/keys/secretKeyBuffer.bin"); try { //These should be loaded from ChannelConfig_whatever.json @@ -44,21 +44,21 @@ public final class Crypto { catch (Exception e) { Grasscutter.getLogger().error("An error occurred while loading keys.", e); } - } + } - public static void xor(byte[] packet, byte[] key) { - try { - for (int i = 0; i < packet.length; i++) { - packet[i] ^= key[i % key.length]; - } - } catch (Exception e) { - Grasscutter.getLogger().error("Crypto error.", e); - } - } + public static void xor(byte[] packet, byte[] key) { + try { + for (int i = 0; i < packet.length; i++) { + packet[i] ^= key[i % key.length]; + } + } catch (Exception e) { + Grasscutter.getLogger().error("Crypto error.", e); + } + } - public static byte[] createSessionKey(int length) { - byte[] bytes = new byte[length]; - secureRandom.nextBytes(bytes); - return bytes; - } + public static byte[] createSessionKey(int length) { + byte[] bytes = new byte[length]; + secureRandom.nextBytes(bytes); + return bytes; + } } diff --git a/src/main/java/emu/grasscutter/utils/Language.java b/src/main/java/emu/grasscutter/utils/Language.java index da022a25e..627c0f310 100644 --- a/src/main/java/emu/grasscutter/utils/Language.java +++ b/src/main/java/emu/grasscutter/utils/Language.java @@ -15,7 +15,7 @@ import java.util.Map; public final class Language { private static final Map cachedLanguages = new ConcurrentHashMap<>(); - + private final JsonObject languageData; private final String languageCode; private final Map cachedTranslations = new ConcurrentHashMap<>(); @@ -54,7 +54,7 @@ public final class Language { */ public static String translate(String key, Object... args) { String translated = Grasscutter.getLanguage().get(key); - + try { return translated.formatted(args); } catch (Exception exception) { @@ -77,7 +77,7 @@ public final class Language { var langCode = Utils.getLanguageCode(player.getAccount().getLocale()); String translated = Grasscutter.getLanguage(langCode).get(key); - + try { return translated.formatted(args); } catch (Exception exception) { @@ -99,13 +99,13 @@ public final class Language { private Language(LanguageStreamDescription description) { @Nullable JsonObject languageData = null; languageCode = description.getLanguageCode(); - + try { languageData = Grasscutter.getGsonFactory().fromJson(Utils.readFromInputStream(description.getLanguageFile()), JsonObject.class); } catch (Exception exception) { Grasscutter.getLogger().warn("Failed to load language file: " + description.getLanguageCode(), exception); } - + this.languageData = languageData; } @@ -117,7 +117,7 @@ public final class Language { private static LanguageStreamDescription getLanguageFileDescription(String languageCode, String fallbackLanguageCode) { var fileName = languageCode + ".json"; var fallback = fallbackLanguageCode + ".json"; - + String actualLanguageCode = languageCode; InputStream file = Grasscutter.class.getResourceAsStream("/languages/" + fileName); @@ -127,21 +127,21 @@ public final class Language { if (cachedLanguages.containsKey(actualLanguageCode)) { return new LanguageStreamDescription(actualLanguageCode, null); } - + file = Grasscutter.class.getResourceAsStream("/languages/" + fallback); } - if(file == null) { // Fallback the fallback language. + if (file == null) { // Fallback the fallback language. Grasscutter.getLogger().warn("Failed to load language file: " + fallback + ", falling back to: en-US.json"); actualLanguageCode = "en-US"; if (cachedLanguages.containsKey(actualLanguageCode)) { return new LanguageStreamDescription(actualLanguageCode, null); } - + file = Grasscutter.class.getResourceAsStream("/languages/en-US.json"); } - if(file == null) + if (file == null) throw new RuntimeException("Unable to load the primary, fallback, and 'en-US' language files."); return new LanguageStreamDescription(actualLanguageCode, file); @@ -153,10 +153,10 @@ public final class Language { * @return The value (as a string) from a nested key. */ public String get(String key) { - if(this.cachedTranslations.containsKey(key)) { + if (this.cachedTranslations.containsKey(key)) { return this.cachedTranslations.get(key); } - + String[] keys = key.split("\\."); JsonObject object = this.languageData; @@ -166,12 +166,12 @@ public final class Language { boolean isValueFound = false; while (true) { - if(index == keys.length) break; - + if (index == keys.length) break; + String currentKey = keys[index++]; - if(object.has(currentKey)) { + if (object.has(currentKey)) { JsonElement element = object.get(currentKey); - if(element.isJsonObject()) + if (element.isJsonObject()) object = element.getAsJsonObject(); else { isValueFound = true; @@ -186,7 +186,7 @@ public final class Language { result += "\nhere is english version:\n" + englishValue; } } - + this.cachedTranslations.put(key, result); return result; } diff --git a/src/main/java/emu/grasscutter/utils/Utils.java b/src/main/java/emu/grasscutter/utils/Utils.java index c7bdad311..45f6b563a 100644 --- a/src/main/java/emu/grasscutter/utils/Utils.java +++ b/src/main/java/emu/grasscutter/utils/Utils.java @@ -26,387 +26,387 @@ import static emu.grasscutter.utils.Language.translate; @SuppressWarnings({"UnusedReturnValue", "BooleanMethodIsAlwaysInverted"}) public final class Utils { - public static final Random random = new Random(); + public static final Random random = new Random(); - public static int randomRange(int min, int max) { - return random.nextInt(max - min + 1) + min; - } + public static int randomRange(int min, int max) { + return random.nextInt(max - min + 1) + min; + } - public static float randomFloatRange(float min, float max) { - return random.nextFloat() * (max - min) + min; - } + public static float randomFloatRange(float min, float max) { + return random.nextFloat() * (max - min) + min; + } - public static double getDist(Position pos1, Position pos2) { - double xs = pos1.getX() - pos2.getX(); - xs = xs * xs; + public static double getDist(Position pos1, Position pos2) { + double xs = pos1.getX() - pos2.getX(); + xs = xs * xs; - double ys = pos1.getY() - pos2.getY(); - ys = ys * ys; + double ys = pos1.getY() - pos2.getY(); + ys = ys * ys; - double zs = pos1.getZ() - pos2.getZ(); - zs = zs * zs; + double zs = pos1.getZ() - pos2.getZ(); + zs = zs * zs; - return Math.sqrt(xs + zs + ys); - } + return Math.sqrt(xs + zs + ys); + } - public static int getCurrentSeconds() { - return (int) (System.currentTimeMillis() / 1000.0); - } + public static int getCurrentSeconds() { + return (int) (System.currentTimeMillis() / 1000.0); + } - public static String lowerCaseFirstChar(String s) { - StringBuilder sb = new StringBuilder(s); - sb.setCharAt(0, Character.toLowerCase(sb.charAt(0))); - return sb.toString(); - } + public static String lowerCaseFirstChar(String s) { + StringBuilder sb = new StringBuilder(s); + sb.setCharAt(0, Character.toLowerCase(sb.charAt(0))); + return sb.toString(); + } - public static String toString(InputStream inputStream) throws IOException { - BufferedInputStream bis = new BufferedInputStream(inputStream); - ByteArrayOutputStream buf = new ByteArrayOutputStream(); - for (int result = bis.read(); result != -1; result = bis.read()) { - buf.write((byte) result); - } - return buf.toString(); - } + public static String toString(InputStream inputStream) throws IOException { + BufferedInputStream bis = new BufferedInputStream(inputStream); + ByteArrayOutputStream buf = new ByteArrayOutputStream(); + for (int result = bis.read(); result != -1; result = bis.read()) { + buf.write((byte) result); + } + return buf.toString(); + } - public static void logByteArray(byte[] array) { - ByteBuf b = Unpooled.wrappedBuffer(array); - Grasscutter.getLogger().info("\n" + ByteBufUtil.prettyHexDump(b)); - b.release(); - } + public static void logByteArray(byte[] array) { + ByteBuf b = Unpooled.wrappedBuffer(array); + Grasscutter.getLogger().info("\n" + ByteBufUtil.prettyHexDump(b)); + b.release(); + } - private static final char[] HEX_ARRAY = "0123456789abcdef".toCharArray(); - public static String bytesToHex(byte[] bytes) { - if (bytes == null) return ""; - char[] hexChars = new char[bytes.length * 2]; - for (int j = 0; j < bytes.length; j++) { - int v = bytes[j] & 0xFF; - hexChars[j * 2] = HEX_ARRAY[v >>> 4]; - hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F]; - } - return new String(hexChars); - } + private static final char[] HEX_ARRAY = "0123456789abcdef".toCharArray(); + public static String bytesToHex(byte[] bytes) { + if (bytes == null) return ""; + char[] hexChars = new char[bytes.length * 2]; + for (int j = 0; j < bytes.length; j++) { + int v = bytes[j] & 0xFF; + hexChars[j * 2] = HEX_ARRAY[v >>> 4]; + hexChars[j * 2 + 1] = HEX_ARRAY[v & 0x0F]; + } + return new String(hexChars); + } - public static String bytesToHex(ByteBuf buf) { - return bytesToHex(byteBufToArray(buf)); - } + public static String bytesToHex(ByteBuf buf) { + return bytesToHex(byteBufToArray(buf)); + } - public static byte[] byteBufToArray(ByteBuf buf) { - byte[] bytes = new byte[buf.capacity()]; - buf.getBytes(0, bytes); - return bytes; - } + public static byte[] byteBufToArray(ByteBuf buf) { + byte[] bytes = new byte[buf.capacity()]; + buf.getBytes(0, bytes); + return bytes; + } - public static int abilityHash(String str) { - int v7 = 0; - int v8 = 0; - while (v8 < str.length()) { - v7 = str.charAt(v8++) + 131 * v7; - } - return v7; - } + public static int abilityHash(String str) { + int v7 = 0; + int v8 = 0; + while (v8 < str.length()) { + v7 = str.charAt(v8++) + 131 * v7; + } + return v7; + } - /** - * Creates a string with the path to a file. - * @param path The path to the file. - * @return A path using the operating system's file separator. - */ - public static String toFilePath(String path) { - return path.replace("/", File.separator); - } + /** + * Creates a string with the path to a file. + * @param path The path to the file. + * @return A path using the operating system's file separator. + */ + public static String toFilePath(String path) { + return path.replace("/", File.separator); + } - /** - * Checks if a file exists on the file system. - * @param path The path to the file. - * @return True if the file exists, false otherwise. - */ - public static boolean fileExists(String path) { - return new File(path).exists(); - } + /** + * Checks if a file exists on the file system. + * @param path The path to the file. + * @return True if the file exists, false otherwise. + */ + public static boolean fileExists(String path) { + return new File(path).exists(); + } - /** - * Creates a folder on the file system. - * @param path The path to the folder. - * @return True if the folder was created, false otherwise. - */ - public static boolean createFolder(String path) { - return new File(path).mkdirs(); - } + /** + * Creates a folder on the file system. + * @param path The path to the folder. + * @return True if the folder was created, false otherwise. + */ + public static boolean createFolder(String path) { + return new File(path).mkdirs(); + } - /** - * Copies a file from the archive's resources to the file system. - * @param resource The path to the resource. - * @param destination The path to copy the resource to. - * @return True if the file was copied, false otherwise. - */ - public static boolean copyFromResources(String resource, String destination) { - try (InputStream stream = Grasscutter.class.getResourceAsStream(resource)) { - if(stream == null) { - Grasscutter.getLogger().warn("Could not find resource: " + resource); - return false; - } + /** + * Copies a file from the archive's resources to the file system. + * @param resource The path to the resource. + * @param destination The path to copy the resource to. + * @return True if the file was copied, false otherwise. + */ + public static boolean copyFromResources(String resource, String destination) { + try (InputStream stream = Grasscutter.class.getResourceAsStream(resource)) { + if (stream == null) { + Grasscutter.getLogger().warn("Could not find resource: " + resource); + return false; + } - Files.copy(stream, new File(destination).toPath(), StandardCopyOption.REPLACE_EXISTING); - return true; - } catch (Exception exception) { - Grasscutter.getLogger().warn("Unable to copy resource " + resource + " to " + destination, exception); - return false; - } - } + Files.copy(stream, new File(destination).toPath(), StandardCopyOption.REPLACE_EXISTING); + return true; + } catch (Exception exception) { + Grasscutter.getLogger().warn("Unable to copy resource " + resource + " to " + destination, exception); + return false; + } + } - /** - * Logs an object to the console. - * @param object The object to log. - */ - public static void logObject(Object object) { - String asJson = Grasscutter.getGsonFactory().toJson(object); - Grasscutter.getLogger().info(asJson); - } + /** + * Logs an object to the console. + * @param object The object to log. + */ + public static void logObject(Object object) { + String asJson = Grasscutter.getGsonFactory().toJson(object); + Grasscutter.getLogger().info(asJson); + } - /** - * Checks for required files and folders before startup. - */ - public static void startupCheck() { - ConfigContainer config = Grasscutter.getConfig(); - Logger logger = Grasscutter.getLogger(); - boolean exit = false; + /** + * Checks for required files and folders before startup. + */ + public static void startupCheck() { + ConfigContainer config = Grasscutter.getConfig(); + Logger logger = Grasscutter.getLogger(); + boolean exit = false; - String resourcesFolder = config.folderStructure.resources; - String dataFolder = config.folderStructure.data; + String resourcesFolder = config.folderStructure.resources; + String dataFolder = config.folderStructure.data; - // Check for resources folder. - if(!fileExists(resourcesFolder)) { - logger.info(translate("messages.status.create_resources")); - logger.info(translate("messages.status.resources_error")); - createFolder(resourcesFolder); exit = true; - } + // Check for resources folder. + if (!fileExists(resourcesFolder)) { + logger.info(translate("messages.status.create_resources")); + logger.info(translate("messages.status.resources_error")); + createFolder(resourcesFolder); exit = true; + } - // Check for BinOutput + ExcelBinOutput. - if(!fileExists(resourcesFolder + "BinOutput") || - !fileExists(resourcesFolder + "ExcelBinOutput")) { - logger.info(translate("messages.status.resources_error")); - exit = true; - } + // Check for BinOutput + ExcelBinOutput. + if (!fileExists(resourcesFolder + "BinOutput") || + !fileExists(resourcesFolder + "ExcelBinOutput")) { + logger.info(translate("messages.status.resources_error")); + exit = true; + } - // Check for game data. - if(!fileExists(dataFolder)) - createFolder(dataFolder); + // Check for game data. + if (!fileExists(dataFolder)) + createFolder(dataFolder); - // Make sure the data folder is populated, if there are any missing files copy them from resources - DataLoader.checkAllFiles(); + // Make sure the data folder is populated, if there are any missing files copy them from resources + DataLoader.checkAllFiles(); - if(exit) System.exit(1); - } + if (exit) System.exit(1); + } - /** - * Gets the timestamp of the next hour. - * @return The timestamp in UNIX seconds. - */ - public static int getNextTimestampOfThisHour(int hour, String timeZone, int param) { - ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of(timeZone)); - for (int i = 0; i < param; i ++){ - if (zonedDateTime.getHour() < hour) { - zonedDateTime = zonedDateTime.withHour(hour).withMinute(0).withSecond(0); - } else { - zonedDateTime = zonedDateTime.plusDays(1).withHour(hour).withMinute(0).withSecond(0); - } - } - return (int) zonedDateTime.toInstant().atZone(ZoneOffset.UTC).toEpochSecond(); - } + /** + * Gets the timestamp of the next hour. + * @return The timestamp in UNIX seconds. + */ + public static int getNextTimestampOfThisHour(int hour, String timeZone, int param) { + ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of(timeZone)); + for (int i = 0; i < param; i ++) { + if (zonedDateTime.getHour() < hour) { + zonedDateTime = zonedDateTime.withHour(hour).withMinute(0).withSecond(0); + } else { + zonedDateTime = zonedDateTime.plusDays(1).withHour(hour).withMinute(0).withSecond(0); + } + } + return (int) zonedDateTime.toInstant().atZone(ZoneOffset.UTC).toEpochSecond(); + } - /** - * Gets the timestamp of the next hour in a week. - * @return The timestamp in UNIX seconds. - */ - public static int getNextTimestampOfThisHourInNextWeek(int hour, String timeZone, int param) { - ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of(timeZone)); - for (int i = 0; i < param; i++) { - if (zonedDateTime.getDayOfWeek() == DayOfWeek.MONDAY && zonedDateTime.getHour() < hour) { - zonedDateTime = ZonedDateTime.now(ZoneId.of(timeZone)).withHour(hour).withMinute(0).withSecond(0); - } else { - zonedDateTime = zonedDateTime.with(TemporalAdjusters.next(DayOfWeek.MONDAY)).withHour(hour).withMinute(0).withSecond(0); - } - } - return (int) zonedDateTime.toInstant().atZone(ZoneOffset.UTC).toEpochSecond(); - } + /** + * Gets the timestamp of the next hour in a week. + * @return The timestamp in UNIX seconds. + */ + public static int getNextTimestampOfThisHourInNextWeek(int hour, String timeZone, int param) { + ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of(timeZone)); + for (int i = 0; i < param; i++) { + if (zonedDateTime.getDayOfWeek() == DayOfWeek.MONDAY && zonedDateTime.getHour() < hour) { + zonedDateTime = ZonedDateTime.now(ZoneId.of(timeZone)).withHour(hour).withMinute(0).withSecond(0); + } else { + zonedDateTime = zonedDateTime.with(TemporalAdjusters.next(DayOfWeek.MONDAY)).withHour(hour).withMinute(0).withSecond(0); + } + } + return (int) zonedDateTime.toInstant().atZone(ZoneOffset.UTC).toEpochSecond(); + } - /** - * Gets the timestamp of the next hour in a month. - * @return The timestamp in UNIX seconds. - */ - public static int getNextTimestampOfThisHourInNextMonth(int hour, String timeZone, int param) { - ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of(timeZone)); - for (int i = 0; i < param; i++) { - if (zonedDateTime.getDayOfMonth() == 1 && zonedDateTime.getHour() < hour) { - zonedDateTime = ZonedDateTime.now(ZoneId.of(timeZone)).withHour(hour).withMinute(0).withSecond(0); - } else { - zonedDateTime = zonedDateTime.with(TemporalAdjusters.firstDayOfNextMonth()).withHour(hour).withMinute(0).withSecond(0); - } - } - return (int) zonedDateTime.toInstant().atZone(ZoneOffset.UTC).toEpochSecond(); - } + /** + * Gets the timestamp of the next hour in a month. + * @return The timestamp in UNIX seconds. + */ + public static int getNextTimestampOfThisHourInNextMonth(int hour, String timeZone, int param) { + ZonedDateTime zonedDateTime = ZonedDateTime.now(ZoneId.of(timeZone)); + for (int i = 0; i < param; i++) { + if (zonedDateTime.getDayOfMonth() == 1 && zonedDateTime.getHour() < hour) { + zonedDateTime = ZonedDateTime.now(ZoneId.of(timeZone)).withHour(hour).withMinute(0).withSecond(0); + } else { + zonedDateTime = zonedDateTime.with(TemporalAdjusters.firstDayOfNextMonth()).withHour(hour).withMinute(0).withSecond(0); + } + } + return (int) zonedDateTime.toInstant().atZone(ZoneOffset.UTC).toEpochSecond(); + } - /** - * Retrieves a string from an input stream. - * @param stream The input stream. - * @return The string. - */ - public static String readFromInputStream(@Nullable InputStream stream) { - if(stream == null) return "empty"; + /** + * Retrieves a string from an input stream. + * @param stream The input stream. + * @return The string. + */ + public static String readFromInputStream(@Nullable InputStream stream) { + if (stream == null) return "empty"; - StringBuilder stringBuilder = new StringBuilder(); - try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))) { - String line; while ((line = reader.readLine()) != null) { - stringBuilder.append(line); - } stream.close(); - } catch (IOException e) { - Grasscutter.getLogger().warn("Failed to read from input stream."); - } catch (NullPointerException ignored) { - return "empty"; - } return stringBuilder.toString(); - } + StringBuilder stringBuilder = new StringBuilder(); + try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))) { + String line; while ((line = reader.readLine()) != null) { + stringBuilder.append(line); + } stream.close(); + } catch (IOException e) { + Grasscutter.getLogger().warn("Failed to read from input stream."); + } catch (NullPointerException ignored) { + return "empty"; + } return stringBuilder.toString(); + } - /** - * Performs a linear interpolation using a table of fixed points to create an effective piecewise f(x) = y function. - * @param x The x value. - * @param xyArray Array of points in [[x0,y0], ... [xN, yN]] format - * @return f(x) = y - */ - public static int lerp(int x, int[][] xyArray) { - try { - if (x <= xyArray[0][0]){ // Clamp to first point - return xyArray[0][1]; - } else if (x >= xyArray[xyArray.length-1][0]) { // Clamp to last point - return xyArray[xyArray.length-1][1]; - } - // At this point we're guaranteed to have two lerp points, and pity be somewhere between them. - for (int i=0; i < xyArray.length-1; i++) { - if (x == xyArray[i+1][0]) { - return xyArray[i+1][1]; - } - if (x < xyArray[i+1][0]) { - // We are between [i] and [i+1], interpolation time! - // Using floats would be slightly cleaner but we can just as easily use ints if we're careful with order of operations. - int position = x - xyArray[i][0]; - int fullDist = xyArray[i+1][0] - xyArray[i][0]; - int prevValue = xyArray[i][1]; - int fullDelta = xyArray[i+1][1] - prevValue; - return prevValue + ( (position * fullDelta) / fullDist ); - } - } - } catch (IndexOutOfBoundsException e) { - Grasscutter.getLogger().error("Malformed lerp point array. Must be of form [[x0, y0], ..., [xN, yN]]."); - } - return 0; - } + /** + * Performs a linear interpolation using a table of fixed points to create an effective piecewise f(x) = y function. + * @param x The x value. + * @param xyArray Array of points in [[x0,y0], ... [xN, yN]] format + * @return f(x) = y + */ + public static int lerp(int x, int[][] xyArray) { + try { + if (x <= xyArray[0][0]) { // Clamp to first point + return xyArray[0][1]; + } else if (x >= xyArray[xyArray.length-1][0]) { // Clamp to last point + return xyArray[xyArray.length-1][1]; + } + // At this point we're guaranteed to have two lerp points, and pity be somewhere between them. + for (int i=0; i < xyArray.length-1; i++) { + if (x == xyArray[i+1][0]) { + return xyArray[i+1][1]; + } + if (x < xyArray[i+1][0]) { + // We are between [i] and [i+1], interpolation time! + // Using floats would be slightly cleaner but we can just as easily use ints if we're careful with order of operations. + int position = x - xyArray[i][0]; + int fullDist = xyArray[i+1][0] - xyArray[i][0]; + int prevValue = xyArray[i][1]; + int fullDelta = xyArray[i+1][1] - prevValue; + return prevValue + ( (position * fullDelta) / fullDist ); + } + } + } catch (IndexOutOfBoundsException e) { + Grasscutter.getLogger().error("Malformed lerp point array. Must be of form [[x0, y0], ..., [xN, yN]]."); + } + return 0; + } - /** - * Checks if an int is in an int[] - * @param key int to look for - * @param array int[] to look in - * @return key in array - */ - public static boolean intInArray(int key, int[] array) { - for (int i : array) { - if (i == key) { - return true; - } - } - return false; - } + /** + * Checks if an int is in an int[] + * @param key int to look for + * @param array int[] to look in + * @return key in array + */ + public static boolean intInArray(int key, int[] array) { + for (int i : array) { + if (i == key) { + return true; + } + } + return false; + } - /** - * Return a copy of minuend without any elements found in subtrahend. - * @param minuend The array we want elements from - * @param subtrahend The array whose elements we don't want - * @return The array with only the elements we want, in the order that minuend had them - */ - public static int[] setSubtract(int[] minuend, int[] subtrahend) { - IntList temp = new IntArrayList(); - for (int i : minuend) { - if (!intInArray(i, subtrahend)) { - temp.add(i); - } - } - return temp.toIntArray(); - } + /** + * Return a copy of minuend without any elements found in subtrahend. + * @param minuend The array we want elements from + * @param subtrahend The array whose elements we don't want + * @return The array with only the elements we want, in the order that minuend had them + */ + public static int[] setSubtract(int[] minuend, int[] subtrahend) { + IntList temp = new IntArrayList(); + for (int i : minuend) { + if (!intInArray(i, subtrahend)) { + temp.add(i); + } + } + return temp.toIntArray(); + } - /** - * Gets the language code from a given locale. - * @param locale A locale. - * @return A string in the format of 'XX-XX'. - */ - public static String getLanguageCode(Locale locale) { - return String.format("%s-%s", locale.getLanguage(), locale.getCountry()); - } + /** + * Gets the language code from a given locale. + * @param locale A locale. + * @return A string in the format of 'XX-XX'. + */ + public static String getLanguageCode(Locale locale) { + return String.format("%s-%s", locale.getLanguage(), locale.getCountry()); + } - /** - * Base64 encodes a given byte array. - * @param toEncode An array of bytes. - * @return A base64 encoded string. - */ - public static String base64Encode(byte[] toEncode) { - return Base64.getEncoder().encodeToString(toEncode); - } + /** + * Base64 encodes a given byte array. + * @param toEncode An array of bytes. + * @return A base64 encoded string. + */ + public static String base64Encode(byte[] toEncode) { + return Base64.getEncoder().encodeToString(toEncode); + } - /** - * Base64 decodes a given string. - * @param toDecode A base64 encoded string. - * @return An array of bytes. - */ - public static byte[] base64Decode(String toDecode) { - return Base64.getDecoder().decode(toDecode); - } + /** + * Base64 decodes a given string. + * @param toDecode A base64 encoded string. + * @return An array of bytes. + */ + public static byte[] base64Decode(String toDecode) { + return Base64.getDecoder().decode(toDecode); + } - /** - * Safely JSON decodes a given string. - * @param jsonData The JSON-encoded data. - * @return JSON decoded data, or null if an exception occurred. - */ - public static T jsonDecode(String jsonData, Class classType) { - try { - return Grasscutter.getGsonFactory().fromJson(jsonData, classType); - } catch (Exception ignored) { - return null; - } - } + /** + * Safely JSON decodes a given string. + * @param jsonData The JSON-encoded data. + * @return JSON decoded data, or null if an exception occurred. + */ + public static T jsonDecode(String jsonData, Class classType) { + try { + return Grasscutter.getGsonFactory().fromJson(jsonData, classType); + } catch (Exception ignored) { + return null; + } + } - /*** - * Draws a random element from the given list, following the given probability distribution, if given. - * @param list The list from which to draw the element. - * @param probabilities The probability distribution. This is given as a list of probabilities of the same length it `list`. - * @return A randomly drawn element from the given list. - */ - public static T drawRandomListElement(List list, List probabilities) { - // If we don't have a probability distribution, or the size of the distribution does not match - // the size of the list, we assume uniform distribution. - if (probabilities == null || probabilities.size() <= 1 || probabilities.size() != list.size()) { - int index = ThreadLocalRandom.current().nextInt(0, list.size()); - return list.get(index); - } + /*** + * Draws a random element from the given list, following the given probability distribution, if given. + * @param list The list from which to draw the element. + * @param probabilities The probability distribution. This is given as a list of probabilities of the same length it `list`. + * @return A randomly drawn element from the given list. + */ + public static T drawRandomListElement(List list, List probabilities) { + // If we don't have a probability distribution, or the size of the distribution does not match + // the size of the list, we assume uniform distribution. + if (probabilities == null || probabilities.size() <= 1 || probabilities.size() != list.size()) { + int index = ThreadLocalRandom.current().nextInt(0, list.size()); + return list.get(index); + } - // Otherwise, we roll with the given distribution. - int totalProbabilityMass = probabilities.stream().reduce(Integer::sum).get(); - int roll = ThreadLocalRandom.current().nextInt(1, totalProbabilityMass + 1); + // Otherwise, we roll with the given distribution. + int totalProbabilityMass = probabilities.stream().reduce(Integer::sum).get(); + int roll = ThreadLocalRandom.current().nextInt(1, totalProbabilityMass + 1); - int currentTotalChance = 0; - for (int i = 0; i < list.size(); i++) { - currentTotalChance += probabilities.get(i); + int currentTotalChance = 0; + for (int i = 0; i < list.size(); i++) { + currentTotalChance += probabilities.get(i); - if (roll <= currentTotalChance) { - return list.get(i); - } - } + if (roll <= currentTotalChance) { + return list.get(i); + } + } - // Should never happen. - return list.get(0); - } + // Should never happen. + return list.get(0); + } - /*** - * Draws a random element from the given list, following a uniform probability distribution. - * @param list The list from which to draw the element. - * @return A randomly drawn element from the given list. - */ - public static T drawRandomListElement(List list) { - return drawRandomListElement(list, null); - } + /*** + * Draws a random element from the given list, following a uniform probability distribution. + * @param list The list from which to draw the element. + * @return A randomly drawn element from the given list. + */ + public static T drawRandomListElement(List list) { + return drawRandomListElement(list, null); + } } From f87088f4f4dd0fc62ad11f00935c08ba6d24db6b Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 21 Jul 2022 07:21:22 +0000 Subject: [PATCH 41/61] Update languages [skip actions] --- src/main/resources/languages/es-ES.json | 31 +- src/main/resources/languages/fr-FR.json | 804 ++++++++++++------------ src/main/resources/languages/pl-PL.json | 35 +- src/main/resources/languages/ro-RO.json | 33 +- src/main/resources/languages/ru-RU.json | 130 ++-- src/main/resources/languages/zh-CN.json | 11 +- src/main/resources/languages/zh-TW.json | 104 ++- 7 files changed, 541 insertions(+), 607 deletions(-) diff --git a/src/main/resources/languages/es-ES.json b/src/main/resources/languages/es-ES.json index 4e807991c..b4c46e714 100644 --- a/src/main/resources/languages/es-ES.json +++ b/src/main/resources/languages/es-ES.json @@ -28,6 +28,8 @@ "login_token_attempt": "[Dispatch] El cliente %s está intentando iniciar sesión a través de un token.", "login_token_error": "[Dispatch] El cliente %s falló al iniciar sesión a través de un token.", "login_token_success": "[Dispatch] El cliente %s inició sesión a través de un token como %s.", + "login_password_error": "🇺🇸[Dispatch] Client %s failed to log in via password.", + "login_password_storage_error": "🇺🇸[Dispatch] Client %s failed to log in via password because there is no password in the database.", "combo_token_success": "[Dispatch] El cliente %s intercambió el combo token exitosamente.", "combo_token_error": "[Dispatch] El cliente %s falló al intercambiar el combo token.", "account_login_create_success": "[Dispatch] El cliente %s falló al iniciar sesión: Cuenta %s creada.", @@ -37,6 +39,9 @@ "session_key_error": "Clave de sesión incorrecta.", "username_error": "Nombre de usuario no encontrado.", "username_create_error": "Nombre de usuario no encontrado, la creación falló.", + "password_error": "🇺🇸Invalid Password", + "password_length_error": "🇺🇸Password length must be greater then or equal to 8", + "password_storage_error": "🇺🇸You don't have a password for your account. Please contact an administrator.", "server_max_player_limit": "Se ha alcanzado el límite de jugadores activos" }, "router_error": "[Dispatch] No se ha podido vincular el router." @@ -117,6 +122,14 @@ "no_account": "Cuenta no encontrada.", "description": "Modifica las cuentas de usuario" }, + "announce": { + "command_usage": "🇺🇸Usage: announce|a <\"tpl\" templateId|\"refresh\"|\"revoke\" templateId|content>", + "send_success": "🇺🇸Send an announcement successfully, you can revoke it by /a revoke %s.", + "refresh_success": "🇺🇸Refresh announcement config file successfully. [Total %s]", + "revoke_done": "🇺🇸Try to revoke announcement %s.", + "not_found": "🇺🇸Could not found announcement %s.", + "description": "🇺🇸Send announcement to all online players, or manage server's announcement" + }, "clear": { "command_usage": "Uso: clear [lv] [r] [*]", "weapons": "Eliminadas las armas para %s.", @@ -157,8 +170,12 @@ }, "help": { "usage": "Uso: ", - "aliases": "Aliases: ", + "aliases": "🇺🇸Aliases: ", "available_commands": "Comandos disponibles: ", + "tip_need_permission": "🇺🇸Permission: ", + "tip_need_no_permission": "🇺🇸 None", + "tip_permission_targeted": "🇺🇸 (Permission %s is also required to use on other players)", + "warn_player_has_no_permission": "🇺🇸Notice: You do not have permission to run this command.", "description": "Envía el mensaje de ayuda o muestra información sobre un comando específico" }, "kick": { @@ -201,7 +218,7 @@ "description": "Da las coordenadas en el escenario actual" }, "quest": { - "usage": "quest [questID]", + "usage": "🇺🇸quest [questID]", "added": "Misión %s añadida.", "finished": "Misión %s finalizada.", "not_found": "Misión no encontrada.", @@ -360,24 +377,24 @@ }, "documentation": { "handbook": { - "title": "GM Handbook", + "title": "🇺🇸GM Handbook", "title_commands": "Comandos", "title_avatars": "Avatares", "title_items": "Objetos", "title_scenes": "Escenario", "title_monsters": "Monstruos", - "header_id": "Id", + "header_id": "🇺🇸Id", "header_command": "Comando", "header_description": "Descripción", - "header_avatar": "Avatar", + "header_avatar": "🇺🇸Avatar", "header_item": "Objeto", "header_scene": "Escenario", "header_monster": "Monstruo" }, "index": { "title": "Documentación", - "handbook": "GM Handbook", + "handbook": "🇺🇸GM Handbook", "gacha_mapping": "JSON de mapeo del Gacha" } } -} +} \ No newline at end of file diff --git a/src/main/resources/languages/fr-FR.json b/src/main/resources/languages/fr-FR.json index 75cf5133a..36eaf6c9b 100644 --- a/src/main/resources/languages/fr-FR.json +++ b/src/main/resources/languages/fr-FR.json @@ -1,424 +1,400 @@ { - "messages": { - "game": { - "port_bind": "Serveur de jeu démarré sur le port %s", - "connect": "Client connecté depuis %s", - "disconnect": "Client déconnecté depuis %s", - "game_update_error": "Une erreur est survenue lors de la mise à jour du jeu.", - "command_error": "Erreur de commande:" - }, - "dispatch": { - "port_bind": "[Dispatch] Serveur de répartition démarré sur le port %s", - "request": "[Dispatch] Le client %s %s demande : %s", - "keystore": { - "general_error": "[Dispatch] Erreur lors du chargement de keystore!", - "password_error": "[Dispatch] Impossible de charger keystore. Essai avec le mot de passe de keystore par défaut...", - "no_keystore_error": "[Dispatch] Pas de certificat SSL trouvé ! Passage en serveur HTTP", - "default_password": "[Dispatch] Le mot de passe par défaut de keystore a été chargé avec succès. Veuillez envisager de définir le mot de passe à 123456 dans config.json." - }, - "authentication": { - "default_unable_to_verify": "[Authentication] Quelque chose à appeler la méthode verifyUser qui n'est pas supportée par le gestionnaire d'authentification par défaut." - }, - "no_commands_error": "Les commandes ne sont pas prises en charge par le mode répartition seulement.", - "unhandled_request_error": "[Dispatch] Requête potentiellement non-gérée %s : %s.", - "account": { - "login_attempt": "[Dispatch] Le client %s essaye de de connecter.", - "login_success": "[Dispatch] Le client %s est connecté en tant que %s.", - "login_max_player_limit": "[Dispatch] Le client %s n'a pas réussi à se connecter : Le nombre de joueurs maximum est atteint.", - "login_token_attempt": "[Dispatch] Le client %s essaye de se connecter via un jeton.", - "login_token_error": "[Dispatch] Le client %s n'a pas réussi à se connecter via un jeton.", - "login_token_success": "[Dispatch] Le client %s est connecté via un jeton en tant que %s.", - "combo_token_success": "[Dispatch] Le client %s a réussi à échanger le jeton combiné.", - "combo_token_error": "[Dispatch] Le client %s n'a pas réussi à échanger le jeton combiné.", - "account_login_create_success": "[Dispatch] Le client %s n'a pas réussi à se connecter : Le compte %s a été créé.", - "account_login_create_error": "[Dispatch] Le client %s n'a pas réussi à se connecter : La création du compte a échoué.", - "account_login_exist_error": "[Dispatch] Le client %s n'a pas réussi à de connecter : Compte non trouvé.", - "account_cache_error": "Erreur d'information sur le cache de compte du jeu.", - "session_key_error": "Mauvaise clé de session.", - "username_error": "Nom d'utilisateur introuvable.", - "username_create_error": "Nom d'utilisateur introuvable, création échouée.", - "server_max_player_limit": "Le nombre de joueurs maximum est atteint." - }, - "router_error": "[Dispatch] Impossible d'attacher le routeur." - }, - "status": { - "free_software": "Grasscutter est un logiciel GRATUIT. Si vous avez payé pour ce logiciel, vous avez peut-être été arnaqué. Page d'accueil : https://github.com/Grasscutters/Grasscutter", - "starting": "Démarrage de Grasscutter...", - "shutdown": "Arrêt en cours...", - "done": "Terminé ! Pour obtenir de l'aide, écrire \"help\"", - "error": "Une erreur est survenue.", - "welcome": "Bienvenue sur Grasscutter !", - "run_mode_error": "Mode d'exécution du serveur invalide: %s.", - "run_mode_help": "Le mode d'exécution du serveur doit être : 'HYBRID', 'DISPATCH_ONLY', or 'GAME_ONLY'. Impossible de démarrer Grasscutter...", - "create_resources": "Création du dossier ressources...", - "resources_error": "Placez une copie de 'BinOutput' and 'ExcelBinOutput' dans le dossier ressources.", - "version": "Version de Grasscutter: %s-%s", - "game_version": "Version du jeu: %s", - "resources": { - "loading": "Loading resources...", - "finish": "Finished loading resources." - } - } + "messages": { + "game": { + "port_bind": "Serveur de jeu démarré sur le port %s", + "connect": "Client connecté depuis %s", + "disconnect": "Client déconnecté depuis %s", + "game_update_error": "Une erreur est survenue lors de la mise à jour du jeu.", + "command_error": "Erreur de commande:" }, - "commands": { - "generic": { - "not_specified": "Aucune commande spécifiée.", - "unknown_command": "Commande inconnue: %s", - "permission_error": "Vous n'avez pas la permission d'exécuter cette commande.", - "console_execute_error": "Cette commande ne peut être exécutée uniquement dans la console.", - "player_execute_error": "Exécutez cette commande dans le jeu.", - "command_exist_error": "Aucune commande trouvée.", - "no_usage_specified": "Pas de description de l'utilisation spécifiée.", - "no_description_specified": "Pas de description spécifiée", - "set_to": "%s a été défini a %s.", - "set_for_to": "%s de %s a été défini a %s.", - "invalid": { - "amount": "Montant invalide.", - "artifactId": "ID de l'artéfact invalide.", - "avatarId": "ID de l'avatar invalide.", - "avatarLevel": "avatarLevel invalide.", - "entityId": "ID de l'entité invalide.", - "itemId": "ID de l'objet invalide.", - "itemLevel": "Niveau de l'objet invalide.", - "itemRefinement": "Raffinement de l'objet invalide.", - "statValue": "Valeur de invalide.", - "value_between": "Invalid value: %s must be between %s and %s.", - "playerId": "ID du joueur invalide.", - "uid": "UID invalide.", - "id": "ID invalide." - } + "dispatch": { + "port_bind": "[Dispatch] Serveur de répartition démarré sur le port %s", + "request": "[Dispatch] Le client %s %s demande : %s", + "keystore": { + "general_error": "[Dispatch] Erreur lors du chargement de keystore!", + "password_error": "[Dispatch] Impossible de charger keystore. Essai avec le mot de passe de keystore par défaut...", + "no_keystore_error": "[Dispatch] Pas de certificat SSL trouvé ! Passage en serveur HTTP", + "default_password": "[Dispatch] Le mot de passe par défaut de keystore a été chargé avec succès. Veuillez envisager de définir le mot de passe à 123456 dans config.json." }, - "execution": { - "player_exist_error": "Joueur introuvable.", - "player_offline_error": "Le joueur n'est pas connecté.", - "item_player_exist_error": "UID ou objet invalide.", - "player_exist_offline_error": "Le joueur est introuvable ou n'est pas connecté.", - "argument_error": "Arguments invalides.", - "clear_target": "Cible réinitialisée.", - "set_target": "Les prochaines commandes cibleront @%s par défaut.", - "set_target_online": "@%s est connecté. Certaines commandes peuvent nécessiter une cible hors ligne.", - "set_target_offline": "@%s est hors ligne. Certaines commandes peuvent nécessiter une cible conectée.", - "need_target": "Cette commande nécessite un UID cible. Ajoutez un argument <@UID> ou définisez une cible persistante avec /target @UID.", - "need_target_online": "Cette commande nécessite un UID cible en ligne, mais la cible actuelle est hors ligne. Ajoutez un argument <@UID> différent ou définissez une cible persistante avec /target @UID.", - "need_target_offline": "Cette commande nécessite un UID cible hors ligne, mais la cible actuelle est en ligne. Ajoutez un argument <@UID> différent ou définissez une cible persistante avec /target @UID." - }, - "status": { - "enabled": "Activé", - "disabled": "Desactivé", - "help": "Aide", - "success": "Succès" + "authentication": { + "default_unable_to_verify": "[Authentication] Quelque chose à appeler la méthode verifyUser qui n'est pas supportée par le gestionnaire d'authentification par défaut." }, + "no_commands_error": "Les commandes ne sont pas prises en charge par le mode répartition seulement.", + "unhandled_request_error": "[Dispatch] Requête potentiellement non-gérée %s : %s.", "account": { - "modify": "Modifie les comptes utilisateurs", - "invalid": "UID invalide.", - "exists": "Un compte avec ce nom d'utilisateur et/ou UID existe déjà.", - "create": "Compte créé avec l'UID %s.", - "delete": "Compte supprimé.", - "no_account": "Compte introuvable.", - "command_usage": "Utilisation: account [UID]", - "description": "Modifie les comptes utilisateurs" + "login_attempt": "[Dispatch] Le client %s essaye de de connecter.", + "login_success": "[Dispatch] Le client %s est connecté en tant que %s.", + "login_max_player_limit": "[Dispatch] Le client %s n'a pas réussi à se connecter : Le nombre de joueurs maximum est atteint.", + "login_token_attempt": "[Dispatch] Le client %s essaye de se connecter via un jeton.", + "login_token_error": "[Dispatch] Le client %s n'a pas réussi à se connecter via un jeton.", + "login_token_success": "[Dispatch] Le client %s est connecté via un jeton en tant que %s.", + "login_password_error": "🇺🇸[Dispatch] Client %s failed to log in via password.", + "login_password_storage_error": "🇺🇸[Dispatch] Client %s failed to log in via password because there is no password in the database.", + "combo_token_success": "[Dispatch] Le client %s a réussi à échanger le jeton combiné.", + "combo_token_error": "[Dispatch] Le client %s n'a pas réussi à échanger le jeton combiné.", + "account_login_create_success": "[Dispatch] Le client %s n'a pas réussi à se connecter : Le compte %s a été créé.", + "account_login_create_error": "[Dispatch] Le client %s n'a pas réussi à se connecter : La création du compte a échoué.", + "account_login_exist_error": "[Dispatch] Le client %s n'a pas réussi à de connecter : Compte non trouvé.", + "account_cache_error": "Erreur d'information sur le cache de compte du jeu.", + "session_key_error": "Mauvaise clé de session.", + "username_error": "Nom d'utilisateur introuvable.", + "username_create_error": "Nom d'utilisateur introuvable, création échouée.", + "password_error": "🇺🇸Invalid Password", + "password_length_error": "🇺🇸Password length must be greater then or equal to 8", + "password_storage_error": "🇺🇸You don't have a password for your account. Please contact an administrator.", + "server_max_player_limit": "Le nombre de joueurs maximum est atteint." }, - "clear": { - "command_usage": "Usage: clear [lv] [r] [*]", - "weapons": "Les armes de %s ont été supprimés.", - "artifacts": "Les artéfacts de %s ont été supprimés.", - "materials": "Les matériaux de %s ont été supprimés.", - "furniture": "Les décoration de %s ont été supprimés.", - "displays": "Les display de %s ont été supprimés.", - "virtuals": "Les virtuals de %s ont été supprimés.", - "everything": "Tous les objets de %s ont été supprimés.", - "description": "Supprime les objets débloqués et non équipés, y compris ceux de rareté 5* de votre inventaire" - }, - "coop": { - "usage": "Usage: coop [UID de l'hôte]", - "success": "%s est apparu dans de monde de %s.", - "description": "Force quelqu'un a rejoindre le monde d'un autre. Si personne n'est ciblé, vous envoie quand même en mode multijoueur." - }, - "enter_dungeon": { - "usage": "Usage: enterdungeon ", - "changed": "Entré dans le donjon %s.", - "not_found_error": "Le donjon n'existe pas.", - "in_dungeon_error": "Vous êtes déjà dans ce donjon.", - "description": "Entrer dans un donjon" - }, - "giveAll": { - "usage": "Usage: giveall [joueur] [quantité]", - "started": "Obtention de tous les objets en cours...", - "success": "Tous les objets ont été donnés à %s.", - "invalid_amount_or_playerId": "Quantité ou joueur cible invalide.", - "description": "Donne tous les objets." - }, - "giveArtifact": { - "usage": "Usage: giveart|gart [joueur] [[,]]... [niveau]", - "id_error": "ID de l'artéfact invalide.", - "success": "%s a été donné à %s.", - "description": "Donne au joueur l'artéfact spécifié." - }, - "give": { - "usage": "Usage: give [quantité] [niveau] [raffinement]", - "refinement_only_applicable_weapons": "Le raffinement est uniquement applicable aux armes.", - "refinement_must_between_1_and_5": "Le raffinement doit être compris entre 1 et 5.", - "given": "Given %s of %s to %s.", - "given_with_level_and_refinement": "%s avec le niveau %s, raffinement %s %s fois à %s.", - "given_level": "%s avec le niveau %s %s fois à %s.", - "given_avatar": "%s avec le niveau %s a été donné à %s.", - "description": "Donne un objet au joueur spécifié" - }, - "godmode": { - "success": "Le godmode est maintenant %s pour %s.", - "description": "Vous empêche de prendre des dégâts. Désactivé par défaut." - }, - "heal": { - "success": "Tous les personnages ont été soignés.", - "description": "Soigne tous les personnages de votre équipe" - }, - "help": { - "usage": "Utilisation: ", - "aliases": "Alias: ", - "available_commands": "Commandes disponibles: ", - "description": "Envoie le message d'aide ou montre les informations à propos d'une commande spécifiée", - "tip_need_permission": "Permission: ", - "tip_need_no_permission": " Aucune", - "tip_permission_targeted": " (La permission %s est également requise pour utiliser sur d'autres joueurs)", - "warn_player_has_no_permission": "Information: Vous n'avez pas la permission d'utiliser cette commande." - }, - "kick": { - "player_kick_player": "Le joueur [%s:%s] a éjecté le joueur [%s:%s]", - "server_kick_player": "Ejection du joueur [%s:%s]...", - "description": "Ejecte le joueur spécifié du serveur (WIP)" - }, - "killall": { - "usage": "Usage: killall [playerUID] [sceneID]", - "scene_not_found_in_player_world": "Scène introuvable dans le monde du joueur.", - "kill_monsters_in_scene": "Exécution de %s monstres dans la scène %s...", - "description": "Tue toutes les entités" - }, - "killCharacter": { - "usage": "Usage: killcharacter [playerID]", - "success": " Le personnage actuel de %s a été tué.", - "description": "Tue le personnage actuel du joueur spécifié" - }, - "language": { - "current_language": "La langue actuelle est %s.", - "language_changed": "La langue a été changé à %s.", - "language_not_found": "Actuellement, cette langue n'est pas supportée par le serveur.", - "description": "Affiche ou change la langue du serveur" - }, - "list": { - "success": "Il y a %s joueur(s) connectés:", - "description": "Liste tous les joueurs connectés" - }, - "nostamina": { - "success": "NoStamina est maintement %s pour %s.", - "description": "Garde votre endurance au maximum." - }, - "permission": { - "usage": "Usage: permission ", - "add": "Permission ajoutée.", - "has_error": "Cet utilisateur possède déjà cette permission!", - "remove": "Permission retirée.", - "not_have_error": "Cet utilisateur n'a pas cette permission!", - "account_error": "Le compte est introuvable.", - "description": "Accorde ou retire une permission a un utilisateur" - }, - "position": { - "success": "Coordonées: %s, %s, %s\nID de la scène: %s", - "description": "Obtenir vos coordonnées" - }, - "quest": { - "usage": "quest [questID]", - "added": "Quête %s ajoutée.", - "finished": "Quête terminée : %s.", - "not_found": "Quête introuvable.", - "invalid_id": "ID de la quête invalide.", - "description": "Ajoute ou termine une quête" - }, - "reload": { - "reload_start": "Rechargement de la configuration.", - "reload_done": "Rechargement terminé.", - "description": "Recharge la configuration du serveur" - }, - "resetConst": { - "reset_all": "Les constellations de tous les avatars ont été réinitialisés.", - "success": "Les constellations de %s ont été réinitialisés. Veuillez-vous reconnecter pour voir les modifications.", - "description": "Réinitialise les constellations d'un avatar. Vous devez vous reconnecter pour voir les modifications." - }, - "resetShopLimit": { - "usage": "Usage: resetshop ", - "success": "Réinitialisation terminée.", - "description": "Réinitialise le temps d'actualisation de la boutique du joueur spécifié" - }, - "sendMail": { - "usage": "Usage: sendmail [templateID]", - "user_not_exist": "L'utilisateur avec l'identifiant '%s' n'existe pas.", - "start_composition": "Démarrage de la composition du message.\nVeuillez utiliser'/sendmail ' pour continuer.\nVous pouvez utiliser '/sendmail stop' à tout moment.", - "templates": "Les modèles de lettres ne sont pas encore disponibles.", - "invalid_arguments": "Arguments invalides.", - "send_cancel": "L'envoi du message a été annulé.", - "send_done": "Le message a été envoyé à %s!", - "send_all_done": "Message envoyé à tous les utilisateurs!", - "not_composition_end": "La composition du message n'est pas au stade final.\nVeuillez utiliser '/sendmail %s' or '/sendmail stop' pour annuler", - "please_use": "Veuillez utiliser '/sendmail %s'", - "set_title": "Le titre du message a été défini à '%s'.\nUtilisez '/sendmail ' pour continuer.", - "set_contents": "Le contenu du message a été défini à '%s'.\nUtilisez '/sendmail ' pour continuer.", - "set_message_sender": "L'expéditeur a été défini à '%s'.\nUtilisez '/sendmail [quantité] [niveau]' pour continuer.", - "send": "%s %s (niveau %s) ont été ajouté au message.\nContinuez d'ajouter plus d'objets ou utilisez '/sendmail finish' pour envoyer le message.", - "invalid_arguments_please_use": "Arguments invalides.\n Veuillez utiliser '/sendmail %s'", - "title": "", - "message": "", - "sender": "", - "arguments": " [quantité] [niveau]", - "error": "ERREUR: Stade de construction invalide : %s. Vérifiez la console pour la pile d'appels.", - "description": "Envoie un courrier à l'utilisateur spécifié. L'utilisation de la commande change en fonction du stade de la composition du message." - }, - "sendMessage": { - "usage": "Usage: sendmessage ", - "success": "Message envoyé.", - "description": "Envoie un message au joueur spécifié en tant que Serveur" - }, - "setFetterLevel": { - "usage": "Usage: setfetterlevel ", - "range_error": "Le niveau d'affinité doit être compris entre 0 et 10.", - "success": "Niveau d'affinité défini à %s.", - "level_error": "Niveau d'affinité invalide.", - "description": "Défini le niveau d'affinité de votre personnage actif" - }, - "setProp": { - "usage": "Usage: setprop|prop \n\tValues for : godmode | nostamina | unlimitedenergy | abyss | worldlevel | bplevel\n\t(cont.) see PlayerProperty enum for other possible values, of form PROP_MAX_SPRING_VOLUME -> max_spring_volume", - "description": "Définit des propriétes pour votre compte. Des choses comme le godemode peuvent être activés avec cette commande, et le déblocage de l'abysse ainsi que l'avancement du PB." - }, - "setStats": { - "usage": "Usage: setstats|stats \n\tValeurs pour : hp | maxhp | def | atk | em | er | crate | cdmg | cdr | heal | heali | shield | defi\n\t(cont.) Bonus de dégât élémentaire: epyro | ecryo | ehydro | egeo | edendro | eelectro | ephys\n\t(cont.) Résistance élémentaire: respyro | rescryo | reshydro | resgeo | resdendro | reselectro | resphys\n", - "description": "Définit les propriétés de combat de votre personnage actif" - }, - "setWorldLevel": { - "usage": "Usage: setworldlevel ", - "value_error": "Le niveau de monde doit être compris entre 0 et 8.", - "success": "Niveau de monde défini à %s.", - "invalid_world_level": "Niveau de monde invalide.", - "description": "Définit le niveau de monde (Reconnectez-vous pour voir les effets)" - }, - "spawn": { - "usage": "Usage: spawn [quantité] [niveau(monstre uniquement)] [ (monstre uniquement, optionnel)]", - "success": " %s %s sont apparu.", - "limit_reached": "La limite d'apparition de la scène est atteinte. Apparition de %s entités à la place.", - "description": "Fait apparaitre une entité à proximité" - }, - "stop": { - "success": "Arrêt du serveur...", - "description": "Arrête le serveur" - }, - "talent": { - "usage_1": "Pour définir le niveau du talent: /talent set ", - "usage_2": "Une autre façon de définir le niveau d'un talent: /talent ", - "usage_3": "Pour obtenir l'ID d'un talent: /talent getid", - "lower_16": "Niveau de talent invalide. Le niveau doit être inférieur a 16.", - "set_id": "Talent défini à %s.", - "set_atk": "Le talent ATK normale a été défini à %s.", - "set_e": "Le talent E a été défini a %s.", - "set_q": "Le talent A/Q a été défini à %s.", - "invalid_skill_id": "ID de talent invalide.", - "set_this": "Ce talent a été défini a %s.", - "invalid_level": "Niveau de talent invalide.", - "normal_attack_id": "ID de l'attaque normale ID %s.", - "e_skill_id": "ID du E %s.", - "q_skill_id": "ID du A/Q %s.", - "description": "Définit le niveau du talent du personnage actif" - }, - "team": { - "usage": "Usage: team [avatarID,...] [index|first|last|index-index,...]", - "invalid_usage": "Utilisation invalide.", - "add_usage": "Utilisation (add): team add [index]", - "invalid_index": "Index invalide.", - "add_too_much": "Ce serveur autorise à avoir au maximum %d avatar(s) dans votre équipe.", - "failed_to_add_avatar": "Echec de l'ajout de l'avatar a l'ID %s dans votre équipe.", - "remove_usage": "Utilisation (remove): team remove ", - "failed_to_parse_index": "Echec de l'analyse de l'index index: %s", - "remove_too_much": "Vous ne pouvez pas retirer tous les avatars.", - "ignore_index": "Index(s) ignorés : %s", - "set_usage": "Utilisation : (set): team set ", - "index_out_of_range": "L'index spécifié est en dehors du champ.", - "failed_parse_avatar_id": "Echec de l'analyse de l'ID de l'avatar: %s", - "avatar_already_in_team": "L'avatar est déjà dans votre équipe.", - "avatar_not_found": "L'avatar %d est introuvable.", - "description": "Modifie votre équipe manuellement." - }, - "teleportAll": { - "success": "Tous les joueurs ont été téléportés sur votre position.", - "error": "Vous ne pouvez utiliser cette commande qu'en mode multijoueur.", - "description": "Téléporte tous les joueurs de votre monde sur votre position" - }, - "teleport": { - "usage_server": "Utilisation: tp @ [sceneID]", - "usage": "Utilisation: tp [@] [sceneID]", - "specify_player_id": "Vous devez spécifier un ID d'utilisateur.", - "invalid_position": "Position invalide.", - "exists_error": "La scène spécifié n'existe pas.", - "success": "%s a été téléporté à %s, %s, %s dans la scène %s.", - "description": "Change la position du joueur" - }, - "unlimitenergy": { - "success": "UnlimitEnergy est maintenant %s pour %s.", - "config_error": "La commande est désactivée, car energyUsage est false dans config.json.", - "description": "Utiliser le déchainement élémentaire ne consomme pas d'énergie" - }, - "unlocktower": { - "success": "Tous les couloirs de l'abysse sont maintenant débloqués.", - "description": "Débloque tous les couloirs de l'abysse" - }, - "weather": { - "description": "Change la météo. Les ID de la météo peuvent être trouvés dans WeatherExcelConfigData.json.\nTypes de climatss: sunny, cloudy, rain, thunderstorm, snow, mist.", - "usage": "Utilisation: weather [weatherId] [climateType]\nLes ID de la météo peuvent être trouvés dans WeatherExcelConfigData.json.\nClimate types: sunny, cloudy, rain, thunderstorm, snow, mist.", - "success": "L'ID de la météo à été défini a %s avec le type de climat %s.", - "status": "L'ID de la météo accutel est %s avec le type de climat %s." - }, - "ban": { - "description": "Bannis un joueur", - "success": "Succès.", - "failure": "Échec, joueur introuvable.", - "invalid_time": "Impossible d'analyser le timestamp.", - "command_usage": "Usage: ban <@playerId> [timestamp] [raison]" - }, - "unban": { - "description": "Retire le bannissement d'un joueur", - "success": "Succès.", - "failure": "Échec, joueur introuvable.", - "command_usage": "Usage: unban <@playerId>" - } + "router_error": "[Dispatch] Impossible d'attacher le routeur." }, - "gacha": { - "details": { - "title": "Détails de la bannière", - "available_five_stars": "Objets 5 étoiles disponibles", - "available_four_stars": "Objets 4 étoiles disponibles", - "available_three_stars": "Objets 3 étoiles disponibles" - }, - "records": { - "title": "Gacha Records", - "date": "Date", - "item": "Objet" - } - }, - "documentation": { - "handbook": { - "title": "Manuel GM", - "title_commands": "Commandes", - "title_avatars": "Avatars", - "title_items": "Objets", - "title_scenes": "Scènes", - "title_monsters": "Monstres", - "header_id": "Id", - "header_command": "Commande", - "header_description": "Description", - "header_avatar": "Avatar", - "header_item": "Objet", - "header_scene": "Scène", - "header_monster": "Monstre" - }, - "index": { - "title": "Documentation", - "handbook": "Manuel GM", - "gacha_mapping": "Gacha mapping JSON" + "status": { + "free_software": "Grasscutter est un logiciel GRATUIT. Si vous avez payé pour ce logiciel, vous avez peut-être été arnaqué. Page d'accueil : https://github.com/Grasscutters/Grasscutter", + "starting": "Démarrage de Grasscutter...", + "shutdown": "Arrêt en cours...", + "done": "Terminé ! Pour obtenir de l'aide, écrire \"help\"", + "error": "Une erreur est survenue.", + "welcome": "Bienvenue sur Grasscutter !", + "run_mode_error": "Mode d'exécution du serveur invalide: %s.", + "run_mode_help": "Le mode d'exécution du serveur doit être : 'HYBRID', 'DISPATCH_ONLY', or 'GAME_ONLY'. Impossible de démarrer Grasscutter...", + "create_resources": "Création du dossier ressources...", + "resources_error": "Placez une copie de 'BinOutput' and 'ExcelBinOutput' dans le dossier ressources.", + "version": "Version de Grasscutter: %s-%s", + "game_version": "Version du jeu: %s", + "resources": { + "loading": "🇺🇸Loading resources...", + "finish": "🇺🇸Finished loading resources." } } + }, + "commands": { + "generic": { + "not_specified": "Aucune commande spécifiée.", + "unknown_command": "Commande inconnue: %s", + "permission_error": "Vous n'avez pas la permission d'exécuter cette commande.", + "console_execute_error": "Cette commande ne peut être exécutée uniquement dans la console.", + "player_execute_error": "Exécutez cette commande dans le jeu.", + "command_exist_error": "Aucune commande trouvée.", + "no_usage_specified": "Pas de description de l'utilisation spécifiée.", + "no_description_specified": "Pas de description spécifiée", + "set_to": "%s a été défini a %s.", + "set_for_to": "%s de %s a été défini a %s.", + "invalid": { + "amount": "Montant invalide.", + "artifactId": "ID de l'artéfact invalide.", + "avatarId": "ID de l'avatar invalide.", + "avatarLevel": "avatarLevel invalide.", + "entityId": "ID de l'entité invalide.", + "itemId": "ID de l'objet invalide.", + "itemLevel": "Niveau de l'objet invalide.", + "itemRefinement": "Raffinement de l'objet invalide.", + "statValue": "Valeur de invalide.", + "value_between": "🇺🇸Invalid value: %s must be between %s and %s.", + "playerId": "ID du joueur invalide.", + "uid": "UID invalide.", + "id": "ID invalide." + } + }, + "execution": { + "player_exist_error": "Joueur introuvable.", + "player_offline_error": "Le joueur n'est pas connecté.", + "item_player_exist_error": "UID ou objet invalide.", + "player_exist_offline_error": "Le joueur est introuvable ou n'est pas connecté.", + "argument_error": "Arguments invalides.", + "clear_target": "Cible réinitialisée.", + "set_target": "Les prochaines commandes cibleront @%s par défaut.", + "set_target_online": "@%s est connecté. Certaines commandes peuvent nécessiter une cible hors ligne.", + "set_target_offline": "@%s est hors ligne. Certaines commandes peuvent nécessiter une cible conectée.", + "need_target": "Cette commande nécessite un UID cible. Ajoutez un argument <@UID> ou définisez une cible persistante avec /target @UID.", + "need_target_online": "Cette commande nécessite un UID cible en ligne, mais la cible actuelle est hors ligne. Ajoutez un argument <@UID> différent ou définissez une cible persistante avec /target @UID.", + "need_target_offline": "Cette commande nécessite un UID cible hors ligne, mais la cible actuelle est en ligne. Ajoutez un argument <@UID> différent ou définissez une cible persistante avec /target @UID." + }, + "status": { + "enabled": "Activé", + "disabled": "Desactivé", + "help": "Aide", + "success": "Succès" + }, + "account": { + "command_usage": "Utilisation: account [UID]", + "invalid": "UID invalide.", + "exists": "Un compte avec ce nom d'utilisateur et/ou UID existe déjà.", + "create": "Compte créé avec l'UID %s.", + "delete": "Compte supprimé.", + "no_account": "Compte introuvable.", + "description": "Modifie les comptes utilisateurs" + }, + "announce": { + "command_usage": "🇺🇸Usage: announce|a <\"tpl\" templateId|\"refresh\"|\"revoke\" templateId|content>", + "send_success": "🇺🇸Send an announcement successfully, you can revoke it by /a revoke %s.", + "refresh_success": "🇺🇸Refresh announcement config file successfully. [Total %s]", + "revoke_done": "🇺🇸Try to revoke announcement %s.", + "not_found": "🇺🇸Could not found announcement %s.", + "description": "🇺🇸Send announcement to all online players, or manage server's announcement" + }, + "clear": { + "command_usage": "🇺🇸Usage: clear [lv] [r] [*]", + "weapons": "Les armes de %s ont été supprimés.", + "artifacts": "Les artéfacts de %s ont été supprimés.", + "materials": "Les matériaux de %s ont été supprimés.", + "furniture": "Les décoration de %s ont été supprimés.", + "displays": "Les display de %s ont été supprimés.", + "virtuals": "Les virtuals de %s ont été supprimés.", + "everything": "Tous les objets de %s ont été supprimés.", + "description": "Supprime les objets débloqués et non équipés, y compris ceux de rareté 5* de votre inventaire" + }, + "coop": { + "usage": "Usage: coop [UID de l'hôte]", + "success": "%s est apparu dans de monde de %s.", + "description": "Force quelqu'un a rejoindre le monde d'un autre. Si personne n'est ciblé, vous envoie quand même en mode multijoueur." + }, + "enter_dungeon": { + "usage": "🇺🇸Usage: enterdungeon ", + "changed": "Entré dans le donjon %s.", + "not_found_error": "Le donjon n'existe pas.", + "in_dungeon_error": "Vous êtes déjà dans ce donjon.", + "description": "Entrer dans un donjon" + }, + "give": { + "usage": "Usage: give [quantité] [niveau] [raffinement]", + "usage_relic": "🇺🇸Usage: give [mainPropID] [[,]]... [lv]", + "illegal_relic": "🇺🇸This artifactID belongs to a blacklisted range, it may not be the one you wanted.", + "given": "🇺🇸Given %s of %s to %s.", + "given_with_level_and_refinement": "%s avec le niveau %s, raffinement %s %s fois à %s.", + "given_level": "%s avec le niveau %s %s fois à %s.", + "given_avatar": "%s avec le niveau %s a été donné à %s.", + "giveall_success": "🇺🇸Successfully gave all items.", + "description": "Donne un objet au joueur spécifié" + }, + "heal": { + "success": "Tous les personnages ont été soignés.", + "description": "Soigne tous les personnages de votre équipe" + }, + "help": { + "usage": "Utilisation: ", + "aliases": "Alias: ", + "available_commands": "Commandes disponibles: ", + "tip_need_permission": "🇺🇸Permission: ", + "tip_need_no_permission": " Aucune", + "tip_permission_targeted": " (La permission %s est également requise pour utiliser sur d'autres joueurs)", + "warn_player_has_no_permission": "Information: Vous n'avez pas la permission d'utiliser cette commande.", + "description": "Envoie le message d'aide ou montre les informations à propos d'une commande spécifiée" + }, + "kick": { + "player_kick_player": "Le joueur [%s:%s] a éjecté le joueur [%s:%s]", + "server_kick_player": "Ejection du joueur [%s:%s]...", + "description": "Ejecte le joueur spécifié du serveur (WIP)" + }, + "killall": { + "usage": "🇺🇸Usage: killall [playerUID] [sceneID]", + "scene_not_found_in_player_world": "Scène introuvable dans le monde du joueur.", + "kill_monsters_in_scene": "Exécution de %s monstres dans la scène %s...", + "description": "Tue toutes les entités" + }, + "killCharacter": { + "usage": "🇺🇸Usage: killcharacter [playerID]", + "success": " Le personnage actuel de %s a été tué.", + "description": "Tue le personnage actuel du joueur spécifié" + }, + "language": { + "current_language": "La langue actuelle est %s.", + "language_changed": "La langue a été changé à %s.", + "language_not_found": "Actuellement, cette langue n'est pas supportée par le serveur.", + "description": "Affiche ou change la langue du serveur" + }, + "list": { + "success": "Il y a %s joueur(s) connectés:", + "description": "Liste tous les joueurs connectés" + }, + "permission": { + "usage": "🇺🇸Usage: permission ", + "add": "Permission ajoutée.", + "has_error": "Cet utilisateur possède déjà cette permission!", + "remove": "Permission retirée.", + "not_have_error": "Cet utilisateur n'a pas cette permission!", + "account_error": "Le compte est introuvable.", + "description": "Accorde ou retire une permission a un utilisateur" + }, + "position": { + "success": "Coordonées: %s, %s, %s\nID de la scène: %s", + "description": "Obtenir vos coordonnées" + }, + "quest": { + "usage": "🇺🇸quest [questID]", + "added": "Quête %s ajoutée.", + "finished": "Quête terminée : %s.", + "not_found": "Quête introuvable.", + "invalid_id": "ID de la quête invalide.", + "description": "Ajoute ou termine une quête" + }, + "reload": { + "reload_start": "Rechargement de la configuration.", + "reload_done": "Rechargement terminé.", + "description": "Recharge la configuration du serveur" + }, + "resetConst": { + "reset_all": "Les constellations de tous les avatars ont été réinitialisés.", + "success": "Les constellations de %s ont été réinitialisés. Veuillez-vous reconnecter pour voir les modifications.", + "description": "Réinitialise les constellations d'un avatar. Vous devez vous reconnecter pour voir les modifications." + }, + "resetShopLimit": { + "usage": "🇺🇸Usage: resetshop ", + "success": "Réinitialisation terminée.", + "description": "Réinitialise le temps d'actualisation de la boutique du joueur spécifié" + }, + "sendMail": { + "usage": "🇺🇸Usage: sendmail [templateID]", + "user_not_exist": "L'utilisateur avec l'identifiant '%s' n'existe pas.", + "start_composition": "Démarrage de la composition du message.\nVeuillez utiliser'/sendmail ' pour continuer.\nVous pouvez utiliser '/sendmail stop' à tout moment.", + "templates": "Les modèles de lettres ne sont pas encore disponibles.", + "invalid_arguments": "Arguments invalides.", + "send_cancel": "L'envoi du message a été annulé.", + "send_done": "Le message a été envoyé à %s!", + "send_all_done": "Message envoyé à tous les utilisateurs!", + "not_composition_end": "La composition du message n'est pas au stade final.\nVeuillez utiliser '/sendmail %s' or '/sendmail stop' pour annuler", + "please_use": "Veuillez utiliser '/sendmail %s'", + "set_title": "Le titre du message a été défini à '%s'.\nUtilisez '/sendmail ' pour continuer.", + "set_contents": "Le contenu du message a été défini à '%s'.\nUtilisez '/sendmail ' pour continuer.", + "set_message_sender": "L'expéditeur a été défini à '%s'.\nUtilisez '/sendmail [quantité] [niveau]' pour continuer.", + "send": "%s %s (niveau %s) ont été ajouté au message.\nContinuez d'ajouter plus d'objets ou utilisez '/sendmail finish' pour envoyer le message.", + "invalid_arguments_please_use": "Arguments invalides.\n Veuillez utiliser '/sendmail %s'", + "title": "", + "message": "🇺🇸", + "sender": "", + "arguments": " [quantité] [niveau]", + "error": "ERREUR: Stade de construction invalide : %s. Vérifiez la console pour la pile d'appels.", + "description": "Envoie un courrier à l'utilisateur spécifié. L'utilisation de la commande change en fonction du stade de la composition du message." + }, + "sendMessage": { + "usage": "Usage: sendmessage ", + "success": "Message envoyé.", + "description": "Envoie un message au joueur spécifié en tant que Serveur" + }, + "setFetterLevel": { + "usage": "🇺🇸Usage: setfetterlevel ", + "range_error": "Le niveau d'affinité doit être compris entre 0 et 10.", + "success": "Niveau d'affinité défini à %s.", + "level_error": "Niveau d'affinité invalide.", + "description": "Défini le niveau d'affinité de votre personnage actif" + }, + "setProp": { + "usage": "🇺🇸Usage: setprop|prop \n\tValues for : godmode | nostamina | unlimitedenergy | abyss | worldlevel | bplevel\n\t(cont.) see PlayerProperty enum for other possible values, of form PROP_MAX_SPRING_VOLUME -> max_spring_volume", + "description": "Définit des propriétes pour votre compte. Des choses comme le godemode peuvent être activés avec cette commande, et le déblocage de l'abysse ainsi que l'avancement du PB." + }, + "setStats": { + "usage": "Usage: setstats|stats \n\tValeurs pour : hp | maxhp | def | atk | em | er | crate | cdmg | cdr | heal | heali | shield | defi\n\t(cont.) Bonus de dégât élémentaire: epyro | ecryo | ehydro | egeo | edendro | eelectro | ephys\n\t(cont.) Résistance élémentaire: respyro | rescryo | reshydro | resgeo | resdendro | reselectro | resphys\n", + "description": "Définit les propriétés de combat de votre personnage actif" + }, + "spawn": { + "usage": "Usage: spawn [quantité] [niveau(monstre uniquement)] [ (monstre uniquement, optionnel)]", + "success": " %s %s sont apparu.", + "limit_reached": "La limite d'apparition de la scène est atteinte. Apparition de %s entités à la place.", + "description": "Fait apparaitre une entité à proximité" + }, + "stop": { + "success": "Arrêt du serveur...", + "description": "Arrête le serveur" + }, + "talent": { + "usage_1": "Pour définir le niveau du talent: /talent set ", + "usage_2": "Une autre façon de définir le niveau d'un talent: /talent ", + "usage_3": "Pour obtenir l'ID d'un talent: /talent getid", + "lower_16": "Niveau de talent invalide. Le niveau doit être inférieur a 16.", + "set_id": "Talent défini à %s.", + "set_atk": "Le talent ATK normale a été défini à %s.", + "set_e": "Le talent E a été défini a %s.", + "set_q": "Le talent A/Q a été défini à %s.", + "invalid_skill_id": "ID de talent invalide.", + "set_this": "Ce talent a été défini a %s.", + "invalid_level": "Niveau de talent invalide.", + "normal_attack_id": "ID de l'attaque normale ID %s.", + "e_skill_id": "ID du E %s.", + "q_skill_id": "ID du A/Q %s.", + "description": "Définit le niveau du talent du personnage actif" + }, + "team": { + "usage": "🇺🇸Usage: team [avatarID,...] [index|first|last|index-index,...]", + "invalid_usage": "Utilisation invalide.", + "add_usage": "Utilisation (add): team add [index]", + "invalid_index": "Index invalide.", + "add_too_much": "Ce serveur autorise à avoir au maximum %d avatar(s) dans votre équipe.", + "failed_to_add_avatar": "Echec de l'ajout de l'avatar a l'ID %s dans votre équipe.", + "remove_usage": "Utilisation (remove): team remove ", + "failed_to_parse_index": "Echec de l'analyse de l'index index: %s", + "remove_too_much": "Vous ne pouvez pas retirer tous les avatars.", + "ignore_index": "Index(s) ignorés : %s", + "set_usage": "Utilisation : (set): team set ", + "index_out_of_range": "L'index spécifié est en dehors du champ.", + "failed_parse_avatar_id": "Echec de l'analyse de l'ID de l'avatar: %s", + "avatar_already_in_team": "L'avatar est déjà dans votre équipe.", + "avatar_not_found": "L'avatar %d est introuvable.", + "description": "Modifie votre équipe manuellement." + }, + "teleportAll": { + "success": "Tous les joueurs ont été téléportés sur votre position.", + "error": "Vous ne pouvez utiliser cette commande qu'en mode multijoueur.", + "description": "Téléporte tous les joueurs de votre monde sur votre position" + }, + "teleport": { + "usage_server": "Utilisation: tp @ [sceneID]", + "usage": "Utilisation: tp [@] [sceneID]", + "specify_player_id": "Vous devez spécifier un ID d'utilisateur.", + "invalid_position": "Position invalide.", + "exists_error": "La scène spécifié n'existe pas.", + "success": "%s a été téléporté à %s, %s, %s dans la scène %s.", + "description": "Change la position du joueur" + }, + "weather": { + "usage": "Utilisation: weather [weatherId] [climateType]\nLes ID de la météo peuvent être trouvés dans WeatherExcelConfigData.json.\nClimate types: sunny, cloudy, rain, thunderstorm, snow, mist.", + "success": "L'ID de la météo à été défini a %s avec le type de climat %s.", + "status": "L'ID de la météo accutel est %s avec le type de climat %s.", + "description": "Change la météo. Les ID de la météo peuvent être trouvés dans WeatherExcelConfigData.json.\nTypes de climatss: sunny, cloudy, rain, thunderstorm, snow, mist." + }, + "ban": { + "command_usage": "Usage: ban <@playerId> [timestamp] [raison]", + "success": "Succès.", + "failure": "Échec, joueur introuvable.", + "invalid_time": "Impossible d'analyser le timestamp.", + "description": "Bannis un joueur" + }, + "unban": { + "command_usage": "🇺🇸Usage: unban <@playerId>", + "success": "Succès.", + "failure": "Échec, joueur introuvable.", + "description": "Retire le bannissement d'un joueur" + } + }, + "gacha": { + "details": { + "title": "Détails de la bannière", + "available_five_stars": "Objets 5 étoiles disponibles", + "available_four_stars": "Objets 4 étoiles disponibles", + "available_three_stars": "Objets 3 étoiles disponibles" + }, + "records": { + "title": "🇺🇸Gacha Records", + "date": "🇺🇸Date", + "item": "Objet" + } + }, + "documentation": { + "handbook": { + "title": "Manuel GM", + "title_commands": "Commandes", + "title_avatars": "🇺🇸Avatars", + "title_items": "Objets", + "title_scenes": "Scènes", + "title_monsters": "Monstres", + "header_id": "🇺🇸Id", + "header_command": "Commande", + "header_description": "🇺🇸Description", + "header_avatar": "🇺🇸Avatar", + "header_item": "Objet", + "header_scene": "Scène", + "header_monster": "Monstre" + }, + "index": { + "title": "🇺🇸Documentation", + "handbook": "Manuel GM", + "gacha_mapping": "🇺🇸Gacha mapping JSON" + } } +} \ No newline at end of file diff --git a/src/main/resources/languages/pl-PL.json b/src/main/resources/languages/pl-PL.json index 41d63f708..0aed901f7 100644 --- a/src/main/resources/languages/pl-PL.json +++ b/src/main/resources/languages/pl-PL.json @@ -28,6 +28,8 @@ "login_token_attempt": "[Account] Klient %s próbuje się zalogować poprzez token.", "login_token_error": "[Account] Logowanie klienta %s poprzez token nie powiodło się.", "login_token_success": "[Account] Klient %s zalogował się poprzez token jako %s.", + "login_password_error": "🇺🇸[Dispatch] Client %s failed to log in via password.", + "login_password_storage_error": "🇺🇸[Dispatch] Client %s failed to log in via password because there is no password in the database.", "combo_token_success": "[Account] Klient %s pomyślnie wymienił token combo.", "combo_token_error": "[Account] Wymienienie tokena combo klienta %s nie powiodło się.", "account_login_create_success": "[Account] Logowanie klienta %s powiodło się: konto %s zostało stworzone.", @@ -37,6 +39,9 @@ "session_key_error": "Błędny klucz sesji.", "username_error": "Podana nazwa użytkownika nie istnieje.", "username_create_error": "Podana nazwa użytkownika nie istnieje. Automatyczne tworzenie nowego konta nie powiodło się.", + "password_error": "🇺🇸Invalid Password", + "password_length_error": "🇺🇸Password length must be greater then or equal to 8", + "password_storage_error": "🇺🇸You don't have a password for your account. Please contact an administrator.", "server_max_player_limit": "Liczba graczy online osiągnęła swój limit." }, "router_error": "[Dispatch] Wystąpił błąd podczas tworzenia routera." @@ -109,7 +114,7 @@ "success": "Sukces" }, "account": { - "usage": "account [UID]", + "command_usage": "🇺🇸Usage: account [UID]", "invalid": "Błędne UID gracza.", "exists": "Konto o tej nazwie użytkownika i/lub UID już istnieje.", "create": "Stworzono konto z UID %s.", @@ -118,7 +123,7 @@ "description": "Twórz lub usuń konta." }, "announce": { - "usage": "announce LUB announce LUB announce LUB announce ", + "command_usage": "🇺🇸Usage: announce|a <\"tpl\" templateId|\"refresh\"|\"revoke\" templateId|content>", "send_success": "Ogłoszenie zostało pomyślnie wysłane. Możesz je odwołać używając \"announce revoke %s\".", "refresh_success": "Odświeżono konfigurację ogłoszeń (w sumie jest ich %s).", "revoke_done": "Pomyślnie odwołano ogłoszenie %s.", @@ -126,7 +131,7 @@ "description": "Wysyłaj i zarządzaj ogłoszeniami." }, "clear": { - "usage": "Użycie: clear [lv] [r] [*]", + "command_usage": "🇺🇸Usage: clear [lv] [r] [*]", "weapons": "Usunięto bronie gracza %s.", "artifacts": "Usunięto artefakty gracza %s.", "materials": "Usunięto materiały gracza %s.", @@ -160,23 +165,20 @@ "description": "Dodaj wybrane przedmioty do ekwipunku wybranego gracza." }, "heal": { - "usage": "heal", "success": "Wszystkie postacie zostały uleczone.", "description": "Ulecz wszystkie postacie w swoim zespole." }, "help": { "usage": "help [nazwa komendy]", - "usage_prefix": "Użycie: ", "aliases": "Aliasy: ", "available_commands": "Dostępne komendy: ", - "description": "Wyświetl wszystkie komendy lub informacje na temat danej komendy.", "tip_need_permission": "Wymagane uprawnienie: ", "tip_need_no_permission": "brak", "tip_permission_targeted": "(użycie tego polecenia na innych graczach również wymaga uprawnienia %s)", - "warn_player_has_no_permission": "Nie masz wystarczających uprawnień do używania tej komendy." + "warn_player_has_no_permission": "Nie masz wystarczających uprawnień do używania tej komendy.", + "description": "Wyświetl wszystkie komendy lub informacje na temat danej komendy." }, "kick": { - "usage": "kick", "player_kick_player": "Gracz [%s:%s] wyrzucił gracza [%s:%s].", "server_kick_player": "Wyrzucono gracza [%s:%s].", "description": "Wyrzuć wskazanego gracza z gry." @@ -193,14 +195,12 @@ "description": "Zabij postać wskazanego gracza." }, "language": { - "usage": "language [kod języka]", "current_language": "Bieżący kod języka to %s.", "language_changed": "Zmieniono język na ten o kodzie %s.", "language_not_found": "Nie znaleziono języka o kodzie \"%s\".", "description": "Pokaż lub zmień bieżący kod języka." }, "list": { - "usage": "list @[ID gracza]", "success": "%s graczy online:", "description": "Pokaż ile jest graczy na serwerze." }, @@ -214,7 +214,6 @@ "description": "Dodaj lub usuń uprawnienia podanego gracza." }, "position": { - "usage": "position", "success": "Koordynaty: (%s, %s, %s).\nID sceny: %s.", "description": "Pokaż gdzie znajduje się dany gracz." }, @@ -227,13 +226,11 @@ "description": "Dodaj lub wykonaj wskazane zadanie." }, "reload": { - "usage": "reload", "reload_start": "Ponowne ładowanie konfiguracji...", "reload_done": "Ponowne ładowanie konfiguracji zakończone.", "description": "Ponownie załaduj język, konfigurację oraz inne dane gry." }, "resetConst": { - "usage": "resetconst [all]", "reset_all": "Zresetowano konstelacje dla wszystkich postaci. Aby zobaczyć zmiany, zaloguj się ponownie.", "success": "Konstelacje awatara %s zostały zresetowane. Aby zobaczyć zmiany, zaloguj się ponownie.", "description": "Resetuj konstelacje wszystkich lub wybranej postaci." @@ -293,7 +290,6 @@ "description": "Dodaj wskazane obiekty do sceny wybranego gracza." }, "stop": { - "usage": "stop", "success": "Serwer zatrzymuje się...", "description": "Zatrzymaj serwer." }, @@ -333,7 +329,6 @@ "description": "Modyfikuj zespół wybranego gracza." }, "teleportAll": { - "usage": "tpall", "success": "Przyzwano wszystkich graczy do wybranego gracza.", "error": "Możesz użyć tej komendy wyłącznie w trybie MP.", "description": "Przyzwij wszystkich graczy do wybranego gracza." @@ -354,14 +349,14 @@ "description": "Zmień ID pogody i typ klimatu." }, "ban": { - "usage": "ban @ [na ile czasu] [powód]", + "command_usage": "🇺🇸Usage: ban <@playerId> [timestamp] [reason]", "success": "Pomyślnie zbanowano podanego gracza.", "failure": "Gracz o podanym ID nie istnieje.", "invalid_time": "Nieprawidłowy czas bana.", "description": "Zbanuj podanego gracza." }, "unban": { - "usage": "unban @", + "command_usage": "🇺🇸Usage: unban <@playerId>", "success": "Pomyślnie odbanowano podanego gracza.", "failure": "Gracz o podanym ID nie istnieje.", "description": "Odbanuj podanego gracza." @@ -382,7 +377,7 @@ }, "documentation": { "handbook": { - "title": "GM Handbook", + "title": "🇺🇸GM Handbook", "title_commands": "Komendy", "title_avatars": "Awatary", "title_items": "Przedmioty", @@ -398,8 +393,8 @@ }, "index": { "title": "Dokumentacja", - "handbook": "GM Handbook", + "handbook": "🇺🇸GM Handbook", "gacha_mapping": "Losowanie w formacie JSON" } } -} +} \ No newline at end of file diff --git a/src/main/resources/languages/ro-RO.json b/src/main/resources/languages/ro-RO.json index 09a34f571..11dff3379 100644 --- a/src/main/resources/languages/ro-RO.json +++ b/src/main/resources/languages/ro-RO.json @@ -28,6 +28,8 @@ "login_token_attempt": "[Dispatch] Clientul %s încearcă să se conecteze prin token.", "login_token_error": "[Dispatch] Clientul %s nu a reușit să se conecteze prin token.", "login_token_success": "[Dispatch] Clientul %s sa conectat prin token ca %s.", + "login_password_error": "🇺🇸[Dispatch] Client %s failed to log in via password.", + "login_password_storage_error": "🇺🇸[Dispatch] Client %s failed to log in via password because there is no password in the database.", "combo_token_success": "[Dispatch] Clientul %s a reușit să schimbe token-ul combo.", "combo_token_error": "[Dispatch] Clientul %s nu a reușit să schimbe token-ul combo.", "account_login_create_success": "[Dispatch] Clientul %s nu a reușit să se conecteze: Cont %s creat.", @@ -37,6 +39,9 @@ "session_key_error": "Cheie de sesiune greșită.", "username_error": "Numele de utilizator nu a fost găsit.", "username_create_error": "Numele de utilizator nu a fost găsit, crearea a eșuat.", + "password_error": "🇺🇸Invalid Password", + "password_length_error": "🇺🇸Password length must be greater then or equal to 8", + "password_storage_error": "🇺🇸You don't have a password for your account. Please contact an administrator.", "server_max_player_limit": "Numărul de jucători online a ajuns la limită." }, "router_error": "[Dispatch] Nu se poate atașa routerul." @@ -117,6 +122,14 @@ "no_account": "Contul nu a fost găsit.", "description": "Modificați conturile de utilizator" }, + "announce": { + "command_usage": "🇺🇸Usage: announce|a <\"tpl\" templateId|\"refresh\"|\"revoke\" templateId|content>", + "send_success": "🇺🇸Send an announcement successfully, you can revoke it by /a revoke %s.", + "refresh_success": "🇺🇸Refresh announcement config file successfully. [Total %s]", + "revoke_done": "🇺🇸Try to revoke announcement %s.", + "not_found": "🇺🇸Could not found announcement %s.", + "description": "🇺🇸Send announcement to all online players, or manage server's announcement" + }, "clear": { "command_usage": "Utilizare: clear [lv] [r] [*]", "weapons": "Arme șterse pentru %s.", @@ -159,11 +172,11 @@ "usage": "Utilizare: ", "aliases": "Aliasuri: ", "available_commands": "Comenzi disponibile: ", - "description": "Trimite mesajul de ajutor sau afișează informații despre o comandă specificată", "tip_need_permission": "Permisiune: ", "tip_need_no_permission": " Niciuna", "tip_permission_targeted": " (Permisiunea %s este de asemenea necesară pentru a fi folosit pe alți jucători)", - "warn_player_has_no_permission": "Notă> Nu aveți permisiunea de a rula această comandă." + "warn_player_has_no_permission": "Notă> Nu aveți permisiunea de a rula această comandă.", + "description": "Trimite mesajul de ajutor sau afișează informații despre o comandă specificată" }, "kick": { "player_kick_player": "Jucătorul [%s:%s] l-a dat afară pe [%s:%s]", @@ -205,7 +218,7 @@ "description": "Obțineți coordonatele" }, "quest": { - "usage": "quest [questID]", + "usage": "🇺🇸quest [questID]", "added": "Misiunea %s adăugată.", "finished": "Ați terminat misiunea %s.", "not_found": "Misiunea nu a fost găsită.", @@ -292,9 +305,9 @@ "invalid_skill_id": "Skill ID nevalabil.", "set_this": "Setat acest talent ca %s.", "invalid_level": "Nivel de talent nevalabil.", - "normal_attack_id": "Normal Attack ID %s.", - "e_skill_id": "E skill ID %s.", - "q_skill_id": "Q skill ID %s.", + "normal_attack_id": "🇺🇸Normal Attack ID %s.", + "e_skill_id": "🇺🇸E skill ID %s.", + "q_skill_id": "🇺🇸Q skill ID %s.", "description": "Stabilește nivelul de talent pentru personajul tău activ actual" }, "team": { @@ -370,10 +383,10 @@ "title_items": "Elemente", "title_scenes": "Scene", "title_monsters": "Monștri", - "header_id": "Id", + "header_id": "🇺🇸Id", "header_command": "Comandă", "header_description": "Descriere", - "header_avatar": "Avatar", + "header_avatar": "🇺🇸Avatar", "header_item": "Element", "header_scene": "Scenă", "header_monster": "Monstru" @@ -381,7 +394,7 @@ "index": { "title": "Documentație", "handbook": "Manual GM", - "gacha_mapping": "Gacha mapping JSON" + "gacha_mapping": "🇺🇸Gacha mapping JSON" } } -} +} \ No newline at end of file diff --git a/src/main/resources/languages/ru-RU.json b/src/main/resources/languages/ru-RU.json index b1117acc7..91cf5cf26 100644 --- a/src/main/resources/languages/ru-RU.json +++ b/src/main/resources/languages/ru-RU.json @@ -9,7 +9,7 @@ }, "dispatch": { "port_bind": "[Dispatch] Распределительный сервер запущен на порте %s", - "request": "[Dispatch] Client %s %s request: %s", + "request": "🇺🇸[Dispatch] Client %s %s request: %s", "keystore": { "general_error": "[Dispatch] Возникла ошибка при загрузке keystore!", "password_error": "[Dispatch] Не удалось загрузить keystore. Пытаемся использовать пароль для keystore по умолчанию...", @@ -28,18 +28,23 @@ "login_token_attempt": "[Dispatch] Клиент %s пытается войти с помощью токена.", "login_token_error": "[Dispatch] Клиент %s не смог войти с помощью токена.", "login_token_success": "[Dispatch] Клиент %s вошел с помощью токена как %s.", - "combo_token_success": "[Dispatch] Client %s succeed to exchange combo token.", - "combo_token_error": "[Dispatch] Client %s failed to exchange combo token.", + "login_password_error": "🇺🇸[Dispatch] Client %s failed to log in via password.", + "login_password_storage_error": "🇺🇸[Dispatch] Client %s failed to log in via password because there is no password in the database.", + "combo_token_success": "🇺🇸[Dispatch] Client %s succeed to exchange combo token.", + "combo_token_error": "🇺🇸[Dispatch] Client %s failed to exchange combo token.", "account_login_create_success": "[Dispatch] Клиенту %s не удалось войти по причине: Аккаунт %s был создан.", "account_login_create_error": "[Dispatch] Клиенту %s не удалось войти по причне : Не удалось создать аккаунт.", "account_login_exist_error": "[Dispatch] Клиенту %s не удалось войти по причине: Аккаунт не найден.", - "account_cache_error": "Game account cache information error.", + "account_cache_error": "🇺🇸Game account cache information error.", "session_key_error": "Некорректный ключ сессии.", "username_error": "Имя пользователя не обнаружено.", "username_create_error": "Имя пользователя не найденоUsername not found, создание не удалось.", + "password_error": "🇺🇸Invalid Password", + "password_length_error": "🇺🇸Password length must be greater then or equal to 8", + "password_storage_error": "🇺🇸You don't have a password for your account. Please contact an administrator.", "server_max_player_limit": "Число игроков в сети достигло предела" }, - "router_error": "[Dispatch] Unable to attach router." + "router_error": "🇺🇸[Dispatch] Unable to attach router." }, "status": { "free_software": "Grasscutter является БЕСПЛАТНЫМ программным обеспечением. Если вы заплатили за него деньги, то вас обманули. Домашняя страница проекта: https://github.com/Grasscutters/Grasscutter", @@ -55,8 +60,8 @@ "version": "Версия Grasscutter: %s-%s", "game_version": "Версия игры: %s", "resources": { - "loading": "Loading resources...", - "finish": "Finished loading resources." + "loading": "🇺🇸Loading resources...", + "finish": "🇺🇸Finished loading resources." } } }, @@ -82,7 +87,7 @@ "itemLevel": "Некорректный уровень предмета (itemLevel).", "itemRefinement": "Некорректный уровень пробуждения предмета (itemRefinement).", "statValue": "Некорректное значение характеристики.", - "value_between": "Invalid value: %s must be between %s and %s.", + "value_between": "🇺🇸Invalid value: %s must be between %s and %s.", "playerId": "Некорректный ID игрока.", "uid": "Некорректный UID.", "id": "Некорректный ID." @@ -109,26 +114,21 @@ "success": "Успех" }, "account": { - "modify": "Изменить аккаунты пользователя", + "command_usage": "Применение: account <имя_пользователя> [UID]", "invalid": "Некорректный UID.", "exists": "Аккаунт с таким именем пользователя и/или UID уже существует.", "create": "Создан аккаунт с UID %s.", "delete": "Аккаунт удалён.", "no_account": "Аккаунт не найден.", - "command_usage": "Применение: account <имя_пользователя> [UID]", "description": "Изменяет аккаунт пользователя" }, - "broadcast": { - "command_usage": "Применение: broadcast <сообщение>", - "message_sent": "Сообщение отправлено.", - "description": "Отправляет сообщение всем игрокам" - }, - "changescene": { - "usage": "Применение: changescene ", - "already_in_scene": "Вы уже находитесь в этой сцене.", - "success": "Переход в сцену %s.", - "exists_error": "Указанной сцены не существует.", - "description": "Изменяет текущую сцену" + "announce": { + "command_usage": "🇺🇸Usage: announce|a <\"tpl\" templateId|\"refresh\"|\"revoke\" templateId|content>", + "send_success": "🇺🇸Send an announcement successfully, you can revoke it by /a revoke %s.", + "refresh_success": "🇺🇸Refresh announcement config file successfully. [Total %s]", + "revoke_done": "🇺🇸Try to revoke announcement %s.", + "not_found": "🇺🇸Could not found announcement %s.", + "description": "🇺🇸Send announcement to all online players, or manage server's announcement" }, "clear": { "command_usage": "Применение: clear [lv] [r] [*]", @@ -136,8 +136,8 @@ "artifacts": "Удалены артефакты у %s.", "materials": "Удалены материалы у %s.", "furniture": "Удалена мебель у %s.", - "displays": "Cleared displays for %s.", - "virtuals": "Cleared virtuals for %s.", + "displays": "🇺🇸Cleared displays for %s.", + "virtuals": "🇺🇸Cleared virtuals for %s.", "everything": "Удалено всё у %s.", "description": "Удаляет все неэкипированные на данный момент предметы из инвентаря, включая предметы золотой редкости" }, @@ -146,11 +146,6 @@ "success": "Игрок %s был призван в мир %s.", "description": "Принудительно присоединяет кого-то к миру другого человека. Если не выбрана цель, то вы всё равно войдете в совместный режим." }, - "drop": { - "command_usage": "Применение: drop [кол-во]", - "success": "Были уронены %s игрока %s.", - "description": "Роняет предмет возле вас" - }, "enter_dungeon": { "usage": "Применение: enterdungeon ", "changed": "Произошёл переход в подземелье %s.", @@ -158,40 +153,17 @@ "in_dungeon_error": "Вы уже в этом подземелье.", "description": "Позволяет войти в подземелье" }, - "giveAll": { - "usage": "Применение: giveall [игрок] [кол-во]", - "started": "Получаем все предметы...", - "success": "Все предметы были успешно выданы %s.", - "invalid_amount_or_playerId": "Некорректное число или ID игрока.", - "description": "Выдаёт все предметы" - }, - "giveArtifact": { - "usage": "Применение: giveart|gart [игрок] [[,<раз>]]... [уровень]", - "id_error": "Некорректный ID артефакта.", - "success": "Выдан %s игроку %s.", - "description": "Выдает игроку заданный артефакт" - }, - "giveChar": { - "usage": "Применение: givechar [level]", - "given": "Выдан(а) %s с уровнем %s игроку %s.", - "invalid_avatar_id": "Некорректный ID аватара.", - "invalid_avatar_level": "Некорректный уровень аватара.", - "invalid_avatar_or_player_id": "Некорректный ID игрока или аватара.", - "description": "Выдает игроку заданного персонажа" - }, "give": { "usage": "Применение: give <игрок> [кол-во] [уровень] [пробуждение]", - "refinement_only_applicable_weapons": "Пробуждение применимо только к оружию.", - "refinement_must_between_1_and_5": "Значение пробуждения должно быть от 1 до 5.", + "usage_relic": "🇺🇸Usage: give [mainPropID] [[,]]... [lv]", + "illegal_relic": "🇺🇸This artifactID belongs to a blacklisted range, it may not be the one you wanted.", "given": "Выдано %s %s игроку %s.", "given_with_level_and_refinement": "Выдано %s с уровнем %s, уровнем пробуждения %s %s раз игроку %s.", "given_level": "Выдано %s с уровнем %s %s раз игроку %s.", + "given_avatar": "🇺🇸Given %s with level %s to %s.", + "giveall_success": "🇺🇸Successfully gave all items.", "description": "Выдаёт предмет лично вам или заданному игроку" }, - "godmode": { - "success": "Godmode теперь %s для %s.", - "description": "Не позволяет получать урон. По умолчанию переключается." - }, "heal": { "success": "Все персонажи были вылечены.", "description": "Лечит всех персонажей в вашей команде." @@ -200,6 +172,10 @@ "usage": "Применение: ", "aliases": "Альтернативные названия: ", "available_commands": "Доступные команды: ", + "tip_need_permission": "🇺🇸Permission: ", + "tip_need_no_permission": "🇺🇸 None", + "tip_permission_targeted": "🇺🇸 (Permission %s is also required to use on other players)", + "warn_player_has_no_permission": "🇺🇸Notice: You do not have permission to run this command.", "description": "Отправляет сообщение с помощью или показывает информацию о заданной команде" }, "kick": { @@ -228,10 +204,6 @@ "success": "Сейчас в сети %s игрок(ов):", "description": "Список игроков в сети" }, - "nostamina": { - "success": "NoStamina теперь %s для %s.", - "description": "Поддерживает уровень выносливости на максимуме." - }, "permission": { "usage": "Применение: permission <имя_пользователя> <разрешение>", "add": "Разрешение добавлено.", @@ -268,9 +240,6 @@ "success": "Сброс выполнен успешно.", "description": "Сбрасывает таймер обновления магазина у выбранного игрока" }, - "restart": { - "description": "Перезапускает текущую сессию" - }, "sendMail": { "usage": "Применение: sendmail [ID_шаблона]", "user_not_exist": "Пользователь с ID '%s' не найден.", @@ -307,20 +276,13 @@ "description": "Устанавливает уровень дружбы для активного персонажа" }, "setProp": { - "usage": "Usage: setprop|prop \n\tValues for : godmode | nostamina | unlimitedenergy | abyss | worldlevel | bplevel\n\t(cont.) see PlayerProperty enum for other possible values, of form PROP_MAX_SPRING_VOLUME -> max_spring_volume", - "description": "Sets accountwide properties. Things like godmode can be enabled this way, as well as changing things like unlocked abyss floor and battle pass progress." + "usage": "🇺🇸Usage: setprop|prop \n\tValues for : godmode | nostamina | unlimitedenergy | abyss | worldlevel | bplevel\n\t(cont.) see PlayerProperty enum for other possible values, of form PROP_MAX_SPRING_VOLUME -> max_spring_volume", + "description": "🇺🇸Sets accountwide properties. Things like godmode can be enabled this way, as well as changing things like unlocked abyss floor and battle pass progress." }, "setStats": { "usage": "Применение: setstats|stats <хар-ка> <значение>\n\tВозможные значения для <хар-ка>: hp | maxhp | def | atk | em | er | crate | cdmg | cdr | heal | heali | shield | defi\n\t(прод.) Бонус элементального урона: epyro | ecryo | ehydro | egeo | edendro | eelectro | ephys\n\t(cont.) Элементальное сопротивление: respyro | rescryo | reshydro | resgeo | resdendro | reselectro | resphys\n", "description": "Задаёт боевые характеристики для активного персонажа" }, - "setWorldLevel": { - "usage": "Применение: setworldlevel ", - "value_error": "Уровень мира должен находиться в пределах 0-8.", - "success": "Уровень мира стал равен %s.", - "invalid_world_level": "Некорректный уровень мира.", - "description": "Задает уровень мира (Перезайдите в игру для того, чтобы увидеть результат)" - }, "spawn": { "usage": "Применение: spawn [кол-во] [уровень(только для монстров)] [ (только для монстров, опционально)]", "success": "Заспавнено %s %s.", @@ -376,36 +338,28 @@ "usage": "Применение: tp [@] [ID_сцены]", "specify_player_id": "Нужно указать ID игрока.", "invalid_position": "Некорректная позиция.", + "exists_error": "🇺🇸The specified scene does not exist.", "success": "Игрок %s был телепортирован по координатам %s, %s, %s в сцене %s.", "description": "Изменяет позицию игрока" }, - "unlimitenergy": { - "success": "UnlimitEnergy теперь %s для игрока %s.", - "config_error": "Команда недоступна, поскольку energyUsage равно false в config.json.", - "description": "Используйте данный элемент для того, чтобы не тратить энергию" - }, - "unlocktower": { - "success": "Теперь открыты все этажи Коридора Бездны.", - "description": "Открывает все уровни башни" - }, "weather": { - "description": "Изменяет погоду.Weather IDs can be found in WeatherExcelConfigData.json.\nClimate types: sunny, cloudy, rain, thunderstorm, snow, mist.", "usage": "Usage: weather [weatherId] [climateType]\nWeather IDs can be found in WeatherExcelConfigData.json.\nClimate types: sunny, cloudy, rain, thunderstorm, snow, mist.", - "success": "Set weather ID to %s with climate type %s.", - "status": "Current weather ID is %s with climate type %s." + "success": "🇺🇸Set weather ID to %s with climate type %s.", + "status": "🇺🇸Current weather ID is %s with climate type %s.", + "description": "Изменяет погоду.Weather IDs can be found in WeatherExcelConfigData.json.\nClimate types: sunny, cloudy, rain, thunderstorm, snow, mist." }, "ban": { - "description": "Банит игрока", + "command_usage": "Применение: ban <@Id игрока> [промежуток_времени] [причина]", "success": "Успех.", "failure": "Неудача, игрок не найден.", "invalid_time": "Не удалось определить промежуток времени.", - "command_usage": "Применение: ban <@Id игрока> [промежуток_времени] [причина]" + "description": "Банит игрока" }, "unban": { - "description": "Разбанивает игрока", + "command_usage": "Применение: unban <@Id_игрока>", "success": "Успех.", "failure": "Неудача, игрок не найден.", - "command_usage": "Применение: unban <@Id_игрока>" + "description": "Разбанивает игрока" } }, "gacha": { @@ -443,4 +397,4 @@ "gacha_mapping": "Мапирование системы гача в JSON" } } -} +} \ No newline at end of file diff --git a/src/main/resources/languages/zh-CN.json b/src/main/resources/languages/zh-CN.json index 9eaf00a9d..da7866ffb 100644 --- a/src/main/resources/languages/zh-CN.json +++ b/src/main/resources/languages/zh-CN.json @@ -28,6 +28,8 @@ "login_token_attempt": "[Dispatch] 客户端 %s 正在尝试通过 token 登录", "login_token_error": "[Dispatch] 客户端 %s 通过 token 登录失败", "login_token_success": "[Dispatch] 客户端 %s 已通过 token 登录,UID 为 %s", + "login_password_error": "🇺🇸[Dispatch] Client %s failed to log in via password.", + "login_password_storage_error": "🇺🇸[Dispatch] Client %s failed to log in via password because there is no password in the database.", "combo_token_success": "[Dispatch] 客户端 %s 成功交换 token", "combo_token_error": "[Dispatch] 客户端 %s 交换 token 失败", "account_login_create_success": "[Dispatch] 客户端 %s 登录失败:已注册 UID 为 %s 的账号", @@ -37,6 +39,9 @@ "session_key_error": "会话密钥错误", "username_error": "未找到用户名", "username_create_error": "未找到用户名,建立连接失败", + "password_error": "🇺🇸Invalid Password", + "password_length_error": "🇺🇸Password length must be greater then or equal to 8", + "password_storage_error": "🇺🇸You don't have a password for your account. Please contact an administrator.", "server_max_player_limit": "服务器在线人数已满" }, "router_error": "[Dispatch] 无法连接路由" @@ -372,7 +377,7 @@ }, "documentation": { "handbook": { - "title": "GM Handbook", + "title": "🇺🇸GM Handbook", "title_commands": "命令", "title_avatars": "角色", "title_items": "物品", @@ -388,8 +393,8 @@ }, "index": { "title": "文档", - "handbook": "GM Handbook", + "handbook": "🇺🇸GM Handbook", "gacha_mapping": "祈愿物品映射JSON" } } -} +} \ No newline at end of file diff --git a/src/main/resources/languages/zh-TW.json b/src/main/resources/languages/zh-TW.json index 1d2dbb570..dc4b4f224 100644 --- a/src/main/resources/languages/zh-TW.json +++ b/src/main/resources/languages/zh-TW.json @@ -28,6 +28,8 @@ "login_token_attempt": "[Dispatch] 客戶端 %s 正在嘗試用憑證登入", "login_token_error": "[Dispatch] 客戶端 %s 使用憑證登入失敗", "login_token_success": "[Dispatch] 客戶端 %s 已透過憑證登入,UID為 %s", + "login_password_error": "🇺🇸[Dispatch] Client %s failed to log in via password.", + "login_password_storage_error": "🇺🇸[Dispatch] Client %s failed to log in via password because there is no password in the database.", "combo_token_success": "[Dispatch] 客戶端 %s 交換憑證成功", "combo_token_error": "[Dispatch] 客戶端 %s 交換憑證失敗", "account_login_create_success": "[Dispatch] 客戶端 %s 登入失敗: 已註冊UID為 %s 的帳號", @@ -37,6 +39,9 @@ "session_key_error": "對話密鑰不符。", "username_error": "未找到此用戶名。", "username_create_error": "未找到用戶名,建立失敗。", + "password_error": "🇺🇸Invalid Password", + "password_length_error": "🇺🇸Password length must be greater then or equal to 8", + "password_storage_error": "🇺🇸You don't have a password for your account. Please contact an administrator.", "server_max_player_limit": "伺服器在線人數已滿" }, "router_error": "[Dispatch] 無法附加到路由上。" @@ -55,8 +60,8 @@ "version": "Grasscutter版本: %s-%s", "game_version": "遊戲版本:%s", "resources": { - "loading": "Loading resources...", - "finish": "Finished loading resources." + "loading": "🇺🇸Loading resources...", + "finish": "🇺🇸Finished loading resources." } } }, @@ -68,6 +73,7 @@ "console_execute_error": "此指令只能在伺服器的命令提示字元執行。", "player_execute_error": "請在遊戲裡使用這條指令。", "command_exist_error": "找不到指令。", + "no_usage_specified": "🇺🇸No usage specified", "no_description_specified": "没有指定說明。", "set_to": "%s 已經設為 %s。", "set_for_to": "%s 的使用者 %s 更改為 %s。", @@ -81,7 +87,7 @@ "itemLevel": "無效的物品等級。", "itemRefinement": "無效的物品精煉度。", "statValue": "無效的數據值。", - "value_between": "Invalid value: %s must be between %s and %s.", + "value_between": "🇺🇸Invalid value: %s must be between %s and %s.", "playerId": "無效的玩家ID。", "uid": "無效的UID。", "id": "無效的ID。" @@ -108,14 +114,22 @@ "success": "成功" }, "account": { + "command_usage": "用法:account [uid]", "invalid": "無效的UID。", "exists": "帳號已存在。", "create": "已建立帳號,UID 為 %s 。", "delete": "帳號已刪除。", "no_account": "帳號不存在。", - "command_usage": "用法:account [uid]", "description": "建立或刪除帳號。" }, + "announce": { + "command_usage": "🇺🇸Usage: announce|a <\"tpl\" templateId|\"refresh\"|\"revoke\" templateId|content>", + "send_success": "🇺🇸Send an announcement successfully, you can revoke it by /a revoke %s.", + "refresh_success": "🇺🇸Refresh announcement config file successfully. [Total %s]", + "revoke_done": "🇺🇸Try to revoke announcement %s.", + "not_found": "🇺🇸Could not found announcement %s.", + "description": "🇺🇸Send announcement to all online players, or manage server's announcement" + }, "clear": { "command_usage": "用法: clear [lv] [r] [*]", "weapons": "已將 %s 的武器清空。", @@ -139,37 +153,17 @@ "in_dungeon_error": "你已經在祕境中了。", "description": "進入指定祕境。" }, - "giveAll": { - "usage": "用法:giveall [player] [amount]", - "started": "正在賦予全部物品...", - "success": "已賦予全部物品。", - "invalid_amount_or_playerId": "無效的數量/玩家ID。", - "description": "賦予所有物品。" - }, - "giveArtifact": { - "usage": "用法:giveart|gart [player] [[,]]... [level]", - "id_error": "無效的聖遺物ID。", - "success": "已把 %s 給予 %s。", - "description": "給予指定聖遺物。" - }, "give": { - "usage": "用法:give [amount] [level] [refinement]", - "refinement_only_applicable_weapons": "精煉度只能施加在武器上面。", - "refinement_must_between_1_and_5": "精煉度必需在 1 到 5 之間。", + "usage": "用法:give [amount] [level] [refinement]", + "usage_relic": "🇺🇸Usage: give [mainPropID] [[,]]... [lv]", + "illegal_relic": "🇺🇸This artifactID belongs to a blacklisted range, it may not be the one you wanted.", "given": "已經將 %s 個 %s 給予 %s。", "given_with_level_and_refinement": "已將 %s [等級%s, 精煉%s] %s個給予 %s", "given_level": "已將 %s 等級 %s %s 個給予 %s", - "given_avatar": "已將 %s 等級 %s 給予 %s。", + "given_avatar": "已將 %s 等級 %s 給予 %s。", + "giveall_success": "🇺🇸Successfully gave all items.", "description": "給予指定物品。" }, - "godmode": { - "success": "上帝模式設定為 %s 。 [用戶:%s]", - "description": "防止你受到傷害。" - }, - "nostamina": { - "success": "無限體力狀態: %s。[使用者:%s]", - "description": "開啟後所有動作都不再消耗體力。" - }, "heal": { "success": "所有角色已被治療。", "description": "治療當前隊伍的角色。" @@ -177,12 +171,12 @@ "help": { "usage": "用法:", "aliases": "別名:", - "description": "發送幫助信息或顯示特定命令的信息", "available_commands": "可用指令:", "tip_need_permission": "需要的權限: ", "tip_need_no_permission": "無", "tip_permission_targeted": "(對其他的玩家使用這個指令還需要權限%s)", - "warn_player_has_no_permission": "注意:你沒有執行這條指令的權限" + "warn_player_has_no_permission": "注意:你沒有執行這條指令的權限", + "description": "發送幫助信息或顯示特定命令的信息" }, "kick": { "player_kick_player": "玩家 [%s:%s] 已把 [%s:%s] 踢出", @@ -207,7 +201,7 @@ "description": "顯示或切換當前語言。" }, "list": { - "success": "目前總線上人數:%s" , + "success": "目前總線上人數:%s", "description": "查看所有在線玩家" }, "permission": { @@ -224,23 +218,18 @@ "description": "獲取目前所在位置的座標。" }, "quest": { - "description": "添加或完成任務", "usage": "quest [任務ID]", "added": "已添加任務 %s", "finished": "已完成任務 %s", "not_found": "未找到任務", - "invalid_id": "無效的任務ID" + "invalid_id": "無效的任務ID", + "description": "添加或完成任務" }, "reload": { "reload_start": "正在重新加載設定檔。", "reload_done": "重新加載已完成。", "description": "重新加載設定檔和數據。" }, - "remove": { - "usage": "用法: remove [多個角色在隊伍中的序號] 序號从1开始", - "invalid_index": "序號不合法,從1開始,最大值為隊内角色數量", - "description": "强制移除對内角色,例如`remove 1 2`表示將1號和2號角色從隊伍中移除" - }, "resetConst": { "reset_all": "重設所有角色的命座。", "success": "已重設 %s 的命座,重新登入後將會生效。", @@ -287,23 +276,17 @@ "description": "設定當前角色的好感度等級。" }, "setProp": { - "usage": "Usage: setprop|prop \n\tValues for : godmode | nostamina | unlimitedenergy | abyss | worldlevel | bplevel\n\t(cont.) see PlayerProperty enum for other possible values, of form PROP_MAX_SPRING_VOLUME -> max_spring_volume", - "description": "Sets accountwide properties. Things like godmode can be enabled this way, as well as changing things like unlocked abyss floor and battle pass progress." + "usage": "🇺🇸Usage: setprop|prop \n\tValues for : godmode | nostamina | unlimitedenergy | abyss | worldlevel | bplevel\n\t(cont.) see PlayerProperty enum for other possible values, of form PROP_MAX_SPRING_VOLUME -> max_spring_volume", + "description": "🇺🇸Sets accountwide properties. Things like godmode can be enabled this way, as well as changing things like unlocked abyss floor and battle pass progress." }, "setStats": { "usage": "用法:setstats|stats \n\t可使用的數據類型:hp (生命值)| maxhp (最大生命值) | def(防禦力) | atk (攻擊力)| em (元素精通) | er (元素充能效率) | crate(暴擊率) | cdmg (暴擊傷害)| cdr (冷卻縮減) | heal(治療加成)| heali (受治療加成)| shield (護盾強效)| defi (無視防禦)\n\t(cont.) 元素增傷類:epyro (火傷) | ecryo (冰傷) | ehydro (水傷) | egeo (岩傷) | edendro (草傷) | eelectro (雷傷) | ephys (物傷)(cont.) 元素減傷類:respyro (火抗) | rescryo (冰抗) | reshydro (水抗) | resgeo (岩抗) | resdendro (草抗) | reselectro (雷抗) | resphys (物抗)\n", "description": "設定當前角色的數據類型。" }, - "setWorldLevel": { - "usage": "用法:setworldlevel ", - "value_error": "世界等級必須設定在0-8之間。", - "success": "已將世界等級設為%s。", - "invalid_world_level": "無效的世界等級。", - "description": "設定世界等級,執行指令後需重新登入後才會生效。" - }, "spawn": { "usage": "用法:spawn [amount] [level(僅限怪物)]", "success": "已生成 %s 個 %s。", + "limit_reached": "🇺🇸Scene spawn limit reached. Spawning %s entities instead.", "description": "在你附近生成一個實體動物。" }, "stop": { @@ -355,19 +338,10 @@ "usage": "用法:tp [@] [sceneId]", "specify_player_id": "你必須指定一個玩家ID。", "invalid_position": "無效的座標。", - "exists_error": "此場景不存在。", + "exists_error": "此場景不存在。", "success": "傳送 %s 到座標 %s,%s,%s ,場景為 %s 。", "description": "將玩家的位置傳送到你所指定的座標。" }, - "unlimitenergy": { - "success": "無限元素能量設定為 %s 。 [用戶:%s]", - "config_error": "指令不可用。因為 config.json 中 energyUsage 為 false。", - "description": "使用元素爆發而不消耗能量。" - }, - "unlocktower": { - "success": "解鎖完成。", - "description": "解鎖所有級別的深境螺旋。" - }, "weather": { "usage": "用法:weather [weatherId] [climateType]\n天氣ID可以在 WeatherExcelConfigData.json 中找到。\n氣候型別:sunny(晴天), cloudy(多雲), rain(雨), thunderstorm(雷雨), snow(雪), mist(霧)", "success": "已設定天氣ID 為 %s,氣候型別為 %s。", @@ -375,17 +349,17 @@ "description": "更改天氣ID和氣候型別。天氣ID可以在 WeatherExcelConfigData.json 中找到。\n氣候型別:sunny(晴天), cloudy(多雲), rain(雨), thunderstorm(雷雨), snow(雪), mist(霧)" }, "ban": { - "description": "停權指定玩家。", + "command_usage": "用法:ban <@playerId> [timestamp] [reason]", "success": "停權成功。", "failure": "停權失敗,玩家帳號不存在。", "invalid_time": "無效的時間戳。", - "command_usage": "用法:ban <@playerId> [timestamp] [reason]" + "description": "停權指定玩家。" }, "unban": { - "description": "撤銷停權指定玩家。", + "command_usage": "用法:unban <@playerId>", "success": "撤銷停權成功。", "failure": "撤銷停權失敗,玩家帳號不存在。", - "command_usage": "用法:unban <@playerId>" + "description": "撤銷停權指定玩家。" } }, "gacha": { @@ -403,7 +377,7 @@ }, "documentation": { "handbook": { - "title": "GM Handbook", + "title": "🇺🇸GM Handbook", "title_commands": "指令", "title_avatars": "角色", "title_items": "道具", @@ -419,8 +393,8 @@ }, "index": { "title": "文件", - "handbook": "GM Handbook", + "handbook": "🇺🇸GM Handbook", "gacha_mapping": "祈願物品映射到JSON上" } } -} +} \ No newline at end of file From 7189e3701d1aaf9775532fb97a97e76789af0092 Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Thu, 21 Jul 2022 01:06:17 -0700 Subject: [PATCH 42/61] Use `getOpenStateMap()` in PlayerOpenStateManager --- .../emu/grasscutter/game/player/PlayerOpenStateManager.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/emu/grasscutter/game/player/PlayerOpenStateManager.java b/src/main/java/emu/grasscutter/game/player/PlayerOpenStateManager.java index 8757639f4..554cb892e 100644 --- a/src/main/java/emu/grasscutter/game/player/PlayerOpenStateManager.java +++ b/src/main/java/emu/grasscutter/game/player/PlayerOpenStateManager.java @@ -33,7 +33,7 @@ public class PlayerOpenStateManager extends BasePlayerDataManager { public static final Set DEV_OPEN_STATES = Stream.of(OpenState.values()) .filter(s -> s != OpenState.OPEN_STATE_NONE && s.getUnlockLevel() <= 1) .collect(Collectors.toSet()); - + public PlayerOpenStateManager(Player player) { super(player); } @@ -44,11 +44,11 @@ public class PlayerOpenStateManager extends BasePlayerDataManager { } public int getOpenState(OpenState openState) { - return this.map.getOrDefault(openState.getValue(), 0); + return getOpenStateMap().getOrDefault(openState.getValue(), 0); } public void setOpenState(OpenState openState, Integer value) { - Integer previousValue = this.map.getOrDefault(openState.getValue(),0); + Integer previousValue = getOpenStateMap().getOrDefault(openState.getValue(),0); if (value != previousValue) { this.map.put(openState.getValue(), value); player.getSession().send(new PacketOpenStateChangeNotify(openState.getValue(),value)); From 5e041b333b8a10febf3e49593292f8b72a4164cd Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Thu, 21 Jul 2022 01:19:28 -0700 Subject: [PATCH 43/61] Forgot to remove extra player var from TeamManager --- src/main/java/emu/grasscutter/game/player/TeamManager.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/main/java/emu/grasscutter/game/player/TeamManager.java b/src/main/java/emu/grasscutter/game/player/TeamManager.java index 9fd19abdf..ce4aafb66 100644 --- a/src/main/java/emu/grasscutter/game/player/TeamManager.java +++ b/src/main/java/emu/grasscutter/game/player/TeamManager.java @@ -42,8 +42,6 @@ import it.unimi.dsi.fastutil.ints.IntSet; @Entity public class TeamManager extends BasePlayerDataManager { - @Transient private Player player; - private Map teams; private int currentTeamIndex; private int currentCharacterIndex; @@ -78,7 +76,7 @@ public class TeamManager extends BasePlayerDataManager { } public World getWorld() { - return player.getWorld(); + return getPlayer().getWorld(); } public Map getTeams() { From ad0225df3a7c5163c8a91ec0407ad3be3b3288e6 Mon Sep 17 00:00:00 2001 From: AnimeGitB Date: Thu, 21 Jul 2022 18:05:09 +0930 Subject: [PATCH 44/61] Make Lint_Commit not fail on no commit --- .github/workflows/lint_commit.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/lint_commit.yml b/.github/workflows/lint_commit.yml index 684cbe4bf..2b0f2a979 100644 --- a/.github/workflows/lint_commit.yml +++ b/.github/workflows/lint_commit.yml @@ -32,10 +32,10 @@ jobs: # - run: git merge development - run: git reset --hard development - run: git stash pop - - run: git add -u - - run: git commit -m 'Fix whitespace [skip actions]' + - name: Commit any whitespace changes + run: git add -u && git commit -m 'Fix whitespace [skip actions]' || true - name: Update Languages run: python manage_languages.py -u - - run: git add -u - - run: git commit -m 'Update languages [skip actions]' + - name: Commit any language changes + run: git add -u && git commit -m 'Update languages [skip actions]' || true - run: git push --set-upstream --force origin LintRatchet From c9c45e4c32689839feb8b5e8d8eb19245ff838e4 Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Thu, 21 Jul 2022 03:42:16 -0700 Subject: [PATCH 45/61] Partial fix for player attacks in co-op not working --- .../recv/HandlerCombatInvocationsNotify.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/main/java/emu/grasscutter/server/packet/recv/HandlerCombatInvocationsNotify.java b/src/main/java/emu/grasscutter/server/packet/recv/HandlerCombatInvocationsNotify.java index e77cbecb7..5df89de0c 100644 --- a/src/main/java/emu/grasscutter/server/packet/recv/HandlerCombatInvocationsNotify.java +++ b/src/main/java/emu/grasscutter/server/packet/recv/HandlerCombatInvocationsNotify.java @@ -11,6 +11,7 @@ import emu.grasscutter.net.proto.AttackResultOuterClass.AttackResult; import emu.grasscutter.net.proto.CombatInvocationsNotifyOuterClass.CombatInvocationsNotify; import emu.grasscutter.net.proto.CombatInvokeEntryOuterClass.CombatInvokeEntry; import emu.grasscutter.net.proto.EntityMoveInfoOuterClass.EntityMoveInfo; +import emu.grasscutter.net.proto.EvtAnimatorParameterInfoOuterClass.EvtAnimatorParameterInfo; import emu.grasscutter.net.proto.EvtBeingHitInfoOuterClass.EvtBeingHitInfo; import emu.grasscutter.net.packet.PacketHandler; import emu.grasscutter.net.proto.MotionInfoOuterClass.MotionInfo; @@ -33,6 +34,7 @@ public class HandlerCombatInvocationsNotify extends PacketHandler { public void handle(GameSession session, byte[] header, byte[] payload) throws Exception { CombatInvocationsNotify notif = CombatInvocationsNotify.parseFrom(payload); for (CombatInvokeEntry entry : notif.getInvokeListList()) { + // Handle combat invoke switch (entry.getArgumentType()) { case COMBAT_TYPE_ARGUMENT_EVT_BEING_HIT: EvtBeingHitInfo hitInfo = EvtBeingHitInfo.parseFrom(entry.getCombatData()); @@ -83,8 +85,21 @@ public class HandlerCombatInvocationsNotify extends PacketHandler { handleFallOnGround(session, entity, motionState); } } + + // MOTION_STATE_NOTIFY = Dont send to other players + if (motionState == MotionState.MOTION_STATE_NOTIFY) { + continue; + } } break; + case COMBAT_TYPE_ARGUMENT_ANIMATOR_PARAMETER_CHANGED: + EvtAnimatorParameterInfo paramInfo = EvtAnimatorParameterInfo.parseFrom(entry.getCombatData()); + + if (paramInfo.getIsServerCache()) { + paramInfo = paramInfo.toBuilder().setIsServerCache(false).build(); + entry = entry.toBuilder().setCombatData(paramInfo.toByteString()).build(); + } + break; default: break; } From a07b3f21e6fbeb9abfad8862d6fa0dc4a1c3c1a3 Mon Sep 17 00:00:00 2001 From: Magix <27646710+KingRainbow44@users.noreply.github.com> Date: Thu, 21 Jul 2022 11:36:49 -0400 Subject: [PATCH 46/61] Bump project version --- build.gradle | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/build.gradle b/build.gradle index 524778302..38d354500 100644 --- a/build.gradle +++ b/build.gradle @@ -43,8 +43,7 @@ sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 group = 'xyz.grasscutters' -version = '1.2.2-dev' - +version = '1.2.3-dev' sourceCompatibility = 17 targetCompatibility = 17 From 62e54010ade7d28a628699c1e1141b79d951db03 Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Thu, 21 Jul 2022 16:23:59 -0700 Subject: [PATCH 47/61] Lower kcp interval to 20 --- src/main/java/emu/grasscutter/server/game/GameServer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/emu/grasscutter/server/game/GameServer.java b/src/main/java/emu/grasscutter/server/game/GameServer.java index 7eb25a67c..503992595 100644 --- a/src/main/java/emu/grasscutter/server/game/GameServer.java +++ b/src/main/java/emu/grasscutter/server/game/GameServer.java @@ -83,7 +83,7 @@ public final class GameServer extends KcpServer { public GameServer(InetSocketAddress address) { ChannelConfig channelConfig = new ChannelConfig(); - channelConfig.nodelay(true, 40, 2, true); + channelConfig.nodelay(true, 20, 2, true); channelConfig.setMtu(1400); channelConfig.setSndwnd(256); channelConfig.setRcvwnd(256); From b505b0825aec5b921b4a61227f5db94fbf7ee411 Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Thu, 21 Jul 2022 16:24:04 -0700 Subject: [PATCH 48/61] Fix host team size not changing when a player joins their world for the first time --- .../emu/grasscutter/game/world/World.java | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/main/java/emu/grasscutter/game/world/World.java b/src/main/java/emu/grasscutter/game/world/World.java index 456a07108..04858e2a5 100644 --- a/src/main/java/emu/grasscutter/game/world/World.java +++ b/src/main/java/emu/grasscutter/game/world/World.java @@ -148,7 +148,7 @@ public class World implements Iterable { player.setPeerId(this.getNextPeerId()); player.getTeamManager().setEntityId(getNextEntityId(EntityIdType.TEAM)); - // Copy main team to mp team + // Copy main team to multiplayer team if (this.isMultiplayer()) { player.getTeamManager().getMpTeam().copyFrom(player.getTeamManager().getCurrentSinglePlayerTeamInfo(), player.getTeamManager().getMaxTeamSize()); player.getTeamManager().setCurrentCharacterIndex(0); @@ -282,8 +282,8 @@ public class World implements Iterable { private void updatePlayerInfos(Player paramPlayer) { for (Player player : getPlayers()) { - // Dont send packets if player is loading in and filter out joining player - if (!player.hasSentAvatarDataNotify() || player.getSceneLoadState().getValue() < SceneLoadState.INIT.getValue() || player == paramPlayer) { + // Dont send packets if player is logging in and filter out joining player + if (!player.hasSentAvatarDataNotify() || player == paramPlayer) { continue; } @@ -292,15 +292,18 @@ public class World implements Iterable { player.getTeamManager().getMpTeam().copyFrom(player.getTeamManager().getMpTeam(), player.getTeamManager().getMaxTeamSize()); player.getTeamManager().updateTeamEntities(null); } + + // Dont send packets if player is loading into the scene + if (player.getSceneLoadState().getValue() < SceneLoadState.INIT.getValue() ) { + // World player info packets + player.getSession().send(new PacketWorldPlayerInfoNotify(this)); + player.getSession().send(new PacketScenePlayerInfoNotify(this)); + player.getSession().send(new PacketWorldPlayerRTTNotify(this)); - // World player info packets - player.getSession().send(new PacketWorldPlayerInfoNotify(this)); - player.getSession().send(new PacketScenePlayerInfoNotify(this)); - player.getSession().send(new PacketWorldPlayerRTTNotify(this)); - - // Team packets - player.getSession().send(new PacketSyncTeamEntityNotify(player)); - player.getSession().send(new PacketSyncScenePlayTeamEntityNotify(player)); + // Team packets + player.getSession().send(new PacketSyncTeamEntityNotify(player)); + player.getSession().send(new PacketSyncScenePlayTeamEntityNotify(player)); + } } } From 8651cdd12b647211bd8577a1b5089a01eb052298 Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Thu, 21 Jul 2022 16:27:43 -0700 Subject: [PATCH 49/61] Rename `hasSentAvatarDataNotify()` to `hasSentLoginPackets()` --- .../emu/grasscutter/game/avatar/Avatar.java | 4 ++-- .../emu/grasscutter/game/player/Player.java | 18 +++++++----------- .../java/emu/grasscutter/game/world/World.java | 2 +- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/main/java/emu/grasscutter/game/avatar/Avatar.java b/src/main/java/emu/grasscutter/game/avatar/Avatar.java index b8adfdbd0..93e00a015 100644 --- a/src/main/java/emu/grasscutter/game/avatar/Avatar.java +++ b/src/main/java/emu/grasscutter/game/avatar/Avatar.java @@ -496,7 +496,7 @@ public class Avatar { item.setEquipCharacter(this.getAvatarId()); item.save(); - if (this.getPlayer().hasSentAvatarDataNotify()) { + if (this.getPlayer().hasSentLoginPackets()) { this.getPlayer().sendPacket(new PacketAvatarEquipChangeNotify(this, item)); } @@ -732,7 +732,7 @@ public class Avatar { this.setFightProperty(FightProperty.FIGHT_PROP_CUR_HP, this.getFightProperty(FightProperty.FIGHT_PROP_MAX_HP) * hpPercent); // Packet - if (getPlayer() != null && getPlayer().hasSentAvatarDataNotify()) { + if (getPlayer() != null && getPlayer().hasSentLoginPackets()) { // Update stats for client getPlayer().sendPacket(new PacketAvatarFightPropNotify(this)); // Update client abilities diff --git a/src/main/java/emu/grasscutter/game/player/Player.java b/src/main/java/emu/grasscutter/game/player/Player.java index 769e79012..b12fcf36b 100644 --- a/src/main/java/emu/grasscutter/game/player/Player.java +++ b/src/main/java/emu/grasscutter/game/player/Player.java @@ -170,7 +170,7 @@ public class Player { @Transient private boolean paused; @Transient private int enterSceneToken; @Transient private SceneLoadState sceneState; - @Transient private boolean hasSentAvatarDataNotify; + @Transient private boolean hasSentLoginPackets; @Transient private long nextSendPlayerLocTime = 0; private transient final Int2ObjectMap coopRequests; @@ -562,7 +562,7 @@ public class Player { } public boolean isFirstLoginEnterScene() { - return !this.hasSentAvatarDataNotify; + return !this.hasSentLoginPackets; } public TeamManager getTeamManager() { @@ -884,14 +884,10 @@ public class Player { this.godmode = godmode; } - public boolean hasSentAvatarDataNotify() { - return hasSentAvatarDataNotify; + public boolean hasSentLoginPackets() { + return hasSentLoginPackets; } - - public void setHasSentAvatarDataNotify(boolean hasSentAvatarDataNotify) { - this.hasSentAvatarDataNotify = hasSentAvatarDataNotify; - } - + public void addAvatar(Avatar avatar, boolean addToCurrentTeam) { boolean result = getAvatars().addAvatar(avatar); @@ -900,7 +896,7 @@ public class Player { getAvatars().addStartingWeapon(avatar); // Done - if (hasSentAvatarDataNotify()) { + if (hasSentLoginPackets()) { // Recalc stats avatar.recalcStats(); // Packet, show notice on left if the avatar will be added to the team @@ -1361,7 +1357,7 @@ public class Player { // First notify packets sent - this.setHasSentAvatarDataNotify(true); + this.hasSentLoginPackets = true; // Send server welcome chat. this.getServer().getChatManager().sendServerWelcomeMessages(this); diff --git a/src/main/java/emu/grasscutter/game/world/World.java b/src/main/java/emu/grasscutter/game/world/World.java index 04858e2a5..9d6b972fb 100644 --- a/src/main/java/emu/grasscutter/game/world/World.java +++ b/src/main/java/emu/grasscutter/game/world/World.java @@ -283,7 +283,7 @@ public class World implements Iterable { private void updatePlayerInfos(Player paramPlayer) { for (Player player : getPlayers()) { // Dont send packets if player is logging in and filter out joining player - if (!player.hasSentAvatarDataNotify() || player == paramPlayer) { + if (!player.hasSentLoginPackets() || player == paramPlayer) { continue; } From c0418067d6c2fc9e33ba54ca1770aa5b5e5a1e34 Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Thu, 21 Jul 2022 18:39:39 -0700 Subject: [PATCH 50/61] Add `kcpInterval` to the config --- src/main/java/emu/grasscutter/config/ConfigContainer.java | 8 +++++--- src/main/java/emu/grasscutter/server/game/GameServer.java | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/main/java/emu/grasscutter/config/ConfigContainer.java b/src/main/java/emu/grasscutter/config/ConfigContainer.java index 1817ddc2a..d6802ccd5 100644 --- a/src/main/java/emu/grasscutter/config/ConfigContainer.java +++ b/src/main/java/emu/grasscutter/config/ConfigContainer.java @@ -120,10 +120,10 @@ public class ConfigContainer { public static class HTTP { public String bindAddress = "0.0.0.0"; + public int bindPort = 443; + /* This is the address used in URLs. */ public String accessAddress = "127.0.0.1"; - - public int bindPort = 443; /* This is the port used in URLs. */ public int accessPort = 0; @@ -145,7 +145,9 @@ public class ConfigContainer { public int loadEntitiesForPlayerRange = 100; public boolean enableScriptInBigWorld = false; public boolean enableConsole = true; - + + /* Kcp internal work interval (milliseconds) */ + public int kcpInterval = 20; /* Controls whether packets should be logged in console or not */ public ServerDebugMode logPackets = ServerDebugMode.NONE; diff --git a/src/main/java/emu/grasscutter/server/game/GameServer.java b/src/main/java/emu/grasscutter/server/game/GameServer.java index 503992595..d5be5047d 100644 --- a/src/main/java/emu/grasscutter/server/game/GameServer.java +++ b/src/main/java/emu/grasscutter/server/game/GameServer.java @@ -83,7 +83,7 @@ public final class GameServer extends KcpServer { public GameServer(InetSocketAddress address) { ChannelConfig channelConfig = new ChannelConfig(); - channelConfig.nodelay(true, 20, 2, true); + channelConfig.nodelay(true, GAME_INFO.kcpInterval, 2, true); channelConfig.setMtu(1400); channelConfig.setSndwnd(256); channelConfig.setRcvwnd(256); From f15262dd3e869dd65c8b00bff22a8d4077deb084 Mon Sep 17 00:00:00 2001 From: Melledy <52122272+Melledy@users.noreply.github.com> Date: Fri, 22 Jul 2022 00:53:12 -0700 Subject: [PATCH 51/61] Refactor excel datas (Mainly item data) --- .../grasscutter/data/common/ItemUseData.java | 18 +- .../data/excels/AvatarSkillData.java | 17 -- .../grasscutter/data/excels/GadgetData.java | 8 - .../emu/grasscutter/data/excels/ItemData.java | 157 +++++++----------- .../data/excels/MonsterDescribeData.java | 5 - .../emu/grasscutter/game/avatar/Avatar.java | 2 +- .../game/battlepass/BattlePassManager.java | 5 +- .../game/combine/CombineManger.java | 5 +- .../game/inventory/MaterialType.java | 68 ++++---- .../game/managers/CookingManager.java | 5 +- .../game/managers/FurnitureManager.java | 10 +- .../game/managers/forging/ForgingManager.java | 5 +- .../emu/grasscutter/game/props/ItemUseOp.java | 72 ++++++++ .../grasscutter/game/props/ItemUseTarget.java | 36 ++++ .../game/systems/InventorySystem.java | 32 ++-- 15 files changed, 245 insertions(+), 200 deletions(-) create mode 100644 src/main/java/emu/grasscutter/game/props/ItemUseOp.java create mode 100644 src/main/java/emu/grasscutter/game/props/ItemUseTarget.java diff --git a/src/main/java/emu/grasscutter/data/common/ItemUseData.java b/src/main/java/emu/grasscutter/data/common/ItemUseData.java index 7f905c206..849bbb777 100644 --- a/src/main/java/emu/grasscutter/data/common/ItemUseData.java +++ b/src/main/java/emu/grasscutter/data/common/ItemUseData.java @@ -1,24 +1,16 @@ package emu.grasscutter.data.common; -import java.util.List; +import emu.grasscutter.game.props.ItemUseOp; public class ItemUseData { - private String useOp; - private List useParam; + private ItemUseOp useOp; + private String[] useParam; - public String getUseOp() { + public ItemUseOp getUseOp() { return useOp; } - public void setUseOp(String useOp) { - this.useOp = useOp; - } - - public List getUseParam() { + public String[] getUseParam() { return useParam; } - - public void setUseParam(List useParam) { - this.useParam = useParam; - } } diff --git a/src/main/java/emu/grasscutter/data/excels/AvatarSkillData.java b/src/main/java/emu/grasscutter/data/excels/AvatarSkillData.java index 76c56ef2e..ffdb93bbf 100644 --- a/src/main/java/emu/grasscutter/data/excels/AvatarSkillData.java +++ b/src/main/java/emu/grasscutter/data/excels/AvatarSkillData.java @@ -17,13 +17,8 @@ public class AvatarSkillData extends GameResource { private boolean isAttackCameraLock; private int proudSkillGroupId; private ElementType costElemType; - private List lockWeightParams; - private long nameTextMapHash; - private String abilityName; - private String lockShape; - private String globalValueKey; @Override public int getId(){ @@ -58,10 +53,6 @@ public class AvatarSkillData extends GameResource { return costElemType; } - public List getLockWeightParams() { - return lockWeightParams; - } - public long getNameTextMapHash() { return nameTextMapHash; } @@ -69,14 +60,6 @@ public class AvatarSkillData extends GameResource { public String getAbilityName() { return abilityName; } - - public String getLockShape() { - return lockShape; - } - - public String getGlobalValueKey() { - return globalValueKey; - } @Override public void onLoad() { diff --git a/src/main/java/emu/grasscutter/data/excels/GadgetData.java b/src/main/java/emu/grasscutter/data/excels/GadgetData.java index 2cd79f6c2..45724d381 100644 --- a/src/main/java/emu/grasscutter/data/excels/GadgetData.java +++ b/src/main/java/emu/grasscutter/data/excels/GadgetData.java @@ -13,10 +13,8 @@ public class GadgetData extends GameResource { private boolean isInteractive; private String[] tags; private String itemJsonName; - private String inteeIconName; private long nameTextMapHash; private int campID; - private String LODPatternName; @Override public int getId() { @@ -43,10 +41,6 @@ public class GadgetData extends GameResource { return itemJsonName; } - public String getInteeIconName() { - return inteeIconName; - } - public long getNameTextMapHash() { return nameTextMapHash; } @@ -55,8 +49,6 @@ public class GadgetData extends GameResource { return campID; } - public String getLODPatternName() { return LODPatternName; } - @Override public void onLoad() { diff --git a/src/main/java/emu/grasscutter/data/excels/ItemData.java b/src/main/java/emu/grasscutter/data/excels/ItemData.java index 6dc2643d9..ed8db17fb 100644 --- a/src/main/java/emu/grasscutter/data/excels/ItemData.java +++ b/src/main/java/emu/grasscutter/data/excels/ItemData.java @@ -1,5 +1,6 @@ package emu.grasscutter.data.excels; +import java.util.Arrays; import java.util.List; import com.google.gson.annotations.SerializedName; @@ -8,6 +9,7 @@ import emu.grasscutter.data.ResourceType; import emu.grasscutter.data.common.ItemUseData; import emu.grasscutter.game.inventory.*; import emu.grasscutter.game.props.FightProperty; +import emu.grasscutter.game.props.ItemUseTarget; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; import lombok.Getter; @@ -17,103 +19,75 @@ import lombok.Getter; "ReliquaryExcelConfigData.json", "HomeWorldFurnitureExcelConfigData.json" }) +@Getter public class ItemData extends GameResource { - + // Main private int id; - @Getter private int stackLimit = 1; - @Getter private int maxUseCount; - @Getter private int rankLevel; - @Getter private String effectName; - @Getter private int[] satiationParams; - @Getter private int rank; - @Getter private int weight; - @Getter private int gadgetId; + private int stackLimit = 1; + private int maxUseCount; + private int rankLevel; + private String effectName; + private int rank; + private int weight; + private int gadgetId; - @Getter private int[] destroyReturnMaterial; - @Getter private int[] destroyReturnMaterialCount; - - @Getter private List itemUse; + private int[] destroyReturnMaterial; + private int[] destroyReturnMaterialCount; - // Food - @Getter private String foodQuality; - @Getter private String useTarget; - private String[] iseParam; - - // String enums - private String itemType; - private String materialType; - private String equipType; + // Enums + private ItemType itemType = ItemType.ITEM_NONE; + private MaterialType materialType = MaterialType.MATERIAL_NONE; + private EquipType equipType = EquipType.EQUIP_NONE; private String effectType; private String destroyRule; - // Post load enum forms of above - private transient MaterialType materialEnumType; - private transient ItemType itemEnumType; - private transient EquipType equipEnumType; + // Food + private String foodQuality; + private int[] satiationParams; + + // Usable item + private ItemUseTarget useTarget; + private List itemUse; // Relic - @Getter private int mainPropDepotId; - @Getter private int appendPropDepotId; - @Getter private int appendPropNum; - @Getter private int setId; + private int mainPropDepotId; + private int appendPropDepotId; + private int appendPropNum; + private int setId; private int[] addPropLevels; - @Getter private int baseConvExp; - @Getter private int maxLevel; + private int baseConvExp; + private int maxLevel; // Weapon - @Getter private int weaponPromoteId; - @Getter private int weaponBaseExp; - @Getter private int storyId; - @Getter private int avatarPromoteId; - @Getter private int awakenMaterial; - @Getter private int[] awakenCosts; - @Getter private int[] skillAffix; + private int weaponPromoteId; + private int weaponBaseExp; + private int storyId; + private int avatarPromoteId; + private int awakenMaterial; + private int[] awakenCosts; + private int[] skillAffix; private WeaponProperty[] weaponProp; // Hash - @Getter private String icon; - @Getter private long nameTextMapHash; - - @Getter private IntSet addPropLevelSet; + private long nameTextMapHash; // Furniture - @Getter private int comfort; - @Getter private List furnType; - @Getter private List furnitureGadgetID; + private int comfort; + private List furnType; + private List furnitureGadgetID; @SerializedName("JFDLJGDFIGL") - @Getter private int roomSceneId; + private int roomSceneId; + + // Custom + private transient IntSet addPropLevelSet; @Override public int getId(){ return this.id; } - public String getMaterialTypeString(){ - return this.materialType; - } - - public String[] getUseParam(){ - return this.iseParam; - } - - public String getItemTypeString(){ - return this.itemType; - } - - public WeaponProperty[] getWeaponProperties() { - return weaponProp; - } - - public ItemType getItemType() { - return this.itemEnumType; - } - - public MaterialType getMaterialType() { - return this.materialEnumType; - } - - public EquipType getEquipType() { - return this.equipEnumType; + public WeaponProperty[] getWeaponProperties() { + return this.weaponProp; } public boolean canAddRelicProp(int level) { @@ -121,48 +95,37 @@ public class ItemData extends GameResource { } public boolean isEquip() { - return this.itemEnumType == ItemType.ITEM_RELIQUARY || this.itemEnumType == ItemType.ITEM_WEAPON; + return this.itemType == ItemType.ITEM_RELIQUARY || this.itemType == ItemType.ITEM_WEAPON; } @Override public void onLoad() { - this.itemEnumType = ItemType.getTypeByName(getItemTypeString()); - this.materialEnumType = MaterialType.getTypeByName(getMaterialTypeString()); - - if (this.itemEnumType == ItemType.ITEM_RELIQUARY) { - this.equipEnumType = EquipType.getTypeByName(this.equipType); + if (this.itemType == ItemType.ITEM_RELIQUARY) { if (this.addPropLevels != null && this.addPropLevels.length > 0) { this.addPropLevelSet = new IntOpenHashSet(this.addPropLevels); } - } else if (this.itemEnumType == ItemType.ITEM_WEAPON) { - this.equipEnumType = EquipType.EQUIP_WEAPON; + } else if (this.itemType == ItemType.ITEM_WEAPON) { + this.equipType = EquipType.EQUIP_WEAPON; } else { - this.equipEnumType = EquipType.EQUIP_NONE; + this.equipType = EquipType.EQUIP_NONE; } - if (this.getWeaponProperties() != null) { - for (WeaponProperty weaponProperty : this.getWeaponProperties()) { - weaponProperty.onLoad(); - } + if (this.weaponProp != null) { + this.weaponProp = Arrays.stream(this.weaponProp).filter(prop -> prop.getPropType() != null).toArray(WeaponProperty[]::new); } - if(this.getFurnType() != null){ + if (this.getFurnType() != null) { this.furnType = this.furnType.stream().filter(x -> x > 0).toList(); } - if(this.getFurnitureGadgetID() != null){ + if (this.getFurnitureGadgetID() != null) { this.furnitureGadgetID = this.furnitureGadgetID.stream().filter(x -> x > 0).toList(); } } + @Getter public static class WeaponProperty { - @Getter private FightProperty fightProp; - @Getter private String propType; - @Getter private float initValue; - @Getter private String type; - - public void onLoad() { - this.fightProp = FightProperty.getPropByName(propType); - } - + private FightProperty propType; + private float initValue; + private String type; } } diff --git a/src/main/java/emu/grasscutter/data/excels/MonsterDescribeData.java b/src/main/java/emu/grasscutter/data/excels/MonsterDescribeData.java index 9f6c81e25..2c1ea241e 100644 --- a/src/main/java/emu/grasscutter/data/excels/MonsterDescribeData.java +++ b/src/main/java/emu/grasscutter/data/excels/MonsterDescribeData.java @@ -10,7 +10,6 @@ public class MonsterDescribeData extends GameResource { private long nameTextMapHash; private int titleID; private int specialNameLabID; - private String icon; @Override public int getId() { @@ -29,10 +28,6 @@ public class MonsterDescribeData extends GameResource { return specialNameLabID; } - public String getIcon() { - return icon; - } - @Override public void onLoad() { diff --git a/src/main/java/emu/grasscutter/game/avatar/Avatar.java b/src/main/java/emu/grasscutter/game/avatar/Avatar.java index 93e00a015..5a42ce925 100644 --- a/src/main/java/emu/grasscutter/game/avatar/Avatar.java +++ b/src/main/java/emu/grasscutter/game/avatar/Avatar.java @@ -632,7 +632,7 @@ public class Avatar { WeaponCurveData curveData = GameData.getWeaponCurveDataMap().get(weapon.getLevel()); if (curveData != null) { for (WeaponProperty weaponProperty : weapon.getItemData().getWeaponProperties()) { - this.addFightProperty(weaponProperty.getFightProp(), weaponProperty.getInitValue() * curveData.getMultByProp(weaponProperty.getType())); + this.addFightProperty(weaponProperty.getPropType(), weaponProperty.getInitValue() * curveData.getMultByProp(weaponProperty.getType())); } } // Weapon promotion stats diff --git a/src/main/java/emu/grasscutter/game/battlepass/BattlePassManager.java b/src/main/java/emu/grasscutter/game/battlepass/BattlePassManager.java index ac5608503..b8ea0cca2 100644 --- a/src/main/java/emu/grasscutter/game/battlepass/BattlePassManager.java +++ b/src/main/java/emu/grasscutter/game/battlepass/BattlePassManager.java @@ -29,6 +29,7 @@ import emu.grasscutter.game.player.BasePlayerDataManager; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.BattlePassMissionRefreshType; import emu.grasscutter.game.props.BattlePassMissionStatus; +import emu.grasscutter.game.props.ItemUseOp; import emu.grasscutter.game.props.WatcherTriggerType; import emu.grasscutter.net.proto.BattlePassCycleOuterClass.BattlePassCycle; import emu.grasscutter.net.proto.BattlePassUnlockStatusOuterClass.BattlePassUnlockStatus; @@ -195,7 +196,7 @@ public class BattlePassManager extends BasePlayerDataManager { } // Get possible item choices. - String[] choices = rewardItemData.getItemUse().get(0).getUseParam().get(0).split(","); + String[] choices = rewardItemData.getItemUse().get(0).getUseParam()[0].split(","); if (choices.length < index) { return; } @@ -205,7 +206,7 @@ public class BattlePassManager extends BasePlayerDataManager { int chosenId = Integer.parseInt(choices[index - 1]); // For ITEM_USE_ADD_SELECT_ITEM chests, we can directly add the item specified in the chest's data. - if (rewardItemData.getItemUse().get(0).getUseOp().equals("ITEM_USE_ADD_SELECT_ITEM")) { + if (rewardItemData.getItemUse().get(0).getUseOp() == ItemUseOp.ITEM_USE_ADD_SELECT_ITEM) { GameItem rewardItem = new GameItem(GameData.getItemDataMap().get(chosenId), entry.getItemCount()); rewardItems.add(rewardItem); } diff --git a/src/main/java/emu/grasscutter/game/combine/CombineManger.java b/src/main/java/emu/grasscutter/game/combine/CombineManger.java index 90920abd1..4aaacb88a 100644 --- a/src/main/java/emu/grasscutter/game/combine/CombineManger.java +++ b/src/main/java/emu/grasscutter/game/combine/CombineManger.java @@ -10,6 +10,7 @@ import emu.grasscutter.game.inventory.Inventory; import emu.grasscutter.game.inventory.ItemType; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.ActionReason; +import emu.grasscutter.game.props.ItemUseOp; import emu.grasscutter.net.proto.RetcodeOuterClass; import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode; import emu.grasscutter.server.game.BaseGameSystem; @@ -55,12 +56,12 @@ public class CombineManger extends BaseGameSystem { public boolean unlockCombineDiagram(Player player, GameItem diagramItem) { // Make sure this is actually a diagram. - if (!diagramItem.getItemData().getItemUse().get(0).getUseOp().equals("ITEM_USE_UNLOCK_COMBINE")) { + if (diagramItem.getItemData().getItemUse().get(0).getUseOp() != ItemUseOp.ITEM_USE_UNLOCK_COMBINE) { return false; } // Determine the combine item we should unlock. - int combineId = Integer.parseInt(diagramItem.getItemData().getItemUse().get(0).getUseParam().get(0)); + int combineId = Integer.parseInt(diagramItem.getItemData().getItemUse().get(0).getUseParam()[0]); // Remove the diagram from the player's inventory. // We need to do this here, before sending CombineFormulaDataNotify, or the the combine UI won't correctly diff --git a/src/main/java/emu/grasscutter/game/inventory/MaterialType.java b/src/main/java/emu/grasscutter/game/inventory/MaterialType.java index e65cb09aa..097bc9e96 100644 --- a/src/main/java/emu/grasscutter/game/inventory/MaterialType.java +++ b/src/main/java/emu/grasscutter/game/inventory/MaterialType.java @@ -8,35 +8,45 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; public enum MaterialType { - MATERIAL_NONE (0), - MATERIAL_FOOD (1), - MATERIAL_QUEST (2), - MATERIAL_EXCHANGE (4), - MATERIAL_CONSUME (5), - MATERIAL_EXP_FRUIT (6), - MATERIAL_AVATAR (7), - MATERIAL_ADSORBATE (8), - MATERIAL_CRICKET (9), - MATERIAL_ELEM_CRYSTAL (10), - MATERIAL_WEAPON_EXP_STONE (11), - MATERIAL_CHEST (12), - MATERIAL_RELIQUARY_MATERIAL (13), - MATERIAL_AVATAR_MATERIAL (14), - MATERIAL_NOTICE_ADD_HP (15), - MATERIAL_SEA_LAMP (16), - MATERIAL_SELECTABLE_CHEST (17), - MATERIAL_FLYCLOAK (18), - MATERIAL_NAMECARD (19), - MATERIAL_TALENT (20), - MATERIAL_WIDGET (21), - MATERIAL_CHEST_BATCH_USE (22), - MATERIAL_FAKE_ABSORBATE (23), - MATERIAL_CONSUME_BATCH_USE (24), - MATERIAL_WOOD (25), - MATERIAL_FURNITURE_FORMULA (27), - MATERIAL_CHANNELLER_SLAB_BUFF (28), - MATERIAL_FURNITURE_SUITE_FORMULA (29), - MATERIAL_COSTUME (30); + MATERIAL_NONE (0), + MATERIAL_FOOD (1), + MATERIAL_QUEST (2), + MATERIAL_EXCHANGE (4), + MATERIAL_CONSUME (5), + MATERIAL_EXP_FRUIT (6), + MATERIAL_AVATAR (7), + MATERIAL_ADSORBATE (8), + MATERIAL_CRICKET (9), + MATERIAL_ELEM_CRYSTAL (10), + MATERIAL_WEAPON_EXP_STONE (11), + MATERIAL_CHEST (12), + MATERIAL_RELIQUARY_MATERIAL (13), + MATERIAL_AVATAR_MATERIAL (14), + MATERIAL_NOTICE_ADD_HP (15), + MATERIAL_SEA_LAMP (16), + MATERIAL_SELECTABLE_CHEST (17), + MATERIAL_FLYCLOAK (18), + MATERIAL_NAMECARD (19), + MATERIAL_TALENT (20), + MATERIAL_WIDGET (21), + MATERIAL_CHEST_BATCH_USE (22), + MATERIAL_FAKE_ABSORBATE (23), + MATERIAL_CONSUME_BATCH_USE (24), + MATERIAL_WOOD (25), + MATERIAL_FURNITURE_FORMULA (27), + MATERIAL_CHANNELLER_SLAB_BUFF (28), + MATERIAL_FURNITURE_SUITE_FORMULA (29), + MATERIAL_COSTUME (30), + MATERIAL_HOME_SEED (31), + MATERIAL_FISH_BAIT (32), + MATERIAL_FISH_ROD (33), + MATERIAL_SUMO_BUFF (34), + MATERIAL_FIREWORKS (35), + MATERIAL_BGM (36), + MATERIAL_SPICE_FOOD (37), + MATERIAL_ACTIVITY_ROBOT (38), + MATERIAL_ACTIVITY_GEAR (39), + MATERIAL_ACTIVITY_JIGSAW (40); private final int value; private static final Int2ObjectMap map = new Int2ObjectOpenHashMap<>(); diff --git a/src/main/java/emu/grasscutter/game/managers/CookingManager.java b/src/main/java/emu/grasscutter/game/managers/CookingManager.java index 4ede72403..f6abcd193 100644 --- a/src/main/java/emu/grasscutter/game/managers/CookingManager.java +++ b/src/main/java/emu/grasscutter/game/managers/CookingManager.java @@ -13,6 +13,7 @@ import emu.grasscutter.game.inventory.GameItem; import emu.grasscutter.game.player.BasePlayerManager; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.ActionReason; +import emu.grasscutter.game.props.ItemUseOp; import emu.grasscutter.net.proto.CookRecipeDataOuterClass; import emu.grasscutter.net.proto.PlayerCookArgsReqOuterClass.PlayerCookArgsReq; import emu.grasscutter.net.proto.PlayerCookReqOuterClass.PlayerCookReq; @@ -47,12 +48,12 @@ public class CookingManager extends BasePlayerManager { ********************/ public synchronized boolean unlockRecipe(GameItem recipeItem) { // Make sure this is actually a cooking recipe. - if (!recipeItem.getItemData().getItemUse().get(0).getUseOp().equals("ITEM_USE_UNLOCK_COOK_RECIPE")) { + if (recipeItem.getItemData().getItemUse().get(0).getUseOp() != ItemUseOp.ITEM_USE_UNLOCK_COOK_RECIPE) { return false; } // Determine the recipe we should unlock. - int recipeId = Integer.parseInt(recipeItem.getItemData().getItemUse().get(0).getUseParam().get(0)); + int recipeId = Integer.parseInt(recipeItem.getItemData().getItemUse().get(0).getUseParam()[0]); // Remove the item from the player's inventory. // We need to do this here, before sending CookRecipeDataNotify, or the the UI won't correctly update. diff --git a/src/main/java/emu/grasscutter/game/managers/FurnitureManager.java b/src/main/java/emu/grasscutter/game/managers/FurnitureManager.java index 38e2dcd7e..ce83e0289 100644 --- a/src/main/java/emu/grasscutter/game/managers/FurnitureManager.java +++ b/src/main/java/emu/grasscutter/game/managers/FurnitureManager.java @@ -6,6 +6,7 @@ import emu.grasscutter.game.home.FurnitureMakeSlotItem; import emu.grasscutter.game.inventory.GameItem; import emu.grasscutter.game.player.BasePlayerManager; import emu.grasscutter.game.player.Player; +import emu.grasscutter.game.props.ItemUseOp; import emu.grasscutter.net.proto.ItemParamOuterClass; import emu.grasscutter.net.proto.RetcodeOuterClass.Retcode; import emu.grasscutter.server.packet.send.*; @@ -34,18 +35,19 @@ public class FurnitureManager extends BasePlayerManager { } public synchronized boolean unlockFurnitureOrSuite(GameItem useItem) { + ItemUseOp itemUseOp = useItem.getItemData().getItemUse().get(0).getUseOp(); + // Check - if (!List.of("ITEM_USE_UNLOCK_FURNITURE_FORMULA", "ITEM_USE_UNLOCK_FURNITURE_SUITE") - .contains(useItem.getItemData().getItemUse().get(0).getUseOp())) { + if (itemUseOp != ItemUseOp.ITEM_USE_UNLOCK_FURNITURE_SUITE && itemUseOp != ItemUseOp.ITEM_USE_UNLOCK_FURNITURE_FORMULA) { return false; } - int furnitureIdOrSuiteId = Integer.parseInt(useItem.getItemData().getItemUse().get(0).getUseParam().get(0)); + int furnitureIdOrSuiteId = Integer.parseInt(useItem.getItemData().getItemUse().get(0).getUseParam()[0]); // Remove first player.getInventory().removeItem(useItem, 1); - if ("ITEM_USE_UNLOCK_FURNITURE_FORMULA".equals(useItem.getItemData().getItemUse().get(0).getUseOp())) { + if (useItem.getItemData().getItemUse().get(0).getUseOp() == ItemUseOp.ITEM_USE_UNLOCK_FURNITURE_FORMULA) { player.getUnlockedFurniture().add(furnitureIdOrSuiteId); notifyUnlockFurniture(); }else { diff --git a/src/main/java/emu/grasscutter/game/managers/forging/ForgingManager.java b/src/main/java/emu/grasscutter/game/managers/forging/ForgingManager.java index 50aeb94a8..f597a1b2a 100644 --- a/src/main/java/emu/grasscutter/game/managers/forging/ForgingManager.java +++ b/src/main/java/emu/grasscutter/game/managers/forging/ForgingManager.java @@ -14,6 +14,7 @@ import emu.grasscutter.game.inventory.GameItem; import emu.grasscutter.game.player.BasePlayerManager; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.ActionReason; +import emu.grasscutter.game.props.ItemUseOp; import emu.grasscutter.game.props.WatcherTriggerType; import emu.grasscutter.net.proto.ForgeQueueDataOuterClass.ForgeQueueData; import emu.grasscutter.net.proto.ForgeQueueManipulateReqOuterClass.ForgeQueueManipulateReq; @@ -39,12 +40,12 @@ public class ForgingManager extends BasePlayerManager { **********/ public synchronized boolean unlockForgingBlueprint(GameItem blueprintItem) { // Make sure this is actually a forging blueprint. - if (!blueprintItem.getItemData().getItemUse().get(0).getUseOp().equals("ITEM_USE_UNLOCK_FORGE")) { + if (blueprintItem.getItemData().getItemUse().get(0).getUseOp() != ItemUseOp.ITEM_USE_UNLOCK_FORGE) { return false; } // Determine the forging item we should unlock. - int forgeId = Integer.parseInt(blueprintItem.getItemData().getItemUse().get(0).getUseParam().get(0)); + int forgeId = Integer.parseInt(blueprintItem.getItemData().getItemUse().get(0).getUseParam()[0]); // Remove the blueprint from the player's inventory. // We need to do this here, before sending ForgeFormulaDataNotify, or the the forging UI won't correctly diff --git a/src/main/java/emu/grasscutter/game/props/ItemUseOp.java b/src/main/java/emu/grasscutter/game/props/ItemUseOp.java new file mode 100644 index 000000000..bae01cf15 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/props/ItemUseOp.java @@ -0,0 +1,72 @@ +package emu.grasscutter.game.props; + +import java.util.stream.Stream; + +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; + +public enum ItemUseOp { + ITEM_USE_NONE (0), + ITEM_USE_ACCEPT_QUEST (1), + ITEM_USE_TRIGGER_ABILITY (2), + ITEM_USE_GAIN_AVATAR (3), + ITEM_USE_ADD_EXP (4), + ITEM_USE_RELIVE_AVATAR (5), + ITEM_USE_ADD_BIG_TALENT_POINT (6), + ITEM_USE_ADD_PERSIST_STAMINA (7), + ITEM_USE_ADD_TEMPORARY_STAMINA (8), + ITEM_USE_ADD_CUR_STAMINA (9), + ITEM_USE_ADD_CUR_HP (10), + ITEM_USE_ADD_ELEM_ENERGY (11), + ITEM_USE_ADD_ALL_ENERGY (12), + ITEM_USE_ADD_DUNGEON_COND_TIME (13), + ITEM_USE_ADD_WEAPON_EXP (14), + ITEM_USE_ADD_SERVER_BUFF (15), + ITEM_USE_DEL_SERVER_BUFF (16), + ITEM_USE_UNLOCK_COOK_RECIPE (17), + ITEM_USE_OPEN_RANDOM_CHEST (20), + ITEM_USE_MAKE_GADGET (24), + ITEM_USE_ADD_ITEM (25), + ITEM_USE_GRANT_SELECT_REWARD (26), + ITEM_USE_ADD_SELECT_ITEM (27), + ITEM_USE_GAIN_FLYCLOAK (28), + ITEM_USE_GAIN_NAME_CARD (29), + ITEM_USE_UNLOCK_PAID_BATTLE_PASS_NORMAL (30), + ITEM_USE_GAIN_CARD_PRODUCT (31), + ITEM_USE_UNLOCK_FORGE (32), + ITEM_USE_UNLOCK_COMBINE (33), + ITEM_USE_UNLOCK_CODEX (34), + ITEM_USE_CHEST_SELECT_ITEM (35), + ITEM_USE_GAIN_RESIN_CARD_PRODUCT (36), + ITEM_USE_ADD_RELIQUARY_EXP (37), + ITEM_USE_UNLOCK_FURNITURE_FORMULA (38), + ITEM_USE_UNLOCK_FURNITURE_SUITE (39), + ITEM_USE_ADD_CHANNELLER_SLAB_BUFF (40), + ITEM_USE_GAIN_COSTUME (41), + ITEM_USE_ADD_TREASURE_MAP_BONUS_REGION_FRAGMENT (42), + ITEM_USE_COMBINE_ITEM (43), + ITEM_USE_UNLOCK_HOME_MODULE (44), + ITEM_USE_UNLOCK_HOME_BGM (45), + ITEM_USE_ADD_REGIONAL_PLAY_VAR (46); + + private final int value; + private static final Int2ObjectMap map = new Int2ObjectOpenHashMap<>(); + + static { + Stream.of(values()).forEach(e -> { + map.put(e.getValue(), e); + }); + } + + private ItemUseOp(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + public static ItemUseOp getTypeByValue(int value) { + return map.getOrDefault(value, ITEM_USE_NONE); + } +} diff --git a/src/main/java/emu/grasscutter/game/props/ItemUseTarget.java b/src/main/java/emu/grasscutter/game/props/ItemUseTarget.java new file mode 100644 index 000000000..0d1744163 --- /dev/null +++ b/src/main/java/emu/grasscutter/game/props/ItemUseTarget.java @@ -0,0 +1,36 @@ +package emu.grasscutter.game.props; + +import java.util.stream.Stream; + +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; + +public enum ItemUseTarget { + ITEM_USE_TARGET_NONE (0), + ITEM_USE_TARGET_CUR_AVATAR (1), + ITEM_USE_TARGET_CUR_TEAM (2), + ITEM_USE_TARGET_SPECIFY_AVATAR (3), + ITEM_USE_TARGET_SPECIFY_ALIVE_AVATAR (4), + ITEM_USE_TARGET_SPECIFY_DEAD_AVATAR (5); + + private final int value; + private static final Int2ObjectMap map = new Int2ObjectOpenHashMap<>(); + + static { + Stream.of(values()).forEach(e -> { + map.put(e.getValue(), e); + }); + } + + private ItemUseTarget(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + + public static ItemUseTarget getTypeByValue(int value) { + return map.getOrDefault(value, ITEM_USE_TARGET_NONE); + } +} diff --git a/src/main/java/emu/grasscutter/game/systems/InventorySystem.java b/src/main/java/emu/grasscutter/game/systems/InventorySystem.java index 2f7a0614b..2ad11f707 100644 --- a/src/main/java/emu/grasscutter/game/systems/InventorySystem.java +++ b/src/main/java/emu/grasscutter/game/systems/InventorySystem.java @@ -23,6 +23,8 @@ import emu.grasscutter.game.inventory.GameItem; import emu.grasscutter.game.inventory.ItemType; import emu.grasscutter.game.player.Player; import emu.grasscutter.game.props.ActionReason; +import emu.grasscutter.game.props.ItemUseOp; +import emu.grasscutter.game.props.ItemUseTarget; import emu.grasscutter.game.shop.ShopChestBatchUseTable; import emu.grasscutter.game.shop.ShopChestTable; import emu.grasscutter.net.proto.ItemParamOuterClass.ItemParam; @@ -813,7 +815,7 @@ public class InventorySystem extends BaseGameSystem { // Use switch (useItem.getItemData().getMaterialType()) { case MATERIAL_FOOD: - if (useItem.getItemData().getUseTarget().equals("ITEM_USE_TARGET_SPECIFY_DEAD_AVATAR")) { + if (useItem.getItemData().getUseTarget() == ItemUseTarget.ITEM_USE_TARGET_SPECIFY_DEAD_AVATAR) { if (target == null) { break; } @@ -822,7 +824,7 @@ public class InventorySystem extends BaseGameSystem { } break; case MATERIAL_NOTICE_ADD_HP: - if (useItem.getItemData().getUseTarget().equals("ITEM_USE_TARGET_SPECIFY_ALIVE_AVATAR")) { + if (useItem.getItemData().getUseTarget() == ItemUseTarget.ITEM_USE_TARGET_SPECIFY_ALIVE_AVATAR) { if (target == null) { break; } @@ -836,22 +838,16 @@ public class InventorySystem extends BaseGameSystem { if (useItem.getItemData().getItemUse() == null) { break; } - - // Handle forging blueprints. - if (useItem.getItemData().getItemUse().get(0).getUseOp().equals("ITEM_USE_UNLOCK_FORGE")) { - // Unlock. - useSuccess = player.getForgingManager().unlockForgingBlueprint(useItem); - } - // Handle combine diagrams. - if (useItem.getItemData().getItemUse().get(0).getUseOp().equals("ITEM_USE_UNLOCK_COMBINE")) { - // Unlock. - useSuccess = player.getServer().getCombineSystem().unlockCombineDiagram(player, useItem); - } - // Handle cooking recipies. - if (useItem.getItemData().getItemUse().get(0).getUseOp().equals("ITEM_USE_UNLOCK_COOK_RECIPE")) { - // Unlock. - useSuccess = player.getCookingManager().unlockRecipe(useItem); - } + + ItemUseOp useOp = useItem.getItemData().getItemUse().get(0).getUseOp(); + + // Unlock item based on use operation + useSuccess = switch (useOp) { + case ITEM_USE_UNLOCK_FORGE -> player.getForgingManager().unlockForgingBlueprint(useItem); + case ITEM_USE_UNLOCK_COMBINE -> player.getServer().getCombineSystem().unlockCombineDiagram(player, useItem); + case ITEM_USE_UNLOCK_COOK_RECIPE -> player.getCookingManager().unlockRecipe(useItem); + default -> useSuccess; + }; break; case MATERIAL_FURNITURE_FORMULA: case MATERIAL_FURNITURE_SUITE_FORMULA: From e9464784bb6a5fd0ac44837141b51117b21f0674 Mon Sep 17 00:00:00 2001 From: Miralyn <41351810+Miralyn@users.noreply.github.com> Date: Fri, 22 Jul 2022 19:17:58 +1000 Subject: [PATCH 52/61] Updated Russian localization (#1543) * updated russian localization * Update ru-RU.json --- src/main/resources/languages/ru-RU.json | 240 ++++++++++++------------ 1 file changed, 120 insertions(+), 120 deletions(-) diff --git a/src/main/resources/languages/ru-RU.json b/src/main/resources/languages/ru-RU.json index 91cf5cf26..667723308 100644 --- a/src/main/resources/languages/ru-RU.json +++ b/src/main/resources/languages/ru-RU.json @@ -3,13 +3,13 @@ "game": { "port_bind": "Игровой сервер запущен на порте %s", "connect": "Клиент подключился с %s", - "disconnect": "Клиент подключился с %s", + "disconnect": "Клиент отсоединился с %s", "game_update_error": "Произошла ошибка при обновлении игры.", "command_error": "Командная ошибка:" }, "dispatch": { "port_bind": "[Dispatch] Распределительный сервер запущен на порте %s", - "request": "🇺🇸[Dispatch] Client %s %s request: %s", + "request": "[Dispatch] Клиент %s %s, запрос: %s", "keystore": { "general_error": "[Dispatch] Возникла ошибка при загрузке keystore!", "password_error": "[Dispatch] Не удалось загрузить keystore. Пытаемся использовать пароль для keystore по умолчанию...", @@ -17,7 +17,7 @@ "default_password": "[Dispatch] Пароль keystore по умолчанию был успешно загружен. Установите пароль 123456 в config.json." }, "authentication": { - "default_unable_to_verify": "[Авторизация] Произошел вызов метода verifyUser, который недоступен в стандартном обработчике авторизации." + "default_unable_to_verify": "[Authentication] Произошел вызов метода verifyUser, который недоступен в стандартном обработчике авторизации.." }, "no_commands_error": "Команды не доступны в режиме \"dispatch only\".", "unhandled_request_error": "[Dispatch] Возможный необработанный запрос %s: %s.", @@ -28,40 +28,40 @@ "login_token_attempt": "[Dispatch] Клиент %s пытается войти с помощью токена.", "login_token_error": "[Dispatch] Клиент %s не смог войти с помощью токена.", "login_token_success": "[Dispatch] Клиент %s вошел с помощью токена как %s.", - "login_password_error": "🇺🇸[Dispatch] Client %s failed to log in via password.", - "login_password_storage_error": "🇺🇸[Dispatch] Client %s failed to log in via password because there is no password in the database.", - "combo_token_success": "🇺🇸[Dispatch] Client %s succeed to exchange combo token.", - "combo_token_error": "🇺🇸[Dispatch] Client %s failed to exchange combo token.", + "login_password_error": "[Dispatch] Клиент %s не смог войти с помощью пароля.", + "login_password_storage_error": "[Dispatch] Клиенту %s не удалось войти с помощью пароля по причине отсутствия пароля в базе данных.", + "combo_token_success": "[Dispatch] Клиент %s произвёл успешный обмен комбинированного токена.", + "combo_token_error": "[Dispatch] Клиенту %s не удалось произвести обмен комбинированного токена.", "account_login_create_success": "[Dispatch] Клиенту %s не удалось войти по причине: Аккаунт %s был создан.", - "account_login_create_error": "[Dispatch] Клиенту %s не удалось войти по причне : Не удалось создать аккаунт.", + "account_login_create_error": "[Dispatch] Клиенту %s не удалось войти по причине: Не удалось создать аккаунт.", "account_login_exist_error": "[Dispatch] Клиенту %s не удалось войти по причине: Аккаунт не найден.", - "account_cache_error": "🇺🇸Game account cache information error.", + "account_cache_error": "Ошибка кэша игрового аккаунта.", "session_key_error": "Некорректный ключ сессии.", "username_error": "Имя пользователя не обнаружено.", - "username_create_error": "Имя пользователя не найденоUsername not found, создание не удалось.", - "password_error": "🇺🇸Invalid Password", - "password_length_error": "🇺🇸Password length must be greater then or equal to 8", - "password_storage_error": "🇺🇸You don't have a password for your account. Please contact an administrator.", + "username_create_error": "Имя пользователя не найдено, создание не удалось.", + "password_error": "Некорректный пароль", + "password_length_error": "Длина пароля должна быть не менее 8 символов", + "password_storage_error": "У вашего аккаунта отсутствует пароль. Свяжитесь с администратором.", "server_max_player_limit": "Число игроков в сети достигло предела" }, - "router_error": "🇺🇸[Dispatch] Unable to attach router." + "router_error": "[Dispatch] Не удалось присоединить маршрутизатор." }, "status": { - "free_software": "Grasscutter является БЕСПЛАТНЫМ программным обеспечением. Если вы заплатили за него деньги, то вас обманули. Домашняя страница проекта: https://github.com/Grasscutters/Grasscutter", + "free_software": "Grasscutter является БЕСПЛАТНЫМ программным обеспечением. Если вы заплатили за него деньги, то вы были обмануты продавцом. Домашняя страница проекта: https://github.com/Grasscutters/Grasscutter", "starting": "Запускаем Grasscutter...", "shutdown": "Отключаемся...", "done": "Готово! Для получения помощи, введите \"help\"", "error": "Произошла ошибка.", "welcome": "Добро пожаловать в Grasscutter!", - "run_mode_error": "Некорректный режим запуска сервера: %s.", - "run_mode_help": "Сервер должен запускаться в одном из следующих режимов: 'HYBRID', 'DISPATCH_ONLY', или 'GAME_ONLY'. Не удалось запустить Grasscutter...", + "run_mode_error": "Некорректный режим работы сервера: %s.", + "run_mode_help": "Сервер должен запускаться в одном из следующих режимов: 'HYBRID', 'DISPATCH_ONLY' или 'GAME_ONLY'. Не удалось запустить Grasscutter...", "create_resources": "Создаём папку ресурсов...", - "resources_error": "Поместите копию папок 'BinOutput' и 'ExcelBinOutput' в папку ресурсов.", + "resources_error": "Поместите копии папок 'BinOutput' и 'ExcelBinOutput' в папку ресурсов.", "version": "Версия Grasscutter: %s-%s", "game_version": "Версия игры: %s", "resources": { - "loading": "🇺🇸Loading resources...", - "finish": "🇺🇸Finished loading resources." + "loading": "Загружаем ресурсы...", + "finish": "Загрузка ресурсов завершена." } } }, @@ -76,18 +76,18 @@ "no_usage_specified": "Применение команды не указано", "no_description_specified": "Описание отсутствует", "set_to": "Характеристика %s стала равной %s.", - "set_for_to": "Характеристика %s игрока %s стала равной %s.", + "set_for_to": "Характеристика %s у %s стала равной %s.", "invalid": { "amount": "Некорректное количество.", "artifactId": "Некорректный ID артефакта.", - "avatarId": "Некорректный ID аватара.", - "avatarLevel": "Некорректный уровень аватара (avatarLevel).", + "avatarId": "Некорректный ID персонажа.", + "avatarLevel": "Некорректный уровень персонажа (avatarLevel).", "entityId": "Некорректный ID сущности.", "itemId": "Некорректный ID предмета.", "itemLevel": "Некорректный уровень предмета (itemLevel).", - "itemRefinement": "Некорректный уровень пробуждения предмета (itemRefinement).", + "itemRefinement": "Некорректный ранг пробуждения предмета (itemRefinement).", "statValue": "Некорректное значение характеристики.", - "value_between": "🇺🇸Invalid value: %s must be between %s and %s.", + "value_between": "Некорректное значение: %s находится в пределах от %s до %s.", "playerId": "Некорректный ID игрока.", "uid": "Некорректный UID.", "id": "Некорректный ID." @@ -101,9 +101,9 @@ "argument_error": "Некорректные аргументы.", "clear_target": "Цель была удалена.", "set_target": "Все последующие команды будут использовать @%s в качестве цели по умолчанию.", - "set_target_online": "@%s сейчас в сети. Для некоторых команд, цель должна быть не в сети.", - "set_target_offline": "@%s сейчас не в сети. Для некоторых команд, цель должна быть в сети.", - "need_target": "Этой команде требуется UID цели. Добавьте аргумент <@UID> или задайте постоянную цель с помощью /target @UID.", + "set_target_online": "@%s сейчас находится в сети. Для некоторых команд, цель должна быть не в сети.", + "set_target_offline": "@%s сейчас находится не в сети. Для некоторых команд, цель должна быть в сети.", + "need_target": "Для данной команды требуется UID цели. Добавьте аргумент <@UID> или задайте постоянную цель с помощью /target @UID.", "need_target_online": "Для данной команды требуется UID цели, находящейся в сети, а выбранная цель сейчас не в сети. Введите другой аргумент <@UID> или добавьте постоянную цель с помощью /target @UID.", "need_target_offline": "Для данной команды требуется UID цели, находящейся не в сети, а выбранная цель сейчас в сети. Введите другой аргумент <@UID> или добавьте постоянную цель с помощью /target @UID." }, @@ -117,34 +117,34 @@ "command_usage": "Применение: account <имя_пользователя> [UID]", "invalid": "Некорректный UID.", "exists": "Аккаунт с таким именем пользователя и/или UID уже существует.", - "create": "Создан аккаунт с UID %s.", + "create": "Аккаунт с UID %s был создан.", "delete": "Аккаунт удалён.", "no_account": "Аккаунт не найден.", - "description": "Изменяет аккаунт пользователя" + "description": "Вносит изменения в аккаунты пользователей" }, "announce": { - "command_usage": "🇺🇸Usage: announce|a <\"tpl\" templateId|\"refresh\"|\"revoke\" templateId|content>", - "send_success": "🇺🇸Send an announcement successfully, you can revoke it by /a revoke %s.", - "refresh_success": "🇺🇸Refresh announcement config file successfully. [Total %s]", - "revoke_done": "🇺🇸Try to revoke announcement %s.", - "not_found": "🇺🇸Could not found announcement %s.", - "description": "🇺🇸Send announcement to all online players, or manage server's announcement" + "command_usage": "Применение: announce|a <\"tpl\" templateId|\"refresh\"|\"revoke\" templateId|content>", + "send_success": "Объявление было отправлено успешно, вы можете отзвать его с помощью команды /a revoke %s.", + "refresh_success": "Конфигурационный файл объявления был успешно обновлён. [Всего %s]", + "revoke_done": "Пытаемся отозвать объявление %s.", + "not_found": "Объявление %s не было найдено.", + "description": "Показывает объявление всем игрокам в сети и позволяет управлять серверными объявлениями" }, "clear": { - "command_usage": "Применение: clear [lv] [r] [*]", + "command_usage": "Применение: clear [lv<макс_уровень>] [r<макс_пробуждение>] [<макс_редкость>*]", "weapons": "Удалены оружия у %s.", "artifacts": "Удалены артефакты у %s.", "materials": "Удалены материалы у %s.", "furniture": "Удалена мебель у %s.", - "displays": "🇺🇸Cleared displays for %s.", - "virtuals": "🇺🇸Cleared virtuals for %s.", + "displays": "Удалены дисплеи у %s.", + "virtuals": "Удалены виртуалы у %s.", "everything": "Удалено всё у %s.", - "description": "Удаляет все неэкипированные на данный момент предметы из инвентаря, включая предметы золотой редкости" + "description": "Удаляет все доступные неэкипированные предметы из вашего инвентаря. По умолчанию удаляет 4* предметы 1-го уровня предмета 1-го ранга пробуждения и ниже, однако, возможно задать более высокие параметры." }, "coop": { - "usage": "Применение: coop [UID хоста]", + "usage": "Применение: coop [UID_хоста]", "success": "Игрок %s был призван в мир %s.", - "description": "Принудительно присоединяет кого-то к миру другого человека. Если не выбрана цель, то вы всё равно войдете в совместный режим." + "description": "Принудительно присоединяет к мирам других людей. Если цель не была выбрана, то отправляет в совместный режим." }, "enter_dungeon": { "usage": "Применение: enterdungeon ", @@ -154,15 +154,15 @@ "description": "Позволяет войти в подземелье" }, "give": { - "usage": "Применение: give <игрок> [кол-во] [уровень] [пробуждение]", - "usage_relic": "🇺🇸Usage: give [mainPropID] [[,]]... [lv]", - "illegal_relic": "🇺🇸This artifactID belongs to a blacklisted range, it may not be the one you wanted.", + "usage": "Применение: give [x<кол-во>] [lv<уровень>] [r<пробуждение>]", + "usage_relic": "Применение: give [ID_глав_хар-ки] [[,<раз>]]... [lv<уровень 0-20>]", + "illegal_relic": "Данный ID_артефакта находится в черном списке. Возможно, это не то, что вы хотите получить.", "given": "Выдано %s %s игроку %s.", - "given_with_level_and_refinement": "Выдано %s с уровнем %s, уровнем пробуждения %s %s раз игроку %s.", - "given_level": "Выдано %s с уровнем %s %s раз игроку %s.", - "given_avatar": "🇺🇸Given %s with level %s to %s.", - "giveall_success": "🇺🇸Successfully gave all items.", - "description": "Выдаёт предмет лично вам или заданному игроку" + "given_with_level_and_refinement": "Выдано %s с уровнем предмета %s, рангом пробуждения %s %s раз игроку %s.", + "given_level": "Выдано %s с уровнем предмета %s %s раз игроку %s.", + "given_avatar": "Выдано %s с уровнем предмета %s игроку %s.", + "giveall_success": "Успешно были выданы все возможные предметы.", + "description": "Выдаёт предмет вам или указанному игроку. С помощью данной команды также возможно выдать любое оружие (опция \"weapons\"), персонажа (опция \"avatars\") и/или материал (опция \"mats\"). Также, с помощью этой команды можно вручную создавать артефакты." }, "heal": { "success": "Все персонажи были вылечены.", @@ -172,130 +172,130 @@ "usage": "Применение: ", "aliases": "Альтернативные названия: ", "available_commands": "Доступные команды: ", - "tip_need_permission": "🇺🇸Permission: ", - "tip_need_no_permission": "🇺🇸 None", - "tip_permission_targeted": "🇺🇸 (Permission %s is also required to use on other players)", - "warn_player_has_no_permission": "🇺🇸Notice: You do not have permission to run this command.", - "description": "Отправляет сообщение с помощью или показывает информацию о заданной команде" + "tip_need_permission": "Разрешения: ", + "tip_need_no_permission": " Не требуются", + "tip_permission_targeted": " (Требуется разрешение %s для применения на других игроках)", + "warn_player_has_no_permission": "Заметка: У вас нет разрешения на запуск этой команды.", + "description": "Отправляет сообщение с помощью или показывает информацию об указанной команде" }, "kick": { - "player_kick_player": "Игрок [%s:%s] кикнул игрока [%s:%s]", - "server_kick_player": "Кикаем игрока [%s:%s]...", - "description": "Кикает указанного игрока с сервера (WIP)" + "player_kick_player": "Игрок [%s:%s] выгнал игрока [%s:%s]", + "server_kick_player": "Выгоняем игрока [%s:%s]...", + "description": "Выгоняет (\"кикает\") указанного игрока с сервера (WIP)" }, "killall": { - "usage": "Применение: killall [playerUID] [sceneID]", + "usage": "Применение: killall [UID_игрока] [ID_сцены]", "scene_not_found_in_player_world": "В мире игрока не была обнаружена эта сцена.", "kill_monsters_in_scene": "Убиваем %s монстров в сцене %s.", - "description": "Убивает все сущности" + "description": "Убивает всех существ в сцене" }, "killCharacter": { - "usage": "Применение: killcharacter [playerID]", - "success": "Убит текущий персонаж игрока %s.", + "usage": "Применение: killcharacter [ID_игрока]", + "success": "Текущий персонаж игрока %s был убит.", "description": "Убивает текущего персонажа игрока" }, "language": { "current_language": "Текущий язык: %s.", - "language_changed": "Язык изменен на: %s.", + "language_changed": "Язык изменён на %s.", "language_not_found": "На текущий момент, на сервере недоступен этот язык.", "description": "Отображает или изменяет текущий язык" }, "list": { "success": "Сейчас в сети %s игрок(ов):", - "description": "Список игроков в сети" + "description": "Отображает всех игроков, находящихся в сети" }, "permission": { "usage": "Применение: permission <имя_пользователя> <разрешение>", - "add": "Разрешение добавлено.", + "add": "Разрешение было добавлено.", "has_error": "У данного пользователя уже имеется это разрешение!", "remove": "Разрешение удалено.", "not_have_error": "У данного пользователя отсутствует данное разрешение!", "account_error": "Аккаунт не найден.", - "description": "Добавляет или удаляет разрешения у пользователя" + "description": "Добавляет (add) или удаляет (remove) разрешения у пользователя" }, "position": { "success": "Координаты: %s, %s, %s\nID сцены: %s", - "description": "Показывает координаты" + "description": "Позволяет получить координаты" }, "quest": { - "usage": "quest [ID_квеста]", + "usage": "Применение: quest [ID_квеста]", "added": "Квест %s был добавлен.", "finished": "Квест %s был завершен.", "not_found": "Квест не найден.", - "invalid_id": "Неизвестный ID квеста.", - "description": "Добавляет или завершает квесты" + "invalid_id": "Некорректный ID квеста.", + "description": "Добавляет (add) или завершает (finish) квесты" }, "reload": { "reload_start": "Перезагружаем файл конфигурации.", "reload_done": "Перезагрузка завершена.", - "description": "Перезагружает конфигурационный файл сервера" + "description": "Перезагружает файл конфигурации сервера" }, "resetConst": { - "reset_all": "Сбросить созвездия всех аватаров.", - "success": "Созвездия %s были сброшены. Перезайдите в игру для вступления изменений в силу.", - "description": "Сбрасывает уровень созвездий активных в данный момент персонажей. Для вступления изменений в силу, после ввода команды необходимо перезайти в игру" + "reset_all": "Сбросить созвездия всех персонажей.", + "success": "Созвездия %s были сброшены. Перезайдите в игру, чтобы увидеть изменения.", + "description": "Сбрасывает уровень созвездия у активного персонажа. Для вступления изменений в силу, после ввода команды необходимо перезайти в игру" }, "resetShopLimit": { "usage": "Применение: resetshop ", - "success": "Сброс выполнен успешно.", + "success": "Сброс был выполнен успешно.", "description": "Сбрасывает таймер обновления магазина у выбранного игрока" }, "sendMail": { "usage": "Применение: sendmail [ID_шаблона]", "user_not_exist": "Пользователь с ID '%s' не найден.", - "start_composition": "Начинаем создание письма.\nВведите '/sendmail <заголовок>' для того, чтобы продолжить.\nВ любой момент времени, вы можете прекратить писать письмо, введя '/sendmail stop'.", - "templates": "Шаблоны писем скоро будут реализованы...", + "start_composition": "Начинаем создание письма.\nВведите '/sendmail <заголовок>' для того, чтобы продолжить.\nВ любой момент времени вы можете прекратить писать это письмо путём ввода '/sendmail stop'.", + "templates": "Шаблоны писем будут реализованы в будущем...", "invalid_arguments": "Некорректные аргументы.", "send_cancel": "Отправление сообщения было отменено.", "send_done": "Сообщение было отправлено пользователю %s!", "send_all_done": "Сообщение было отправлено всем пользователям!", - "not_composition_end": "Составление письма еще не было завершено.\nВведите '/sendmail %s' для продолжения или '/sendmail stop' для отмены", + "not_composition_end": "Составление письма еще не было завершено.\nВведите '/sendmail %s' для того, чтобы продолжить, либо '/sendmail stop' для отмены", "please_use": "Пожалуйста, введите '/sendmail %s'", "set_title": "Был задан следующий заголовок: '%s'.\nВведите '/sendmail <содержание>' для того, чтобы продолжить.", "set_contents": "Было задано следующее содержание письма: '%s'.\nВведите '/sendmail <отправитель>' для того, чтобы продолжить.", - "set_message_sender": "Был задан следующий отправитель письма: '%s'.\nВведите '/sendmail [кол-во] [уровень]' для того, чтобы продолжить.", - "send": "Было задано следующее вложение: %s %s (%s уровня).\nВы можете продолжить добавлять предметы или ввести '/sendmail finish' для того, чтобы отправить письмо.", + "set_message_sender": "Был задан следующий отправитель письма: '%s'.\nВведите '/sendmail [кол-во] [уровень]' для того, чтобы продолжить", + "send": "Было задано следующее вложение: %s %s (%s уровня)\nВы можете продолжить добавлять предметы или ввести '/sendmail finish' для того, чтобы отправить письмо.", "invalid_arguments_please_use": "Некорректные аргументы.\n Пожалуйста, введите '/sendmail %s'", "title": "<заголовок>", "message": "<содержание>", "sender": "<отправитель>", "arguments": " [кол-во] [уровень]", "error": "ОШИБКА: Некорректная стадия создания %s. Проверьте stacktrace в консоли.", - "description": "Отправляет сообщение по почте заданному пользователю. Применение данной команды изменяется в зависимости от стадии написания письма." + "description": "Отправляет сообщение по почте указанному пользователю. Применение данной команды изменяется в зависимости от стадии написания письма" }, "sendMessage": { - "usage": "Применение: sendmessage <игрок> <сообщение>", - "success": "Сообщение отправлено.", - "description": "Отправляет сообщение выбранному игроку от имени сервера" + "usage": "Применение: sendmessage <сообщение>", + "success": "Сообщение было отправлено.", + "description": "Отправляет сообщение выбранному игроку от имени сервера. При отсутствии конкретной цели, отправляет сообщение всем игрокам на сервере." }, "setFetterLevel": { - "usage": "Применение: setfetterlevel ", + "usage": "Применение: setfetterlevel <уровень>", "range_error": "Значение уровня дружбы должно быть между 0 и 10.", "success": "Уровень дружбы стал равен %s.", "level_error": "Некорректный уровень дружбы.", - "description": "Устанавливает уровень дружбы для активного персонажа" + "description": "Задаёт уровень дружбы для активного персонажа" }, "setProp": { - "usage": "🇺🇸Usage: setprop|prop \n\tValues for : godmode | nostamina | unlimitedenergy | abyss | worldlevel | bplevel\n\t(cont.) see PlayerProperty enum for other possible values, of form PROP_MAX_SPRING_VOLUME -> max_spring_volume", - "description": "🇺🇸Sets accountwide properties. Things like godmode can be enabled this way, as well as changing things like unlocked abyss floor and battle pass progress." + "usage": "Применение: setprop|prop <св-во> <значение>\n\tВозможные значения <св-во>: godmode | nostamina | unlimitedenergy | abyss | worldlevel | bplevel\n\t(прод.) см. перечисление (enum) PlayerProperty для остальных возможных значений, of form PROP_MAX_SPRING_VOLUME -> max_spring_volume", + "description": "Задаёт свойства аккаунта. С помощью данной команды может быть включен godmode, а также разблокированы этажи Коридора Бездны и изменён прогресс боевого пропуска." }, "setStats": { - "usage": "Применение: setstats|stats <хар-ка> <значение>\n\tВозможные значения для <хар-ка>: hp | maxhp | def | atk | em | er | crate | cdmg | cdr | heal | heali | shield | defi\n\t(прод.) Бонус элементального урона: epyro | ecryo | ehydro | egeo | edendro | eelectro | ephys\n\t(cont.) Элементальное сопротивление: respyro | rescryo | reshydro | resgeo | resdendro | reselectro | resphys\n", + "usage": "Применение: setstats|stats <хар-ка> <значение>\n\tВозможные значения <хар-ка>: hp | maxhp | def | atk | em | er | crate | cdmg | cdr | heal | heali | shield | defi\n\t(прод.) Бонус элементального урона: epyro | ecryo | ehydro | egeo | edendro | eelectro | ephys\n\t(прод.) Элементальное сопротивление: respyro | rescryo | reshydro | resgeo | resdendro | reselectro | resphys\n", "description": "Задаёт боевые характеристики для активного персонажа" }, "spawn": { - "usage": "Применение: spawn [кол-во] [уровень(только для монстров)] [ (только для монстров, опционально)]", + "usage": "Применение: spawn [кол-во] [уровень(только для монстров)] [ (только для монстров, опционально)]", "success": "Заспавнено %s %s.", - "limit_reached": "Лимит существ в сцене был достигнут. Спавним %s сущностей вместо этого.", - "description": "Спавнит сущность неподалеку от вас" + "limit_reached": "Лимит существ в сцене был достигнут. Спавним %s существ вместо этого.", + "description": "Спавнит существо неподалеку от вас" }, "stop": { "success": "Сервер завершает свою работу...", - "description": "Завершает работу сервера" + "description": "Останавливает работу сервера" }, "talent": { "usage_1": "Для того, чтобы задать уровень таланта: /talent set <значение>", - "usage_2": "Еще один способ задать уровень таланта: /talent <значение>", + "usage_2": "Альтернативный способ задать уровень таланта: /talent <значение>", "usage_3": "Для того, чтобы получить ID таланта: /talent getid", "lower_16": "Некорректный уровень таланта. Уровень должен быть ниже 16.", "set_id": "Уровень таланта стал равен %s.", @@ -311,26 +311,26 @@ "description": "Устанавливает уровень таланта для вашего активного персонажа" }, "team": { - "usage": "Применение: team [ID_аватара,...] [индекс|first|last|индекс-индекс,...]", + "usage": "Применение: team [ID_персонажа,...] [индекс|first|last|индекс-индекс,...]", "invalid_usage": "Некорректное применение.", - "add_usage": "Применение (для добавления): team add [индекс]", + "add_usage": "Применение (для добавления): team add [индекс]", "invalid_index": "Некорректный индекс.", - "add_too_much": "Сервер позволяет вам иметь максимум %d аватар(а) в команде.", - "failed_to_add_avatar": "Не удалось добавить ID аватара %s.", + "add_too_much": "Сервер позволяет вам иметь максимум %d персонаж(а) в команде.", + "failed_to_add_avatar": "Не удалось добавить персонажа с ID %s.", "remove_usage": "Применение (для удаления): team remove <индекс|first|last|индекс-индекс,...>", "failed_to_parse_index": "Не удалось обработать индекс: %s", - "remove_too_much": "Вы не можете удалить всех своих аватаров.", - "ignore_index": "Игнорированы индекс(ы): %s", - "set_usage": "Применение (для задания): team set <индекс> ", - "index_out_of_range": "Указанный индекс вне границ.", - "failed_parse_avatar_id": "Не удалось распознать ID аватара: %s", - "avatar_already_in_team": "Аватар уже находится в команде.", - "avatar_not_found": "Аватар %d не найден.", - "description": "Вручную настройте свою команду." + "remove_too_much": "Вы не можете удалить всех своих персонажей.", + "ignore_index": "Были проигнорированы индекс(ы): %s", + "set_usage": "Применение (для задания): team set <индекс> ", + "index_out_of_range": "Указанный индекс находится вне границ.", + "failed_parse_avatar_id": "Не удалось распознать ID персонажа: %s", + "avatar_already_in_team": "Персонаж уже находится в команде.", + "avatar_not_found": "Персонаж %d не был найден.", + "description": "Позволяет вручную настроить свою команду." }, "teleportAll": { "success": "Все игроки были телепортированы к вам.", - "error": "Данную команду возможно использовать только в многопользовательском режиме.", + "error": "Данную команду возможно применить только в многопользовательском режиме.", "description": "Телепортирует всех игроков в вашем мире к вам" }, "teleport": { @@ -338,28 +338,28 @@ "usage": "Применение: tp [@] [ID_сцены]", "specify_player_id": "Нужно указать ID игрока.", "invalid_position": "Некорректная позиция.", - "exists_error": "🇺🇸The specified scene does not exist.", + "exists_error": "Указанная сцена не существует.", "success": "Игрок %s был телепортирован по координатам %s, %s, %s в сцене %s.", - "description": "Изменяет позицию игрока" + "description": "Изменяет местоположение игрока" }, "weather": { - "usage": "Usage: weather [weatherId] [climateType]\nWeather IDs can be found in WeatherExcelConfigData.json.\nClimate types: sunny, cloudy, rain, thunderstorm, snow, mist.", - "success": "🇺🇸Set weather ID to %s with climate type %s.", - "status": "🇺🇸Current weather ID is %s with climate type %s.", - "description": "Изменяет погоду.Weather IDs can be found in WeatherExcelConfigData.json.\nClimate types: sunny, cloudy, rain, thunderstorm, snow, mist." + "usage": "Применение: weather [ID_погоды] [тип_климата]\nДоступные ID погоды можно найти в WeatherExcelConfigData.json.\nТипы климата: sunny (солнечно), cloudy (облачно), rain (дождь), thunderstorm (гроза), snow (снег), mist (туман)", + "success": "Установлен ID погоды %s, тип климата: %s.", + "status": "Текущий ID погоды: %s, тип климата: %s.", + "description": "Изменяет ID погоды и тип климата. ID погоды можно найти в WeatherExcelConfigData.json.\nТипы климата: sunny (солнечно), cloudy (облачно), rain (дождь), thunderstorm (гроза), snow (снег), mist (туман)" }, "ban": { - "command_usage": "Применение: ban <@Id игрока> [промежуток_времени] [причина]", + "command_usage": "Применение: ban <@ID_игрока> [промежуток_времени] [причина]", "success": "Успех.", "failure": "Неудача, игрок не найден.", "invalid_time": "Не удалось определить промежуток времени.", - "description": "Банит игрока" + "description": "Запрещает игроку присоединяться к серверу (\"банит\")" }, "unban": { - "command_usage": "Применение: unban <@Id_игрока>", + "command_usage": "Применение: unban <@ID_игрока>", "success": "Успех.", "failure": "Неудача, игрок не найден.", - "description": "Разбанивает игрока" + "description": "Разблокировывает доступ к серверу (\"разбанивает\")" } }, "gacha": { @@ -379,14 +379,14 @@ "handbook": { "title": "Справочник гейм-мастера", "title_commands": "Команды", - "title_avatars": "Аватары", + "title_avatars": "Персонажи (аватары)", "title_items": "Предметы", "title_scenes": "Сцены", "title_monsters": "Монстры", "header_id": "ID", "header_command": "Команда", "header_description": "Описание", - "header_avatar": "Аватар", + "header_avatar": "Персонаж", "header_item": "Предмет", "header_scene": "Сцена", "header_monster": "Монстр" @@ -397,4 +397,4 @@ "gacha_mapping": "Мапирование системы гача в JSON" } } -} \ No newline at end of file +} From 2cfbe78184fc08819763d8dcf36abd0296760a43 Mon Sep 17 00:00:00 2001 From: AnimeGitB Date: Mon, 18 Jul 2022 18:36:17 +0930 Subject: [PATCH 53/61] Refactor Command usage and description strings --- .../java/emu/grasscutter/command/Command.java | 8 +- .../grasscutter/command/CommandHandler.java | 39 ++++++++- .../emu/grasscutter/command/CommandMap.java | 6 +- .../command/commands/AccountCommand.java | 80 +++++++++-------- .../command/commands/AnnounceCommand.java | 3 +- .../command/commands/BanCommand.java | 3 +- .../command/commands/ClearCommand.java | 9 +- .../command/commands/CoopCommand.java | 2 +- .../command/commands/EnterDungeonCommand.java | 2 +- .../command/commands/GiveCommand.java | 11 ++- .../command/commands/HealCommand.java | 2 +- .../command/commands/HelpCommand.java | 86 +++++++++---------- .../command/commands/KickCommand.java | 11 ++- .../command/commands/KillAllCommand.java | 3 +- .../commands/KillCharacterCommand.java | 2 +- .../command/commands/LanguageCommand.java | 4 +- .../command/commands/ListCommand.java | 2 +- .../command/commands/PermissionCommand.java | 2 +- .../command/commands/PositionCommand.java | 8 +- .../command/commands/QuestCommand.java | 3 +- .../command/commands/ReloadCommand.java | 2 +- .../command/commands/ResetConstCommand.java | 8 +- .../commands/ResetShopLimitCommand.java | 2 +- .../command/commands/SendMailCommand.java | 6 +- .../command/commands/SendMessageCommand.java | 9 +- .../commands/SetFetterLevelCommand.java | 8 +- .../command/commands/SetPropCommand.java | 2 +- .../command/commands/SetStatsCommand.java | 2 +- .../command/commands/SpawnCommand.java | 13 ++- .../command/commands/StopCommand.java | 2 +- .../command/commands/TalentCommand.java | 7 +- .../command/commands/TeamCommand.java | 9 +- .../command/commands/TeleportAllCommand.java | 3 +- .../command/commands/TeleportCommand.java | 3 +- .../command/commands/UnBanCommand.java | 2 - .../command/commands/WeatherCommand.java | 3 +- .../java/emu/grasscutter/game/Account.java | 1 + .../documentation/HandbookRequestHandler.java | 6 +- .../java/emu/grasscutter/tools/Tools.java | 10 +-- src/main/resources/languages/en-US.json | 1 + 40 files changed, 221 insertions(+), 164 deletions(-) diff --git a/src/main/java/emu/grasscutter/command/Command.java b/src/main/java/emu/grasscutter/command/Command.java index 4af98e788..095e64cdb 100644 --- a/src/main/java/emu/grasscutter/command/Command.java +++ b/src/main/java/emu/grasscutter/command/Command.java @@ -7,14 +7,12 @@ import java.lang.annotation.RetentionPolicy; public @interface Command { String label() default ""; - String usage() default "commands.generic.no_usage_specified"; - - String description() default "commands.generic.no_description_specified"; - String[] aliases() default {}; + String[] usage() default {""}; + String permission() default ""; - + String permissionTargeted() default ""; public enum TargetRequirement { diff --git a/src/main/java/emu/grasscutter/command/CommandHandler.java b/src/main/java/emu/grasscutter/command/CommandHandler.java index 4803b154f..c9a690040 100644 --- a/src/main/java/emu/grasscutter/command/CommandHandler.java +++ b/src/main/java/emu/grasscutter/command/CommandHandler.java @@ -2,12 +2,11 @@ package emu.grasscutter.command; import emu.grasscutter.Grasscutter; import emu.grasscutter.game.player.Player; -import emu.grasscutter.server.event.game.CommandResponseEvent; import emu.grasscutter.server.event.game.ReceiveCommandFeedbackEvent; -import emu.grasscutter.server.event.types.ServerEvent; import static emu.grasscutter.utils.Language.translate; import java.util.List; +import java.util.StringJoiner; public interface CommandHandler { @@ -37,6 +36,42 @@ public interface CommandHandler { sendMessage(player, translate(player, messageKey, args)); } + default String getUsageString(Player player, String... args) { + Command annotation = this.getClass().getAnnotation(Command.class); + String usage_prefix = translate(player, "commands.execution.usage_prefix"); + String command = annotation.label(); + for (String alias : annotation.aliases()) { + if (alias.length() < command.length()) + command = alias; + } + String target = switch (annotation.targetRequirement()) { + case NONE -> ""; + case OFFLINE -> "@ "; // TODO: make translation keys for offline and online players + case ONLINE -> (player == null) ? "@ " : "[@] "; // TODO: make translation keys for offline and online players + case PLAYER -> (player == null) ? "@ " : "[@] "; + }; + String[] usages = annotation.usage(); + StringJoiner joiner = new StringJoiner("\n\t"); + for (String usage : usages) + joiner.add(usage_prefix + command + " " + target + usage); + return joiner.toString(); + } + + default void sendUsageMessage(Player player, String... args) { + sendMessage(player, getUsageString(player, args)); + } + + default String getLabel() { + return this.getClass().getAnnotation(Command.class).label(); + } + + default String getDescriptionString(Player player) { + Command annotation = this.getClass().getAnnotation(Command.class); + String key = "commands.%s.description".formatted(annotation.label()); + // TODO: fallback to "commands.generic.no_description_specified" + return translate(player, key); + } + /** * Called when a player/console invokes a command. * @param sender The player/console that invoked the command. diff --git a/src/main/java/emu/grasscutter/command/CommandMap.java b/src/main/java/emu/grasscutter/command/CommandMap.java index da37f0b37..5bfeab7d7 100644 --- a/src/main/java/emu/grasscutter/command/CommandMap.java +++ b/src/main/java/emu/grasscutter/command/CommandMap.java @@ -8,9 +8,9 @@ import java.util.*; @SuppressWarnings({"UnusedReturnValue", "unused"}) public final class CommandMap { - private final Map commands = new HashMap<>(); - private final Map aliases = new HashMap<>(); - private final Map annotations = new HashMap<>(); + private final Map commands = new LinkedHashMap<>(); + private final Map aliases = new LinkedHashMap<>(); + private final Map annotations = new LinkedHashMap<>(); private final Map targetPlayerIds = new HashMap<>(); private static final String consoleId = "console"; diff --git a/src/main/java/emu/grasscutter/command/commands/AccountCommand.java b/src/main/java/emu/grasscutter/command/commands/AccountCommand.java index 843b78913..15855c4c9 100644 --- a/src/main/java/emu/grasscutter/command/commands/AccountCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/AccountCommand.java @@ -13,18 +13,24 @@ import java.util.List; import static emu.grasscutter.utils.Language.translate; -@Command(label = "account", usage = "account [uid|password] [uid] ", description = "commands.account.description", targetRequirement = Command.TargetRequirement.NONE) +@Command( + label = "account", + usage = { + "create []", // Only with EXPERIMENTAL_RealPassword == false + "delete ", + "create []", // Only with EXPERIMENTAL_RealPassword == true + "resetpass "}, // Only with EXPERIMENTAL_RealPassword == true + targetRequirement = Command.TargetRequirement.NONE) public final class AccountCommand implements CommandHandler { - @Override public void execute(Player sender, Player targetPlayer, List args) { if (sender != null) { - CommandHandler.sendMessage(sender, translate(sender, "commands.generic.console_execute_error")); + CommandHandler.sendTranslatedMessage(sender, "commands.generic.console_execute_error"); return; } if (args.size() < 2) { - CommandHandler.sendMessage(null, translate(sender, "commands.account.command_usage")); + CommandHandler.sendTranslatedMessage(sender, "commands.account.command_usage"); return; } @@ -33,17 +39,16 @@ public final class AccountCommand implements CommandHandler { switch (action) { default: - CommandHandler.sendMessage(null, translate(sender, "commands.account.command_usage")); + CommandHandler.sendTranslatedMessage(sender, "commands.account.command_usage"); return; case "create": int uid = 0; String password = ""; - if (Configuration.ACCOUNT.EXPERIMENTAL_RealPassword == true) { - if (args.size() < 3) { - CommandHandler.sendMessage(null, "EXPERIMENTAL_RealPassword requires a password argument"); - CommandHandler.sendMessage(null, "Usage: account create [uid]"); - + if(Configuration.ACCOUNT.EXPERIMENTAL_RealPassword == true) { + if(args.size() < 3) { + CommandHandler.sendMessage(sender, "EXPERIMENTAL_RealPassword requires a password argument"); + CommandHandler.sendMessage(sender, "Usage: account create [uid]"); return; } password = args.get(2); @@ -52,10 +57,10 @@ public final class AccountCommand implements CommandHandler { try { uid = Integer.parseInt(args.get(3)); } catch (NumberFormatException ignored) { - CommandHandler.sendMessage(null, translate(sender, "commands.account.invalid")); - if (Configuration.ACCOUNT.EXPERIMENTAL_RealPassword == true) { - CommandHandler.sendMessage(null, "EXPERIMENTAL_RealPassword requires argument 2 to be a password, not a uid"); - CommandHandler.sendMessage(null, "Usage: account create [uid]"); + CommandHandler.sendMessage(sender, translate(sender, "commands.account.invalid")); + if(Configuration.ACCOUNT.EXPERIMENTAL_RealPassword == true) { + CommandHandler.sendMessage(sender, "EXPERIMENTAL_RealPassword requires argument 2 to be a password, not a uid"); + CommandHandler.sendMessage(sender, "Usage: account create [uid]"); } return; } @@ -65,7 +70,7 @@ public final class AccountCommand implements CommandHandler { try { uid = Integer.parseInt(args.get(2)); } catch (NumberFormatException ignored) { - CommandHandler.sendMessage(null, translate(sender, "commands.account.invalid")); + CommandHandler.sendMessage(sender, translate(sender, "commands.account.invalid")); return; } } @@ -73,7 +78,7 @@ public final class AccountCommand implements CommandHandler { emu.grasscutter.game.Account account = DatabaseHelper.createAccountWithUid(username, uid); if (account == null) { - CommandHandler.sendMessage(null, translate(sender, "commands.account.exists")); + CommandHandler.sendMessage(sender, translate(sender, "commands.account.exists")); return; } else { if (Configuration.ACCOUNT.EXPERIMENTAL_RealPassword == true) { @@ -82,7 +87,7 @@ public final class AccountCommand implements CommandHandler { account.addPermission("*"); account.save(); // Save account to database. - CommandHandler.sendMessage(null, translate(sender, "commands.account.create", Integer.toString(account.getReservedPlayerUid()))); + CommandHandler.sendMessage(sender, translate(sender, "commands.account.create", Integer.toString(account.getReservedPlayerUid()))); } return; case "delete": @@ -90,51 +95,50 @@ public final class AccountCommand implements CommandHandler { Account toDelete = DatabaseHelper.getAccountByName(username); if (toDelete == null) { - CommandHandler.sendMessage(null, translate(sender, "commands.account.no_account")); + CommandHandler.sendMessage(sender, translate(sender, "commands.account.no_account")); return; } - // Get the player for the account. - // If that player is currently online, we kick them before proceeding with the deletion. - Player player = Grasscutter.getGameServer().getPlayerByAccountId(toDelete.getId()); - if (player != null) { - player.getSession().close(); - } + // Make sure player isn't online as we delete their account. + kickAccount(toDelete); // Finally, we do the actual deletion. DatabaseHelper.deleteAccount(toDelete); - CommandHandler.sendMessage(null, translate(sender, "commands.account.delete")); + CommandHandler.sendMessage(sender, translate(sender, "commands.account.delete")); return; case "resetpass": - if (Configuration.ACCOUNT.EXPERIMENTAL_RealPassword != true) { - CommandHandler.sendMessage(null, "resetpass requires EXPERIMENTAL_RealPassword to be true."); + if(Configuration.ACCOUNT.EXPERIMENTAL_RealPassword != true) { + CommandHandler.sendMessage(sender, "resetpass requires EXPERIMENTAL_RealPassword to be true."); return; } - if (args.size() != 3) { - CommandHandler.sendMessage(null, "Invalid Args"); - CommandHandler.sendMessage(null, "Usage: account resetpass "); + if(args.size() != 3) { + CommandHandler.sendMessage(sender, "Invalid Args"); + CommandHandler.sendMessage(sender, "Usage: account resetpass "); return; } Account toUpdate = DatabaseHelper.getAccountByName(username); if (toUpdate == null) { - CommandHandler.sendMessage(null, translate(sender, "commands.account.no_account")); + CommandHandler.sendMessage(sender, translate(sender, "commands.account.no_account")); return; } - // Get the player for the account. - // If that player is currently online, we kick them before proceeding with the deletion. - Player uPlayer = Grasscutter.getGameServer().getPlayerByAccountId(toUpdate.getId()); - if (uPlayer != null) { - uPlayer.getSession().close(); - } + // Make sure player can't stay logged in with old password. + kickAccount(toUpdate); toUpdate.setPassword(BCrypt.withDefaults().hashToString(12, args.get(2).toCharArray())); toUpdate.save(); - CommandHandler.sendMessage(null, "Password Updated."); + CommandHandler.sendMessage(sender, "Password Updated."); return; } } + + private void kickAccount(Account account) { + Player player = Grasscutter.getGameServer().getPlayerByAccountId(account.getId()); + if (player != null) { + player.getSession().close(); + } + } } diff --git a/src/main/java/emu/grasscutter/command/commands/AnnounceCommand.java b/src/main/java/emu/grasscutter/command/commands/AnnounceCommand.java index 136db705d..90881793b 100644 --- a/src/main/java/emu/grasscutter/command/commands/AnnounceCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/AnnounceCommand.java @@ -13,10 +13,9 @@ import java.util.Random; import static emu.grasscutter.utils.Language.translate; @Command(label = "announce", - usage = "announce|a <\"tpl\" templateId|\"refresh\"|\"revoke\" templateId|content>", + usage = {"", "refresh", "(tpl|revoke) "}, permission = "server.announce", aliases = {"a"}, - description = "commands.announce.description", targetRequirement = Command.TargetRequirement.NONE) public final class AnnounceCommand implements CommandHandler { diff --git a/src/main/java/emu/grasscutter/command/commands/BanCommand.java b/src/main/java/emu/grasscutter/command/commands/BanCommand.java index 6b4dd9766..6f0b0abec 100644 --- a/src/main/java/emu/grasscutter/command/commands/BanCommand.java +++ b/src/main/java/emu/grasscutter/command/commands/BanCommand.java @@ -10,8 +10,7 @@ import emu.grasscutter.server.game.GameSession; @Command( label = "ban", - usage = "ban <@player> [time] [reason]", - description = "commands.ban.description", + usage = {"[