From 3e2b1b84b8fed3d26112354f6b923dca2fe3fa9f Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Thu, 25 Sep 2025 23:41:41 +0800 Subject: [PATCH 1/6] =?UTF-8?q?feat:=20=E6=97=A0=E9=99=90=E7=9B=98?= =?UTF-8?q?=E6=9D=90=E8=B4=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../textures/item/infinity_biginteger_cell.png | Bin 2266 -> 421 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/src/main/resources/assets/extendedae_plus/textures/item/infinity_biginteger_cell.png b/src/main/resources/assets/extendedae_plus/textures/item/infinity_biginteger_cell.png index 5c47ca4fdedf33c73a8afa63e5c1fe41f4978db7..75e2465e80eefebf2e0a16b5d6a9e829cab46469 100644 GIT binary patch delta 396 zcmV;70dxM^5v2o=BYy#GNklLb@)0i5U z3^zY-kt0?^Pz*rV`192}26izayoP`cK-UP;fvy>53c5=eL7L+{0>L(cG{FGK=3~Y4 zVO$2Q-bA>e$cBIo5Mg9t5Wnybt{B8HF82o;`e@-Hu=tZpcYm=O!i22rnfeh189ik% zKHIqwY@=Mf9asrS4&)+`%Rnxj6t|y&kHO+Uh6_Ln&Di7Nwt`#&0x!2;VL0`3A%oOS z8-|_w7rXM({eP=l4C{AnX3)3@iBb#~z*NEvF)=j(3u&wCF+6;Ionh~WPKHk$T3}m2 z5+IvF0F*jW0`VwA4&$5ue;Cf3J_A+&BVd|A8bKJO5tg)3QX)(P%q0%)mSCq}VAukd qf@y-O!%Kq<0YwuC<5fthBmiHxu5I}BX0iYP002ovP6b4+LSTaG0HaO- literal 2266 zcmcgueNYr-99|d)5hWog8wPb}Q}ctpyWQKp+uJx1Iq)zJ5GcSgb8q)O?)2_<-Cf`y zrqGNeq%2eOqiIT;v`;ll#}dgAF`Ud8ok%OgR2-eeufnvbcaP)320z9>x|zLw_uc1x zp6BJhA1G3_uoqzvHp z*sEnwSe;wMS1;f#0+u!vO%1S+zz0+g4fwo%g$-D-ATJBY+O!@+gAjFr6-(Cy(Go{K znjy*nwde?(HyB9NY|)t+r`cp=Qc%)B(s~1_CkULdu!Mm%Flgw9K{;7)u?4oQkQltO zVs2HHSiQcovQk%R)QNJLp0HRf8V5<@5P>UIew7R0e&ykQ1{+X#*(0eQ(T{43oKq}U ztr)c07lTg<)B2TAo?yoG0Z!5rI)fHd5Ge3roK!A*gW>|O2VURKx6lTH0t`))S~mw9gtdDVSh}jv^HB&E zhDKfw8te&{M1S3f?W+&4h`atW0Hsifm52b~7bN(^_ zcTPQa@4?(%U-r5DAA`|r`(Hph&!FvPtR#?d36x^`2Vfa-6FTyVy;D>pV;j2Vh zH+?vQM4ZdEr57=c@2p63C(KH2P184;M$1Q%N4f1AIv?D;eDat33*#Q$^klQPqsB=j@t2le0pTmq^P9W`ZM0yc}eTAs@x`N?y(kg?@v89 zs?wg>)16Q-v$t#MkGec5FY?cg*{__pe%d*=WrTTr^YiuD*MA|7HBRVRy?i(N_UcQQ z_bq#G_YXS{b{?WGb;Rvh<^QB@eKb-*MxMRmY3n+%aDH>tytghM7#crx=VUSGo0GeA z-|oIqlT|D1-#9zv2KvX|NcwUlI^<{OzB&$(To+@m*Q^!xk6S}Lu&?Iz)4zS3iu~R& zBC4<;;{KHpV})z&CG)nlcF#FwKaq&kani3>Q<7RY9-H1(8r!x0IZ#TiEw|;)Xe!M( zrPhrcQ;=2L+AuPa8Ij+9ZdqW$(MQGx*txCSQs#V@c}hi^jy{H@G*!o+%|XU(IsKLU zrFe1a{H-}pr`CbenOA#SV&07C$cw4%N$oy^F2Y}aan`mswlDU!(NjMxK76r4mig??bH%wcSIOZT0_w|s^mL;@A$L<|df4n!M zxj1S2wdmSb*=%3586gg}C2m-<=n_OJ*GG0{uI;1g^A`UDbnOYi From f77833a339546b8f21723c8c1242ae97f74930c7 Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Fri, 26 Sep 2025 00:27:18 +0800 Subject: [PATCH 2/6] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E9=AB=98=E7=BA=A7?= =?UTF-8?q?ae=E6=94=AF=E6=8C=81=E6=99=BA=E8=83=BD=E7=B3=BB=E5=88=97mixin?= =?UTF-8?q?=E6=9E=84=E9=80=A0=E5=87=BD=E6=95=B0=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../advancedae/client/gui/AdvPatternProviderScreenMixin.java | 5 ++--- .../client/gui/SmallAdvPatternProviderScreenMixin.java | 5 ++--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/extendedae_plus/mixin/advancedae/client/gui/AdvPatternProviderScreenMixin.java b/src/main/java/com/extendedae_plus/mixin/advancedae/client/gui/AdvPatternProviderScreenMixin.java index 2136f1a..229c50c 100644 --- a/src/main/java/com/extendedae_plus/mixin/advancedae/client/gui/AdvPatternProviderScreenMixin.java +++ b/src/main/java/com/extendedae_plus/mixin/advancedae/client/gui/AdvPatternProviderScreenMixin.java @@ -14,7 +14,6 @@ import net.minecraft.network.chat.Component; import net.minecraft.world.entity.player.Inventory; import net.pedroksl.advanced_ae.client.gui.AdvPatternProviderScreen; import net.pedroksl.advanced_ae.gui.advpatternprovider.AdvPatternProviderMenu; -import org.checkerframework.checker.units.qual.C; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Unique; import org.spongepowered.asm.mixin.injection.At; @@ -43,8 +42,8 @@ public abstract class AdvPatternProviderScreenMixin extends AEBaseScreen Date: Fri, 26 Sep 2025 00:34:39 +0800 Subject: [PATCH 3/6] =?UTF-8?q?feat:=20=E6=9B=B4=E6=96=B0=E5=AE=9E?= =?UTF-8?q?=E4=BD=93=E5=8A=A0=E9=80=9F=E5=8D=A1=E6=9D=90=E8=B4=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../textures/item/entity_speed_card_x16.png | Bin 2485 -> 2400 bytes .../textures/item/entity_speed_card_x2.png | Bin 2271 -> 2360 bytes .../textures/item/entity_speed_card_x4.png | Bin 2501 -> 2380 bytes .../textures/item/entity_speed_card_x8.png | Bin 2476 -> 2394 bytes 4 files changed, 0 insertions(+), 0 deletions(-) diff --git a/src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x16.png b/src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x16.png index adfcc54a61cacbeaf5785fe622850a3a8549da53..fc3db8219d8075adc06819e594900d8a06171901 100644 GIT binary patch delta 845 zcmdlg{6J{K5hiXUvk(IVD`R6TBh$&}nUqlYf0zPPOw5za3@nXIbj^$mOmq#COpJ9c zEfdXk&61On%?yl_%+gXVCKoVksTdm=8yh938tPgYo2Ka+nVJ{@S%!(amPW=##%bmz zsVPZ@oA)uRF%f5E1B)1nTNbj|OrF6iHo2NDvR>`z%m@YsrUFkF#}JRsyHor zNpoOTCcZ?eCPS$Sk!-?D6h>%g+ZDUcI@en*aNp-*eyJeILwom_b3x|C;#! zj?Rr+lJ3@PwD4&PU9(tRBDAy>PXg+9H0hLK~T@zzPp zmR>toAsQ4@F2}fFyZV{qG5-QS&)&)rK1)xa^gY7`h7ZZLv72&L*Kb$%$@hp4?<=!r2l|ZT zCiff;wz*zA&uqRJ-c|qPfYdX6>mOnaSKbS1JvExUJ?d%kHq(qb`Hz2IQaYH>;E~sr zVBnCxqWN3^yS=^1>Ei6wt9gzJ{g!d~J9Xu%>2pozCh7S<)^ASI>ld(E^~!b5b=l*a z6a}1~Z>%^V<4?Dqe+_tI%J-2BG1S4UgV>Xgq;5;5Cc&6}L!rR=`?qMO&}FxhR=D|wez za{uU-n!9MjoTclv(@xL5!OwL%5{PD6Pm@2RduBq%z0Ibxqh~PsJzy_BBjc2;WMORY r(Yw!buYAPU0xkOu$Lb%j*E0m4=@V4QSyA_f0SG)@{an^LB{Ts5aZzDN delta 929 zcmaDLv{iV+5hiX!lMn+VD+3cNQ-jIpnUqlYf0zPPEDcP|Eewr}buBDXjC2i6OiXnx z%uUmDEsWBPjg1VF3{%ZgCl@elsiYVh7$%unnChllq?za@C7Pt_CYqX==$fXOB^g_$ zq$Qarrf%NHtj0u~kqs>3Tu4q^$YL{j2CLZQYPQJw-=1Za3=B+1JzX3_JUY)#Iqw}3 zD01B1|GxD7AIHp>Ez)@Drm?lvRjBR3qK*!h`UFm0wF|9^j*Sl%EiyRWmb18f!LmhS zjzTLZ{AJD5{@)O$#}ia2Gk0cr`n^A&wid|Dy?F7GZ+fxZ_j%v%4hY|SB2id#Uc$0< zQ)jFZ2n|`Z$<5{BwnIy7fi zuOuzXkI$=9k58G!&@gj(@!9-~FQ$}Lu7Bq9`{ngRO#HXHd$XzLq zefIr^^_+*!A09k8TejwF@|4}b5_yI6tNx|+vcGm#zR}XSx4fq}-8}KJfK9-=eQA$Z zcDwkM$?b4+-~3s@@Qu>CH_r|pdGe(GK(noJL$2I}CkOoIpKP{e84mFS{kJ$nk1W~Zq8@6XPT_SB0BjSiy|=^CfBowb0e%ZoxG66X7UWy z{Cf64<;4sPOdg&tjv*eMcc+~9mJSp+ZZBP=ZR>F>Eqfd5#GqNt0gl;Kfu5|ktOvWZ znd7+URlkxC$l$jXsrsPw<@(YM6`HLQ!n|8d7dTB`H9e-}`aWG(&3l_|m%RUJCcV;& ze`)c}+QYNo*QDP&bDg7!q2bOIpV!a%xBYmxb>aN_$3{PHUOvw7W@ntngIQC9>aKr1 z;d_?F$|Gj~pO?j^lP+FmczxSiMW|E2!$ycvXKI+!^XkQi88{vq->h-9l3x7rQP73o z584GMPgnW6^b*(RO6i81d(P(E3u{<5Q{}Gw<0P$PUng2$6ndh1{p*$RUnbvs_~Wn@TVxc}{Y==P;M*B$>6G412VHJ>;iZr*zF z$%*Vu(Q(##53|a*ziOPfbKl;@HJjFyu@%m3{QZ0F*EN%R?=hRrTJrmL)dKzrx6OR2 z_+<*`SFJsE=ufrtR|oT-DQ`C`c(1&kmBRMxib@-Uj`q>RbJs_Nb#)%9H<~t8$=Jjr zEknRN`_sL5di`o|AImZ5?5SzaRNJ}t`Q}KCqKD}R(iV0I*e#ps!m&R&QjyK+hmE1W za?ANgXSKCnEJPKR~ZRd+S@(sOxW-skW<4Gdp;Lc8|pSb!?Du#Urw;1HsygPcHZXcJ9Dc=C0eU^tBT z+XSYFv2dvmDW1qU$eRH=w8*YqfolIcs)+EmwGW3dx&Gq=ix<1G<4IDoe6$1IzlI`A zlxURBr5P44bdd(qs*`wW8Gn~2rkQ7&%F0SKx0|-facPf$y6H!bSxBig3oTtFWrc*I zl8`mxik2;t3SJ~(nkaFVk&iF;uLCeR@}=PS+;0R(m6p=($sDjh2h^(EhU|?zAYeIl zZij5zJ<@^f*F1YR{a#t&Y0sVA763x78rFwDaZV}Yr=n4zxR`gSSbvI&sW^(ZkQIqd`4))5hiXUvk(IVD`R6T6XVI}nUqlYf0zPP%u>t~O;XG(bq$iu40H{RP0V!@ z(~OLCQ%y|`Obv}pElms!CKoVksTiAEnkJhiC+eD|nVRZaB$*iMCK?+U>L!_6CK*`* zwWL`lZr;bN#zdTv4J=|PZdu4;GkFH9*yL)q$ofq#3%eN@m|{F#978-h?@rmD9ULff z++M#Vt8hi&=bS|WT^)?fYrnY1+?phEYbA@!nadsr9hv4HUHHGTxqE_Qck?CJijWWN zOENF9wTRtv63(8clPQ$%61C)lVWG$Ux4S)8WflsY|8&oC&hNeVi{DwsuZ>&JY*78) z@$qy1ZC}3C_ojW{z2@*ocTR>+;`cS#*HzwO`10n?MDd%ByWX5U?QUqHrOmK(($nJ{ zW$uMmbGbU06dHq8cgfF@VSjM*_wSah^&i<}M3SbzV!kLp>#*0R75dA=W_C+3oN?uO zrqsrArBwW$BD?qG$)$yw=) z4>ta5iZSc1zoD)k$jDJ&=3Y7Lf79{DX=)pR}q@!3HNqd?a6c@Lw~#EU{Ub>&C4#DT`*g zH52m^l_me^+TQ3`er`Scx7vU>#T&Az8uhc^3pUR@!nLkLadz}?iyPCf)-Pb+&mf;v Vttnhx^@ITkJYD@<);T3K0RXl6Tu}f3 delta 945 zcmX>jbX0i55hiX!lMn+VD+6OIW24FEnUqlYf0zPPEK(9p(=5zPbW<&oO?1-?Ow4sH z4U&v?&5SLRQcP1)3@itCK{QW=_V&9nj0jg zBv~4pT5R6Otj0u~kqs>3Tu4q^$YL{j2CLZQYPQIFhlfiI85o$Zdb&7>!I~*1pN(hTdh3i$Ys1^na$Ig%t4pcJSCnj~VBTO+*B-!Mm zix^YqCvlE-KbT`Ch6qnI_+ok4FTSUHTk}-0sd+ZDjdy-O^L}3OJKOmQx6PK$;CS%) zr;O$AlZ>ZRBi>h{YwJewva;+lBv< z+5SLDPUFgF60)-ntZvn3c*7(uAj8PYshhfZSx(j(l~t*Mvb~S`BsG>Dd~%29E&KP& z^LyHV>D0ZPWfN{?Jbz6du}XI|d&>jGDo zzgZ3^+Q_>boRQdE{afHsrw`lyFASo$T&~YL5LU~1v**L2z5QI5ADmcz{mk2! z$NJPgJCiQTSum~o$9&SHe!`+atLN%7Zr^p4@;E*9$m!KL%#F^OJic=6+M*qIWhD0M zKjA!~ZIyJ!$z$ov+}BE)UMeaxTUH26pAs`8;Dh4KwnmZZl2yMSe6M9V$Fo;|$Gba+ z&PH$dm^%IP!c@K=cYi;%lC!Uz^z+=l6E=(ttAn1poLJ^8e62F};-|V_-@a;_*H`&H zH8*^6>)53S)@2@{HPb}0RKzcf8ckD4_7HXTE?{|c+I=OwN@kR%9DU{b?(Q) zI~ED17(2ax_?dP2Mg@Mp((+HWZ=OD@*zmcmgukqSn|Gcghr_RjH|rleemKV=x~%c_ z9f{T7{SLoUt5D#zN&mX8y(F?wuENc|`?G@W8%5Q%&ksJia;5%2bCcu&DgF~h55m`L wOX<2AY0P9lr}IQiFZV$6wQJW(eRXEC+cP?RnC+OQ*vS9_p00i_>zopr00@eZOaK4? diff --git a/src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x8.png b/src/main/resources/assets/extendedae_plus/textures/item/entity_speed_card_x8.png index dbfdae5b48127a7c29b6c395ce4b413f8542b4f9..c73e9ac1ea05c798bbbc0558fae103092e66e4ee 100644 GIT binary patch delta 839 zcmZ1@d`oD<5hiXUvk(IVD`O)o6N|~`nUqlYf0zPPQq#=M3{#RUbd3yB%ybjYOe}RR zEeuU{QxnaSjZ6$JjZ;iaCl@elsTilFT9{fG8tEn(8=L5+C7UGaTBaFW>LwW`nxz`1 zS|+C$7;N6htj0u~kqsI@Kj%7kI+iHTao#z8jGEK$@13r`fB*a5-+R|5%~E6dxH0AJ zWBF}64A$SMtv_nw`zYD7_;H|6!_LRreNF2U7#b#au{pfBY17U9`P6IW=HGhydeuc) z-_@;B*&Ehf|07~>_io?u$BK5-Omx-w7*0?7beiwKUxh@&hnTiAm^O zhsH~3s*zWwe>&~sr@}B}j)#He#0d?nULCDn+nyZHzHau`Yf=*RD^`ie>Yu*c#mJFZ z@Z&FgUX{fy>xPB)TNnho-A<$w^FGM)S3kawPme{9@dDe1@RcVrZ?}tgyLGrK8>zJ% ze0Wa$);B(jUlITAHl2UJyu|5x-REb|btO07T9y7_lktVGoA&IS*IUc>hJm^EoMK;y zNl+>4*JZ2X-f=ej`aZt;rl(#hJ;D6-^sD<>8_ehVnVI$;j8^)DRTeUuW?cRN+M{SO7%X1^3Jpcup)eGd>#i{NKU?@7H^NDZYxR{z7y7(Ug{d{kFf97`Pc27(8A5T-G@yGywn@uWzOR delta 920 zcmca5v_^Qt5hiX!lMn+VD+3cN1M|t}nUqlYf0zPPl2VLJjZzIvbj^~IQ*|vYADuTO_7g z7@8WUCT`xxtj0u~kqs>3Tu4q^$YL{j2CLZQYPQJwCa?M(3=B+rJY5_^JUY)#IqNM_ zC~@3=vGMCQi#IP@B=O4dG@q2GM3bW+t8C3dA*(eB?2b&#o=uCKCwZ1#Y!2{B5!m9Q zwf7I>#IjHP8XWv=D|fuxwfpn!xwXYsYu3GcrL}JQywl9a=WFWk-#0%0d7{qgM;40A zA6^FqEzRF!x3u0tf{j70pS@w#t1J`W$6qGfoz$G3&&lwedH#v}J;9aQU2?qv5@r{b z)LI`3R5IFMz8jud;;|?459fi*4Gfx^3l=`;hB+E%mFqyJyZ0@0r!DleVUIU7MC!pTDbd?-r)%_uEgu zPgZ<(|E1&o3ft@JD=s=WHBCtPa5(wctm+e=*CZJ;-Do-SLZPy?=)Tn~jt?I`8%WpL zpVL>CP&yJ*%N}GgsbIru_7?%#x64_)?yg>;bRZ>`-7K--=WmhE>Cqbx1tx8(*};5w zZ<7+wl!OV-Sj9i5M|Ch4n)cThxUQ=5_6^ypF2mL?`CxAvtXjHP#bWsD{!6+X*~ z?l{FI=&Gue-6ER1+sAA6;+6&jo+%qn9oYT+<$J~#azA#w|NJC>j?52V9rNjK?vEP2 zyb1K4A?N4w=$p$j4u%<(R_3*0y?mMeW!ZgG`v2+Zeq8akEK9idn^D;B`^8=->z}tT z3S4qy=GK)ny1EwLFp5*u47h8}>hQby(Uhj#*E5~0-dR1Di7P5dIorH&;leA9R$Bb` zj)mzikEyGXQvn97e7oeL3p|V1S;eDgN6slotD$ zD}UCmTN}*$0v^6$*FO?}$5M*ljLm%mCv$A|d5PKQcO@8e%V~U%+xYW}r;WNX|D45( zXI2Wx7YPM_`;<_X_RRjl!F_xQ?d&;)3FUsz5AI{S`AK2px!u!VI>=qAxqbOa^5+Ng YhhFsV*I&8rAOjG1y85}Sb4q9e071Hr&Hw-a From cc9dd480b43a4b203f6580957aaecb25b9cefd96 Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Fri, 26 Sep 2025 15:52:51 +0800 Subject: [PATCH 4/6] =?UTF-8?q?feat:=20=E7=A7=BB=E6=A4=8D=E6=97=A0?= =?UTF-8?q?=E9=99=90=E7=9B=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/extendedae_plus/ExtendedAEPlus.java | 34 +- .../InfinityBigIntegerCellHandler.java | 22 + .../InfinityBigIntegerCellInventory.java | 414 ++++++++++++++++++ .../ae/items/InfinityBigIntegerCellItem.java | 88 ++++ .../extendedae_plus/init/ModCreativeTabs.java | 2 + .../com/extendedae_plus/init/ModItems.java | 6 + .../util/storage/InfinityConstants.java | 30 ++ .../util/storage/InfinityDataStorage.java | 48 ++ .../util/storage/InfinityStorageManager.java | 151 +++++++ .../assets/extendedae_plus/lang/en_us.json | 3 + .../assets/extendedae_plus/lang/zh_cn.json | 3 + 11 files changed, 799 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellHandler.java create mode 100644 src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellInventory.java create mode 100644 src/main/java/com/extendedae_plus/ae/items/InfinityBigIntegerCellItem.java create mode 100644 src/main/java/com/extendedae_plus/util/storage/InfinityConstants.java create mode 100644 src/main/java/com/extendedae_plus/util/storage/InfinityDataStorage.java create mode 100644 src/main/java/com/extendedae_plus/util/storage/InfinityStorageManager.java diff --git a/src/main/java/com/extendedae_plus/ExtendedAEPlus.java b/src/main/java/com/extendedae_plus/ExtendedAEPlus.java index 5a01c42..43285e6 100644 --- a/src/main/java/com/extendedae_plus/ExtendedAEPlus.java +++ b/src/main/java/com/extendedae_plus/ExtendedAEPlus.java @@ -2,14 +2,18 @@ package com.extendedae_plus; import appeng.api.parts.IPart; import appeng.api.parts.PartModels; +import appeng.api.storage.StorageCells; import appeng.block.AEBaseEntityBlock; import appeng.blockentity.crafting.CraftingBlockEntity; import appeng.items.parts.PartModelsHelper; +import com.extendedae_plus.ae.api.storage.InfinityBigIntegerCellHandler; import com.extendedae_plus.config.ModConfigs; import com.extendedae_plus.init.*; +import com.extendedae_plus.util.storage.InfinityStorageManager; import com.mojang.logging.LogUtils; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.MinecraftServer; import net.minecraft.world.level.block.Blocks; import net.neoforged.bus.api.IEventBus; import net.neoforged.bus.api.SubscribeEvent; @@ -18,7 +22,10 @@ import net.neoforged.fml.common.Mod; import net.neoforged.fml.config.ModConfig; import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent; import net.neoforged.neoforge.common.NeoForge; +import net.neoforged.neoforge.event.server.ServerStartedEvent; import net.neoforged.neoforge.event.server.ServerStartingEvent; +import net.neoforged.neoforge.event.server.ServerStoppedEvent; +import org.jetbrains.annotations.Nullable; import org.slf4j.Logger; // The value here should match an entry in the META-INF/neoforge.mods.toml file @@ -52,7 +59,8 @@ public class ExtendedAEPlus { // Note that this is necessary if and only if we want *this* class (ExtendedAEPlus) to respond directly to events. // Do not add this line if there are no @SubscribeEvent-annotated functions in this class, like onServerStarting() below. NeoForge.EVENT_BUS.register(this); - + NeoForge.EVENT_BUS.addListener(ExtendedAEPlus::onServerStarted); + NeoForge.EVENT_BUS.addListener(ExtendedAEPlus::onServerStopped); // 注册配置:接入自定义的 ModConfigs modContainer.registerConfig(ModConfig.Type.COMMON, ModConfigs.COMMON_SPEC, "extendedae_plus-common.toml"); modContainer.registerConfig(ModConfig.Type.CLIENT, ModConfigs.CLIENT_SPEC, "extendedae_plus-client.toml"); @@ -69,6 +77,7 @@ public class ExtendedAEPlus { LOGGER.info("HELLO FROM COMMON SETUP"); // 示例日志,避免引用不存在的模板 Config 字段 LOGGER.info("DIRT BLOCK >> {}", BuiltInRegistries.BLOCK.getKey(Blocks.DIRT)); + StorageCells.addCellHandler(InfinityBigIntegerCellHandler.INSTANCE); // 绑定 AE2 的 CraftingBlockEntity 到本模组的自定义加速器方块,避免 AEBaseEntityBlock.blockEntityType 为空 event.enqueueWork(() -> { @@ -116,7 +125,28 @@ public class ExtendedAEPlus { }); } - // 移除示例 addCreative 事件,避免将示例物品加入原版标签 + @Nullable + private static InfinityStorageManager storageManager; + + @Nullable + private static MinecraftServer storageManagerServer; + + private static void onServerStarted(ServerStartedEvent event) { + storageManagerServer = event.getServer(); + storageManager = InfinityStorageManager.getInstance(event.getServer()); + } + + private static void onServerStopped(ServerStoppedEvent event) { + if (storageManagerServer == event.getServer()) { + storageManagerServer = null; + storageManager = null; + } + } + + @Nullable + public static InfinityStorageManager currentStorageManager() { + return storageManager; + } // You can use SubscribeEvent and let the Event Bus discover methods to call @SubscribeEvent diff --git a/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellHandler.java b/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellHandler.java new file mode 100644 index 0000000..3b7aa46 --- /dev/null +++ b/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellHandler.java @@ -0,0 +1,22 @@ +package com.extendedae_plus.ae.api.storage; + +import appeng.api.storage.cells.ICellHandler; +import appeng.api.storage.cells.ISaveProvider; +import com.extendedae_plus.ExtendedAEPlus; +import com.extendedae_plus.ae.items.InfinityBigIntegerCellItem; +import net.minecraft.world.item.ItemStack; + +public class InfinityBigIntegerCellHandler implements ICellHandler { + + public static final InfinityBigIntegerCellHandler INSTANCE = new InfinityBigIntegerCellHandler(); + + @Override + public boolean isCell(ItemStack is) { + return is.getItem() instanceof InfinityBigIntegerCellItem; + } + + @Override + public InfinityBigIntegerCellInventory getCellInventory(ItemStack is, ISaveProvider container) { + return InfinityBigIntegerCellInventory.createInventory(is, container, ExtendedAEPlus.currentStorageManager()); + } +} \ No newline at end of file diff --git a/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellInventory.java b/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellInventory.java new file mode 100644 index 0000000..675c41e --- /dev/null +++ b/src/main/java/com/extendedae_plus/ae/api/storage/InfinityBigIntegerCellInventory.java @@ -0,0 +1,414 @@ +package com.extendedae_plus.ae.api.storage; + +import appeng.api.config.Actionable; +import appeng.api.networking.security.IActionSource; +import appeng.api.stacks.AEItemKey; +import appeng.api.stacks.AEKey; +import appeng.api.stacks.KeyCounter; +import appeng.api.storage.cells.CellState; +import appeng.api.storage.cells.ISaveProvider; +import appeng.api.storage.cells.StorageCell; +import appeng.core.AELog; +import com.extendedae_plus.ae.items.InfinityBigIntegerCellItem; +import com.extendedae_plus.util.storage.InfinityConstants; +import com.extendedae_plus.util.storage.InfinityDataStorage; +import com.extendedae_plus.util.storage.InfinityStorageManager; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.minecraft.core.component.DataComponents; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.network.chat.Component; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.component.CustomData; +import org.jetbrains.annotations.Nullable; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.math.RoundingMode; +import java.util.Objects; +import java.util.UUID; + +/** + * This code is inspired by AE2Things[](https://github.com/Technici4n/AE2Things-Forge), licensed under the MIT License.

+ * Original copyright (c) Technici4n

+ */ +public class InfinityBigIntegerCellInventory implements StorageCell { + private final InfinityBigIntegerCellItem cell; + // 磁盘本身 + private final ItemStack self; + @Nullable + private final InfinityStorageManager storageManager; + // AE2 提供的保存提供者,用于在容器中批量保存时触发回调 + private final ISaveProvider container; + // 存储物品键和数量的映射 + private Object2ObjectMap AEKey2AmountsMap; + // 存储的物品种类数量 + private int totalAEKeyType; + // 存储的物品总数 + private BigInteger totalAEKey2Amounts = BigInteger.ZERO; + // 标记是否已持久化到 SavedData + private boolean isPersisted = true; + + + public InfinityBigIntegerCellInventory(InfinityBigIntegerCellItem cell, + ItemStack stack, + ISaveProvider saveProvider, + @Nullable InfinityStorageManager storageManager) { + // 保存存储单元类型(InfinityBigIntegerCellItem 实例),用于访问磁盘属性 + this.cell = cell; + // 保存物品堆栈,表示磁盘本身,包含运行时的 NBT 数据 + this.self = stack; + // 保存提供者,用于触发数据保存 + this.container = saveProvider; + // 初始化 storedAmounts 为 null,延迟加载物品数据 + this.AEKey2AmountsMap = null; + this.storageManager = storageManager; + // 初始化磁盘数据 + initData(); + } + + // 将 BigInteger 格式化为带单位的字符串,保留两位小数 + public static String formatBigInteger(BigInteger number) { + // 使用方法局部的 DecimalFormat,避免静态共享的非线程安全问题 + java.text.DecimalFormat df = new java.text.DecimalFormat("#.##"); + BigDecimal bd = new BigDecimal(number); + BigDecimal thousand = new BigDecimal(1000); + String[] units = new String[]{"", "K", "M", "G", "T", "P", "E", "Z", "Y"}; + int idx = 0; + while (bd.compareTo(thousand) >= 0 && idx < units.length - 1) { + bd = bd.divide(thousand, 2, RoundingMode.HALF_UP); + idx++; + } + if (idx == 0) { + return bd.setScale(0, RoundingMode.DOWN).toPlainString(); + } + return df.format(bd.doubleValue()) + units[idx]; + } + + // 静态方法,创建存储单元库存 + public static InfinityBigIntegerCellInventory createInventory(ItemStack stack, + ISaveProvider saveProvider, + @Nullable InfinityStorageManager storageManager) { + // 检查物品堆栈是否为空 + Objects.requireNonNull(stack, "Cannot create cell inventory for null itemstack"); + // 检查物品是否为 IDISKCellItem 类型 + if (!(stack.getItem() instanceof InfinityBigIntegerCellItem cell)) { + return null; + } + // 创建并返回新的 DISKCellInventory 实例 + return new InfinityBigIntegerCellInventory(cell, stack, saveProvider, storageManager); + } + + // 获取磁盘的 InfinityDataStorage 数据 + private InfinityDataStorage getCellStorage() { + // 如果磁盘有 UUID,返回对应的 InfinityDataStorage + if (getUUID() != null && this.storageManager != null) { + return storageManager.getOrCreateCell(getUUID()); + } else { + // 否则返回空的 InfinityDataStorage + return InfinityDataStorage.EMPTY; + } + } + + // 初始化磁盘数据 + private void initData() { + // 如果磁盘有 UUID,加载存储的物品数据 + if (hasUUID()) { + this.totalAEKeyType = getCellStorage().amounts.size(); + this.totalAEKey2Amounts = getCellStorage().itemCount.equals(BigInteger.ZERO) ? + BigInteger.ZERO : + getCellStorage().itemCount; + + } else { + // 否则初始化为空 + this.totalAEKeyType = 0; + this.totalAEKey2Amounts = BigInteger.ZERO; + // 加载物品数据 + getCellStoredMap(); + } + } + + // 获取存储单元的状态(空、部分填充) + @Override + public CellState getStatus() { + // 如果没有存储任何物品,返回空状态 + if (this.getTotalAEKey2Amounts().equals(BigInteger.ZERO)) { + return CellState.EMPTY; + } + // 否则返回满状态 + return CellState.NOT_EMPTY; + } + + // 获取存储单元的待机能耗 + @Override + public double getIdleDrain() { + return 512; + } + + // 持久化存储单元数据到全局存储 + @Override + public void persist() { + if (this.isPersisted || this.storageManager == null) + return; + + if (this.totalAEKey2Amounts.equals(BigInteger.ZERO)) { + if (hasUUID()) { + this.storageManager.removeCell(getUUID()); + // 从 DataComponents.CUSTOM_DATA 里移除对应字段 + CustomData data = self.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY); + CompoundTag tag = data.copyTag(); + tag.remove(InfinityConstants.INFINITY_CELL_UUID); + tag.remove(InfinityConstants.INFINITY_ITEM_TOTAL); + tag.remove(InfinityConstants.INFINITY_ITEM_TYPES); + // backward compat + tag.remove(InfinityConstants.INFINITY_CELL_ITEM_COUNT); + + self.set(DataComponents.CUSTOM_DATA, CustomData.of(tag)); + + initData(); + } + return; + } + + // 创建物品键列表 + ListTag keys = new ListTag(); + // 创建物品数量列表 + ListTag amounts = new ListTag(); + // 初始化物品总数 + BigInteger itemCount = BigInteger.ZERO; + + for (var entry : this.AEKey2AmountsMap.object2ObjectEntrySet()) { + BigInteger amount = entry.getValue(); + // 如果数量大于 0,添加到键和数量列表 + if (amount.compareTo(BigInteger.ZERO) > 0) { + keys.add(entry.getKey().toTagGeneric(this.storageManager.getRegistries())); + CompoundTag amountTag = new CompoundTag(); + amountTag.putByteArray("value", amount.toByteArray()); + amounts.add(amountTag); + + itemCount = itemCount.add(amount); + } + } + + if (keys.isEmpty()) { + this.storageManager.updateCell(getUUID(), new InfinityDataStorage()); + } else { + this.storageManager.modifyDisk(getUUID(), keys, amounts, itemCount); + } + + // 更新存储的物品种类数量 + this.totalAEKeyType = this.AEKey2AmountsMap.size(); + // 更新存储的物品总数 + this.totalAEKey2Amounts = itemCount; + // 将物品总数与种类数量存入物品堆栈的 NBT(用于快捷查看/tooltip),同时保留旧字段以兼容历史版本 + + // 写回 DataComponents.CUSTOM_DATA(替代 getOrCreateTag) + CompoundTag tag = self.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).copyTag(); + tag.putByteArray(InfinityConstants.INFINITY_ITEM_TOTAL, itemCount.toByteArray()); + tag.putInt(InfinityConstants.INFINITY_ITEM_TYPES, this.totalAEKeyType); + tag.putByteArray(InfinityConstants.INFINITY_CELL_ITEM_COUNT, itemCount.toByteArray()); + self.set(DataComponents.CUSTOM_DATA, CustomData.of(tag)); + // 标记数据已持久化 + this.isPersisted = true; + } + + // 获取存储单元的描述(此处返回null,可自定义) + @Override + public Component getDescription() { + return null; + } + + // 获取存储的物品总数 + public BigInteger getTotalAEKey2Amounts() { + return this.totalAEKey2Amounts; + } + + // 获取存储的物品种类数量 + public int getTotalAEKeyType() { + return this.totalAEKeyType; + } + + // 判断物品堆栈是否有UUID + public boolean hasUUID() { + CustomData data = self.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY); + return !data.isEmpty() && data.copyTag().contains(InfinityConstants.INFINITY_CELL_UUID); + } + + // 获取物品堆栈的UUID + public UUID getUUID() { + CustomData data = self.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY); + if (!data.isEmpty() && data.copyTag().contains(InfinityConstants.INFINITY_CELL_UUID)) { + return data.copyTag().getUUID(InfinityConstants.INFINITY_CELL_UUID); + } + return null; + } + + // 获取或初始化存储映射 + private Object2ObjectMap getCellStoredMap() { + if (AEKey2AmountsMap == null) { + AEKey2AmountsMap = new Object2ObjectOpenHashMap<>(); + this.loadCellStoredMap(); + } + return AEKey2AmountsMap; + } + + // 获取所有可用的物品堆栈及其数量 + @Override + public void getAvailableStacks(KeyCounter out) { + BigInteger maxLong = BigInteger.valueOf(Long.MAX_VALUE); + if (this.getCellStoredMap() == null) return; + for (var entry : this.getCellStoredMap().object2ObjectEntrySet()) { + AEKey key = entry.getKey(); + BigInteger value = entry.getValue(); + + // 获取 KeyCounter 中已有的值 + long existing = out.get(key); + + // 计算总和并限制到 Long.MAX_VALUE + BigInteger sum = BigInteger.valueOf(existing).add(value); + long toSet = sum.compareTo(maxLong) > 0 ? Long.MAX_VALUE : sum.longValue(); + // 更新 KeyCounter + if (existing == Long.MAX_VALUE) { + continue; + } + long delta = toSet - existing; + if (delta != 0) { + out.add(key, delta); + } + } + } + + + // 从存储中加载物品映射 + private void loadCellStoredMap() { + if (this.storageManager == null) { + return; + } + + boolean dataCorruption = false; + if (self.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY).isEmpty()) return; + + var keys = getCellStorage().keys; + var amounts = getCellStorage().amounts; + // 数据损坏 + if (keys.size() != amounts.size()) { + AELog.warn("Loading storage cell with mismatched amounts/tags: %d != %d", amounts.size(), keys.size()); + } + + var registries = this.storageManager.getRegistries(); + + // 遍历数量和键,加载到 AEKey2AmountsMap + for (int i = 0; i < amounts.size(); i++) { + AEKey key = AEKey.fromTagGeneric(registries,keys.getCompound(i)); + BigInteger amount = new BigInteger(amounts.getCompound(i).getByteArray("value")); + // 检查数据是否损坏 + if (amount.compareTo(BigInteger.ZERO) <= 0 || key == null) { + dataCorruption = true; + } else { + AEKey2AmountsMap.put(key, amount); + } + } + if (dataCorruption) { + this.saveChanges(); + } + } + + // 标记数据需要保存,并通知容器或直接持久化 + private void saveChanges() { + // 更新存储的物品种类数量 + this.totalAEKeyType = this.AEKey2AmountsMap.size(); + // 重置物品总数 + this.totalAEKey2Amounts = BigInteger.ZERO; + // 计算物品总数 + for (BigInteger AEKey2Amounts : this.AEKey2AmountsMap.values()) { + this.totalAEKey2Amounts = this.totalAEKey2Amounts.add(AEKey2Amounts); + } + // 标记数据未持久化 + this.isPersisted = false; + // 如果有保存提供者,通知保存 + if (this.container != null) { + this.container.saveChanges(); + } else { + // 否则立即持久化 + this.persist(); + } + } + + // 插入物品到存储单元 + @Override + public long insert(AEKey what, long amount, Actionable mode, IActionSource source) { + // 数量为0或类型不匹配直接返回 + if (amount == 0) { + return 0; + } + // 不允许存储无限单元自身 + if (what instanceof AEItemKey itemKey && itemKey.getItem() instanceof InfinityBigIntegerCellItem) { + return 0; + } + + // 如果没有 UUID,且服务器端存储管理器已就绪,则生成 UUID 并初始化存储 + if (storageManager != null && !this.hasUUID()) { + // 取出自定义 NBT(如果没有就返回空) + CustomData data = self.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY); + CompoundTag tag = data.copyTag(); + + // 生成新的 UUID 并写入 + UUID newUUID = UUID.randomUUID(); + tag.putUUID(InfinityConstants.INFINITY_CELL_UUID, newUUID); + + // 回写到 ItemStack + self.set(DataComponents.CUSTOM_DATA, CustomData.of(tag)); + + // 初始化存储 + this.storageManager.getOrCreateCell(newUUID); + + // 加载已存储的映射 + loadCellStoredMap(); + } + // 获取当前物品数量 + BigInteger currentAmount = this.getCellStoredMap().getOrDefault(what, BigInteger.ZERO); + + if (mode == Actionable.MODULATE) { + // 实际插入,更新数量并保存 + BigInteger newAmount = currentAmount.add(BigInteger.valueOf(amount)); + getCellStoredMap().put(what, newAmount); + this.saveChanges(); + } + return amount; + } + + // 从存储单元提取物品 + @Override + public long extract(AEKey what, long amount, Actionable mode, IActionSource source) { + BigInteger currentAmount = this.getCellStoredMap().getOrDefault(what, BigInteger.ZERO); + // 如果有物品可提取 + if (currentAmount.compareTo(BigInteger.ZERO) > 0) { + + BigInteger requested = BigInteger.valueOf(amount); + + // 如果提取数量大于等于当前数量 + if (requested.compareTo(currentAmount) >= 0) { + if (mode == Actionable.MODULATE) { + getCellStoredMap().remove(what); + this.saveChanges(); + } + return currentAmount.compareTo(BigInteger.valueOf(Long.MAX_VALUE)) > 0 ? Long.MAX_VALUE : currentAmount.longValue(); + } else { + // 提取部分数量 + if (mode == Actionable.MODULATE) { + getCellStoredMap().put(what, currentAmount.subtract(requested)); + this.saveChanges(); + } + return requested.longValue(); + } + } + return 0; + } + + // 获取存储单元内所有物品的总数量(格式化字符串) + public String getTotalStorage() { + // 使用缓存的 totalStored,避免每次全表扫描 + return formatBigInteger(totalAEKey2Amounts); + } +} diff --git a/src/main/java/com/extendedae_plus/ae/items/InfinityBigIntegerCellItem.java b/src/main/java/com/extendedae_plus/ae/items/InfinityBigIntegerCellItem.java new file mode 100644 index 0000000..2ae9fb0 --- /dev/null +++ b/src/main/java/com/extendedae_plus/ae/items/InfinityBigIntegerCellItem.java @@ -0,0 +1,88 @@ +package com.extendedae_plus.ae.items; + +import appeng.api.config.FuzzyMode; +import appeng.api.storage.cells.ICellWorkbenchItem; +import com.extendedae_plus.ae.api.storage.InfinityBigIntegerCellInventory; +import com.extendedae_plus.util.storage.InfinityConstants; +import com.google.common.base.Preconditions; +import net.minecraft.ChatFormatting; +import net.minecraft.core.component.DataComponents; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.item.component.CustomData; + +import java.math.BigInteger; +import java.util.List; + +public class InfinityBigIntegerCellItem extends Item implements ICellWorkbenchItem { + + public InfinityBigIntegerCellItem() { + super(new Properties().stacksTo(1).fireResistant()); + } + + @Override + public void appendHoverText(ItemStack stack, TooltipContext context, List tooltip, TooltipFlag tooltipFlag) { + tooltip.add(Component.translatable("tooltip.extendedae_plus.infinity_biginteger_cell.summon1")); + tooltip.add(Component.translatable("tooltip.extendedae_plus.infinity_biginteger_cell.summon2")); + + Preconditions.checkArgument(stack.getItem() == this); + // 仅在 ItemStack 自身存在 UUID 时显示 UUID,避免触发持久化或加载逻辑 + CustomData customData = stack.getOrDefault(DataComponents.CUSTOM_DATA, CustomData.EMPTY); + + if (!customData.isEmpty()) { + CompoundTag tag = customData.copyTag(); + + if (tag.contains(InfinityConstants.INFINITY_CELL_UUID)) { + String uuidStr = tag.getUUID(InfinityConstants.INFINITY_CELL_UUID).toString(); + tooltip.add( + Component.literal("UUID: ").withStyle(ChatFormatting.GRAY) + .append(Component.literal(uuidStr).withStyle(ChatFormatting.YELLOW)) + ); + } + + if (tag.contains(InfinityConstants.INFINITY_ITEM_TYPES)) { + try { + int types = tag.getInt(InfinityConstants.INFINITY_ITEM_TYPES); + tooltip.add( + Component.literal("Types: ").withStyle(ChatFormatting.GRAY) + .append(Component.literal(String.valueOf(types)).withStyle(ChatFormatting.GREEN)) + ); + } catch (Exception ignored) {} + } + + if (tag.contains(InfinityConstants.INFINITY_ITEM_TOTAL)) { + try { + byte[] bytes = tag.getByteArray(InfinityConstants.INFINITY_ITEM_TOTAL); + BigInteger total = new BigInteger(bytes); + String formatted = InfinityBigIntegerCellInventory.formatBigInteger(total); + tooltip.add( + Component.literal("Total: ").withStyle(ChatFormatting.GRAY) + .append(Component.literal(formatted).withStyle(ChatFormatting.AQUA)) + ); + } catch (Exception ignored) {} + } else if (tag.contains(InfinityConstants.INFINITY_CELL_ITEM_COUNT)) { + try { + byte[] bytes = tag.getByteArray(InfinityConstants.INFINITY_CELL_ITEM_COUNT); + BigInteger total = new BigInteger(bytes); + String formatted = InfinityBigIntegerCellInventory.formatBigInteger(total); + tooltip.add( + Component.literal("Total: ").withStyle(ChatFormatting.GRAY) + .append(Component.literal(formatted).withStyle(ChatFormatting.AQUA)) + ); + } catch (Exception ignored) {} + } + } + } + + @Override + public FuzzyMode getFuzzyMode(ItemStack itemStack) { + return null; + } + + @Override + public void setFuzzyMode(ItemStack itemStack, FuzzyMode fuzzyMode) { + } +} \ No newline at end of file diff --git a/src/main/java/com/extendedae_plus/init/ModCreativeTabs.java b/src/main/java/com/extendedae_plus/init/ModCreativeTabs.java index 10d9144..d5fc5da 100644 --- a/src/main/java/com/extendedae_plus/init/ModCreativeTabs.java +++ b/src/main/java/com/extendedae_plus/init/ModCreativeTabs.java @@ -29,6 +29,8 @@ public final class ModCreativeTabs { output.accept(ModItems.createEntitySpeedCardStack((byte) 4)); output.accept(ModItems.createEntitySpeedCardStack((byte) 8)); output.accept(ModItems.createEntitySpeedCardStack((byte) 16)); + + output.accept(ModItems.INFINITY_BIGINTEGER_CELL_ITEM.get()); }) .build()); diff --git a/src/main/java/com/extendedae_plus/init/ModItems.java b/src/main/java/com/extendedae_plus/init/ModItems.java index e985c1e..c059433 100644 --- a/src/main/java/com/extendedae_plus/init/ModItems.java +++ b/src/main/java/com/extendedae_plus/init/ModItems.java @@ -3,6 +3,7 @@ package com.extendedae_plus.init; import com.extendedae_plus.ExtendedAEPlus; import com.extendedae_plus.ae.definitions.upgrades.EntitySpeedCardItem; import com.extendedae_plus.ae.items.EntitySpeedTickerPartItem; +import com.extendedae_plus.ae.items.InfinityBigIntegerCellItem; import net.minecraft.world.item.BlockItem; import net.minecraft.world.item.Item; import net.minecraft.world.item.ItemStack; @@ -62,6 +63,11 @@ public final class ModItems { () -> new EntitySpeedCardItem(new Item.Properties()) ); + public static final DeferredItem INFINITY_BIGINTEGER_CELL_ITEM = ITEMS.register( + "infinity_biginteger_cell", InfinityBigIntegerCellItem::new + ); + + /** * 工厂:创建带 multiplier 的实体加速卡 ItemStack(2/4/8/16) */ diff --git a/src/main/java/com/extendedae_plus/util/storage/InfinityConstants.java b/src/main/java/com/extendedae_plus/util/storage/InfinityConstants.java new file mode 100644 index 0000000..1fcb598 --- /dev/null +++ b/src/main/java/com/extendedae_plus/util/storage/InfinityConstants.java @@ -0,0 +1,30 @@ +package com.extendedae_plus.util.storage; + +public interface InfinityConstants { + // 当前磁盘格式版本号,增加字段用于向后/向前兼容 + int FORMAT_VERSION = 2; + // 存储磁盘数据的格式版本号 + String FORMAT_VERSION_FIELD = "infinity_format_version"; + + // savedData 文件名常量 + String SAVE_FILE_NAME = "infinity_biginteger_cells"; + + // 磁盘的唯一标识符键名,存储在 ItemStack 和 InfinityStorageManager 中 + String INFINITY_CELL_UUID = "infinity_cell_uuid"; + // 单个磁盘的 InfinityDataStorage 数据键名 + String INFINITY_CELL_DATA = "infinity_cell_data"; + // 所有磁盘数据的列表键名,存储在 InfinityStorageManager 的 NBT 中 + String INFINITY_CELL_LIST = "infinity_cell_list"; + + // 磁盘中所有物品键的键名(ListTag of CompoundTag) + String INFINITY_CELL_KEYS = "infinity_cell_keys"; + // 磁盘中每种物品数量的键名(ListTag of CompoundTag,包含 "value") + String INFINITY_CELL_AMOUNTS = "infinity_cell_amounts"; + // 磁盘中所有物品的总数键名(ListTag,包含一个 CompoundTag 的 "value") + String INFINITY_CELL_ITEM_COUNT = "infinity_cell_item_count"; + + // ItemStack 的 NBT 中存储总物品数量的键名 + String INFINITY_ITEM_TOTAL = "infinity_item_total"; + // ItemStack 的 NBT 中存储物品种类数量的键名 + String INFINITY_ITEM_TYPES = "infinity_item_types"; +} diff --git a/src/main/java/com/extendedae_plus/util/storage/InfinityDataStorage.java b/src/main/java/com/extendedae_plus/util/storage/InfinityDataStorage.java new file mode 100644 index 0000000..6462128 --- /dev/null +++ b/src/main/java/com/extendedae_plus/util/storage/InfinityDataStorage.java @@ -0,0 +1,48 @@ +package com.extendedae_plus.util.storage; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; + +import java.math.BigInteger; + +/** + * This code is inspired by AE2Things[](https://github.com/Technici4n/AE2Things-Forge), licensed under the MIT License.

+ * Original copyright (c) Technici4n

+ */ +public class InfinityDataStorage { + // 定义一个静态常量 EMPTY,表示一个空的 DataStorage 实例,用于默认或占位场景 + public static final InfinityDataStorage EMPTY = new InfinityDataStorage(); + + public ListTag keys; + public ListTag amounts; + // 存储磁盘中物品的总数,使用 BigInteger 支持大容量 + public BigInteger itemCount; + + public InfinityDataStorage() { + this(new ListTag(), new ListTag(), BigInteger.ZERO); + } + + private InfinityDataStorage(ListTag keys, ListTag amounts, BigInteger itemCount) { + this.keys = keys; + this.amounts = amounts; + this.itemCount = itemCount; + } + + // 将 DataStorage 数据序列化为 NBT 格式 + public CompoundTag serializeNBT() { + CompoundTag nbt = new CompoundTag(); + nbt.put(InfinityConstants.INFINITY_CELL_KEYS, keys); + nbt.put(InfinityConstants.INFINITY_CELL_AMOUNTS, amounts); + nbt.putByteArray(InfinityConstants.INFINITY_CELL_ITEM_COUNT, itemCount.toByteArray()); + return nbt; + } + + // 从 NBT 数据反序列化创建 DataStorage 实例 + public static InfinityDataStorage loadFromNBT(CompoundTag nbt) { + ListTag keys = nbt.getList(InfinityConstants.INFINITY_CELL_KEYS, ListTag.TAG_COMPOUND); + ListTag amounts = nbt.getList(InfinityConstants.INFINITY_CELL_AMOUNTS, ListTag.TAG_COMPOUND); + BigInteger itemCount = new BigInteger(nbt.getByteArray(InfinityConstants.INFINITY_CELL_ITEM_COUNT)); + // 使用加载的数据创建新的 DataStorage 实例 + return new InfinityDataStorage(keys, amounts, itemCount); + } +} diff --git a/src/main/java/com/extendedae_plus/util/storage/InfinityStorageManager.java b/src/main/java/com/extendedae_plus/util/storage/InfinityStorageManager.java new file mode 100644 index 0000000..fabcfff --- /dev/null +++ b/src/main/java/com/extendedae_plus/util/storage/InfinityStorageManager.java @@ -0,0 +1,151 @@ +package com.extendedae_plus.util.storage; + +import net.minecraft.core.HolderLookup; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.saveddata.SavedData; + +import javax.annotation.Nullable; +import java.lang.ref.WeakReference; +import java.math.BigInteger; +import java.util.*; + +/** + * This code is inspired by AE2Things[](https://github.com/Technici4n/AE2Things-Forge), licensed under the MIT License.

+ * Original copyright (c) Technici4n

+ */ +public class InfinityStorageManager extends SavedData { + private static final Factory FACTORY = new Factory<>(InfinityStorageManager::new, InfinityStorageManager::readNbt); + // 存储所有磁盘的Map,键为UUID,值为DataStorage对象 + private final Map cells; + @Nullable + private WeakReference registries; + + + // 构造方法,初始化磁盘Map + public InfinityStorageManager() { + cells = new HashMap<>(); + // 标记数据为“脏”,确保新创建的实例在下次保存时写入磁盘 + this.setDirty(); + } + + // 私有构造方法,用于从已有Map创建StorageManager + private InfinityStorageManager(Map cells) { + // 确保使用已加载的数据 + this.cells = cells; + // 标记数据为“脏”,确保新创建的实例在下次保存时写入磁盘 + this.setDirty(); + } + + + // 静态方法,从 NBT 数据反序列化创建 StorageManager 实例 + public static InfinityStorageManager readNbt(CompoundTag nbt, HolderLookup.Provider registries) { + // 读取格式版本,缺省视为 1(兼容旧档) + int version = nbt.contains(InfinityConstants.FORMAT_VERSION_FIELD) ? + nbt.getInt(InfinityConstants.FORMAT_VERSION_FIELD) : + 1; + + Map cells = new HashMap<>(); + // 从 NBT 中获取磁盘数据列表,指定类型为 CompoundTag(TAG_COMPOUND) + ListTag cellList = nbt.getList(InfinityConstants.INFINITY_CELL_LIST, CompoundTag.TAG_COMPOUND); + // 遍历 cellList 中的每个 CompoundTag + for (int i = 0; i < cellList.size(); i++) { + // 获取当前索引的 CompoundTag,表示单个磁盘的数据 + CompoundTag cell = cellList.getCompound(i); + // 从 CompoundTag 中读取 UUID 和 DataStorage 数据,并存入 cells 映射 + cells.put(cell.getUUID(InfinityConstants.INFINITY_CELL_UUID), InfinityDataStorage.loadFromNBT(cell.getCompound(InfinityConstants.INFINITY_CELL_DATA))); + } + // 使用加载的 cells 数据创建新的 StorageManager 实例 + return new InfinityStorageManager(cells); + } + + + @Override + public CompoundTag save(CompoundTag nbt, HolderLookup.Provider provider) { + // 将内存中的所有 cell 序列化为一个 ListTag + ListTag cellList = new ListTag(); + for (Map.Entry entry : cells.entrySet()) { + CompoundTag cell = new CompoundTag(); + cell.putUUID(InfinityConstants.INFINITY_CELL_UUID, entry.getKey()); + cell.put(InfinityConstants.INFINITY_CELL_DATA, entry.getValue().serializeNBT()); + cellList.add(cell); + } + nbt.put(InfinityConstants.INFINITY_CELL_LIST, cellList); + // 写入当前格式版本号,便于未来迁移与兼容判断 + nbt.putInt(InfinityConstants.FORMAT_VERSION_FIELD, InfinityConstants.FORMAT_VERSION); + return nbt; + } + + // 返回当前已加载的所有 UUID 的不可变视图,用于命令或调试用途 + public Set getAllLoadedUUIDs() { + return Collections.unmodifiableSet(cells.keySet()); + } + + // 更新或添加某个 UUID 对应的数据并标记为脏(需要保存) + public void updateCell(UUID uuid, InfinityDataStorage infinityDataStorage) { + cells.put(uuid, infinityDataStorage); + // 标记数据为“脏”,确保修改后的数据会在下次保存时写入磁盘 + setDirty(); + } + + // 删除某个 UUID 的持久化记录并标记为脏 + public void removeCell(UUID uuid) { + cells.remove(uuid); + // 标记数据为“脏”,确保移除操作会在下次保存时反映到磁盘 + setDirty(); + } + + // 检查指定 UUID 是否存在于 disks 映射中 + public boolean hasUUID(UUID uuid) { + // 返回 cells 映射是否包含指定 UUID + return cells.containsKey(uuid); + } + + // 获取或创建某个 UUID 对应的数据容器 + public InfinityDataStorage getOrCreateCell(UUID uuid) { + // 检查 cells 映射中是否不存在指定 UUID + if (!cells.containsKey(uuid)) { + updateCell(uuid, new InfinityDataStorage()); + } + // 返回指定 UUID 对应的 DataStorage 对象 + return cells.get(uuid); + } + + // 修改指定 UUID 的磁盘数据,包括堆栈键、数量和总项目数 + public void modifyDisk(UUID uuid, ListTag keys, ListTag amounts, BigInteger itemCount) { + // 获取或创建指定 UUID 的 DataStorage 对象 + InfinityDataStorage cellToModify = getOrCreateCell(uuid); + if (keys != null && amounts != null) { + cellToModify.keys = keys; + cellToModify.amounts = amounts; + } + // 更新 DataStorage 的 itemCount 字段 + cellToModify.itemCount = itemCount; + // 将修改后的 DataStorage 对象更新到 cells 映射 + updateCell(uuid, cellToModify); + } + + + public static InfinityStorageManager getInstance(MinecraftServer server) { + ServerLevel world = server.getLevel(ServerLevel.OVERWORLD); + var manager = world.getDataStorage().computeIfAbsent(FACTORY, InfinityConstants.SAVE_FILE_NAME); + manager.registries = new WeakReference<>(server.registryAccess()); + return manager; + } + + public HolderLookup.Provider getRegistries() { + var r = this.registries; + if (r == null) { + throw new IllegalStateException("StorageManager was not initialized properly."); + } + + var registries = r.get(); + if (registries == null) { + throw new IllegalStateException("Using a StorageManager whose server was already closed"); + } + + return registries; + } +} diff --git a/src/main/resources/assets/extendedae_plus/lang/en_us.json b/src/main/resources/assets/extendedae_plus/lang/en_us.json index babef8e..8775525 100644 --- a/src/main/resources/assets/extendedae_plus/lang/en_us.json +++ b/src/main/resources/assets/extendedae_plus/lang/en_us.json @@ -22,6 +22,9 @@ "item.extendedae_plus.entity_speed_card.x4": "Entity Speed Card (x4)", "item.extendedae_plus.entity_speed_card.x8": "Entity Speed Card (x8)", "item.extendedae_plus.entity_speed_card.x16": "Entity Speed Card (x16)", + "item.extendedae_plus.infinity_biginteger_cell": "§4De§cvou§6rer §eof §aCo§bsmic §dSilence", + "tooltip.extendedae_plus.infinity_biginteger_cell.summon1": "§6Through ninefold sacrifice, the Void echoes§r—§8Iava, Lord of the Void§r, bestows upon thee this artifact", + "tooltip.extendedae_plus.infinity_biginteger_cell.summon2": "§b—§4A §dUni§cverse §eWith§ain §6A §bSin§5gle §9Point", "tooltip.extendedae_plus.entity_speed_card.multiplier": "Multiplier: %s", "tooltip.extendedae_plus.entity_speed_card.max": "Maximum Effect: %s Times", diff --git a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json index 8592356..fe2d4a8 100644 --- a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json +++ b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json @@ -22,6 +22,9 @@ "item.extendedae_plus.entity_speed_card.x4": "实体加速卡 (x4)", "item.extendedae_plus.entity_speed_card.x8": "实体加速卡 (x8)", "item.extendedae_plus.entity_speed_card.x16": "实体加速卡 (x16)", + "item.extendedae_plus.infinity_biginteger_cell": "§4吞§c噬§6万§e籁§a的§b寂§d静", + "tooltip.extendedae_plus.infinity_biginteger_cell.summon1": "§6九重献祭, 终得虚空回响§r——觐见§8虚空之主Iava§r, 赐汝此物", + "tooltip.extendedae_plus.infinity_biginteger_cell.summon2": "§b——§4方§d寸§c之§e间§a, §6自§b有§5千§9寰", "tooltip.extendedae_plus.entity_speed_card.multiplier": "乘数: %s", "tooltip.extendedae_plus.entity_speed_card.max": "最大生效: %s 倍", From 9ac7d118138deff5ff38a74592839a63e3a7a695 Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Fri, 26 Sep 2025 17:57:42 +0800 Subject: [PATCH 5/6] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E5=AE=9E=E4=BD=93?= =?UTF-8?q?=E5=8A=A0=E9=80=9F=E5=99=A8=E9=BB=91=E5=90=8D=E5=8D=95=E5=92=8C?= =?UTF-8?q?=E5=80=8D=E7=8E=87=E5=90=8D=E5=8D=95=E6=97=A0=E6=B3=95=E7=83=AD?= =?UTF-8?q?=E9=87=8D=E8=BD=BD=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../util/ConfigParsingUtils.java | 83 ++++++++++++------- 1 file changed, 53 insertions(+), 30 deletions(-) diff --git a/src/main/java/com/extendedae_plus/util/ConfigParsingUtils.java b/src/main/java/com/extendedae_plus/util/ConfigParsingUtils.java index c1f2395..0cf6ddc 100644 --- a/src/main/java/com/extendedae_plus/util/ConfigParsingUtils.java +++ b/src/main/java/com/extendedae_plus/util/ConfigParsingUtils.java @@ -114,48 +114,71 @@ public final class ConfigParsingUtils { // ------------------ 全局缓存与接口 ------------------ private static volatile List cachedBlacklist = null; private static volatile List cachedMultiplierEntries = null; + private static volatile List cachedBlacklistSourceSnapshot = null; + private static volatile List cachedMultiplierSourceSnapshot = null; private static final Object CACHE_LOCK = new Object(); /** * 获取已解析并缓存的黑名单(线程安全、懒加载)。 */ - public static List getCachedBlacklist(List source) { - if (cachedBlacklist == null) { - synchronized (CACHE_LOCK) { - if (cachedBlacklist == null) { - cachedBlacklist = compilePatterns(source); - } - } - } else { - synchronized (CACHE_LOCK) { - List newCachedBlackList = compilePatterns(source); - if (!cachedBlacklist.equals(newCachedBlackList)) { - cachedBlacklist = newCachedBlackList; - } - } + public static List getCachedBlacklist(java.util.List source) { + List normalized = normalizeSource(source); + + // fast path: identical snapshot reference or equal contents + if (cachedBlacklist != null && listEquals(cachedBlacklistSourceSnapshot, normalized)) { + return Collections.unmodifiableList(cachedBlacklist); + } + + synchronized (CACHE_LOCK) { + if (cachedBlacklist == null || !listEquals(cachedBlacklistSourceSnapshot, normalized)) { + cachedBlacklist = compilePatterns(normalized); + cachedBlacklistSourceSnapshot = normalized.isEmpty() ? Collections.emptyList() : new ArrayList<>(normalized); + } + return Collections.unmodifiableList(cachedBlacklist); } - return Collections.unmodifiableList(cachedBlacklist); } /** * 获取已解析并缓存的倍率列表(线程安全、懒加载)。 */ - public static List getCachedMultiplierEntries(List source) { - if (cachedMultiplierEntries == null) { - synchronized (CACHE_LOCK) { - if (cachedMultiplierEntries == null) { - cachedMultiplierEntries = parseMultiplierList(source); - } - } - }else { - synchronized (CACHE_LOCK) { - List newCachedMultiplierEntries = parseMultiplierList(source); - if (!cachedMultiplierEntries.equals(newCachedMultiplierEntries)) { - cachedMultiplierEntries = newCachedMultiplierEntries; - } - } + public static List getCachedMultiplierEntries(java.util.List source) { + List normalized = normalizeSource(source); + + if (cachedMultiplierEntries != null && listEquals(cachedMultiplierSourceSnapshot, normalized)) { + return Collections.unmodifiableList(cachedMultiplierEntries); } - return Collections.unmodifiableList(cachedMultiplierEntries); + + synchronized (CACHE_LOCK) { + if (cachedMultiplierEntries == null || !listEquals(cachedMultiplierSourceSnapshot, normalized)) { + cachedMultiplierEntries = parseMultiplierList(normalized); + cachedMultiplierSourceSnapshot = normalized.isEmpty() ? Collections.emptyList() : new ArrayList<>(normalized); + } + return Collections.unmodifiableList(cachedMultiplierEntries); + } + } + + // Normalize the incoming source list: trim entries, drop blanks, keep stable ordering + private static List normalizeSource(java.util.List source) { + List out = new ArrayList<>(); + if (source == null) return out; + for (String s : source) { + if (s == null) continue; + String t = s.trim(); + if (t.isEmpty()) continue; + out.add(t); + } + return out; + } + + // Null-safe equality for two lists of strings. Uses size + element equals. + private static boolean listEquals(List a, List b) { + if (a == b) return true; + if (a == null || b == null) return false; + if (a.size() != b.size()) return false; + for (int i = 0; i < a.size(); i++) { + if (!a.get(i).equals(b.get(i))) return false; + } + return true; } /** From fc25e2bd1c827d27bb91a99ccbce1a2b17b999eb Mon Sep 17 00:00:00 2001 From: C-H716 <1536152356@qq.com> Date: Fri, 26 Sep 2025 22:09:20 +0800 Subject: [PATCH 6/6] =?UTF-8?q?feat:=20=E5=AE=9E=E4=BD=93=E5=8A=A0?= =?UTF-8?q?=E9=80=9F=E5=99=A8=E7=95=8C=E9=9D=A2=E6=98=BE=E7=A4=BA=E8=83=BD?= =?UTF-8?q?=E9=87=8F=E6=98=AF=E5=90=A6=E5=85=85=E8=B6=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../ae/menu/EntitySpeedTickerMenu.java | 44 ++++++++++++----- .../ae/parts/EntitySpeedTickerPart.java | 47 ++++++++++++++----- .../ae/screen/EntitySpeedTickerScreen.java | 7 +++ .../ae2/screens/entity_speed_ticker.json | 3 +- .../assets/extendedae_plus/lang/en_us.json | 1 + .../assets/extendedae_plus/lang/zh_cn.json | 1 + 6 files changed, 78 insertions(+), 25 deletions(-) diff --git a/src/main/java/com/extendedae_plus/ae/menu/EntitySpeedTickerMenu.java b/src/main/java/com/extendedae_plus/ae/menu/EntitySpeedTickerMenu.java index e72e8ce..40e1e28 100644 --- a/src/main/java/com/extendedae_plus/ae/menu/EntitySpeedTickerMenu.java +++ b/src/main/java/com/extendedae_plus/ae/menu/EntitySpeedTickerMenu.java @@ -36,6 +36,28 @@ public class EntitySpeedTickerMenu extends UpgradeableMenu partItem) { @@ -81,18 +75,42 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTicka .setIdlePowerUsage(1) .addService(IGridTickable.class, this); } + // 当前打开的菜单实例(如果有) + public EntitySpeedTickerMenu menu; + // 控制是否启用加速(默认启用) + private boolean accelerateEnabled = true; + // 标记网络中能量是否充足(用于 GUI 提示,默认充足) + private boolean networkEnergySufficient = true; public boolean getAccelerateEnabled() { return this.accelerateEnabled; } + public boolean isNetworkEnergySufficient() { + return this.networkEnergySufficient; + } + public void setAccelerateEnabled(boolean accelerateEnabled) { this.accelerateEnabled = accelerateEnabled; } + /** + * 更新网络能量充足标记并在菜单存在且状态变化时触发同步 + * @param sufficient 是否能量充足 + */ + private void updateNetworkEnergySufficient(boolean sufficient) { + // 保持部件内部状态一致(部件为权威来源) + this.networkEnergySufficient = sufficient; + if (this.menu != null) { + try { + // 使用菜单的封装方法更新并广播,以保持封装性 + this.menu.setNetworkEnergySufficient(sufficient); + } catch (Exception ignored) {} + } + } + /** * 获取当前状态下的静态模型(用于渲染) - * * @return 当前状态的模型 */ public IPartModel getStaticModels() { @@ -105,8 +123,6 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTicka } } - - /** * 当玩家激活部件(右键)时调用,打开自定义菜单 * @@ -239,14 +255,21 @@ public class EntitySpeedTickerPart extends UpgradeablePart implements IGridTicka requiredPower *= multiplier; - // 先模拟提取以检查网络中是否有足够能量,再真正抽取 +// 先模拟提取以检查网络中是否有足够能量,再真正抽取 double simulated = getMainNode().getGrid().getEnergyService() .extractAEPower(requiredPower, Actionable.SIMULATE, PowerMultiplier.CONFIG); - if (simulated < requiredPower) return; + if (simulated < requiredPower) { + updateNetworkEnergySufficient(false); // 能量不足 + return; + } double extractedPower = getMainNode().getGrid().getEnergyService() .extractAEPower(requiredPower, Actionable.MODULATE, PowerMultiplier.CONFIG); - if (extractedPower < requiredPower) return; + if (extractedPower < requiredPower) { + updateNetworkEnergySufficient(false); // 能量不足 + return; + } + updateNetworkEnergySufficient(true); // 能量充足 // 计算加速倍数:基于 2 的次方,并把 8 张映射到最大 1024x(2^10) // 已由 product 计算得到 speed;上面已在没有卡时提前返回 diff --git a/src/main/java/com/extendedae_plus/ae/screen/EntitySpeedTickerScreen.java b/src/main/java/com/extendedae_plus/ae/screen/EntitySpeedTickerScreen.java index 32421e2..30605bb 100644 --- a/src/main/java/com/extendedae_plus/ae/screen/EntitySpeedTickerScreen.java +++ b/src/main/java/com/extendedae_plus/ae/screen/EntitySpeedTickerScreen.java @@ -128,6 +128,13 @@ public class EntitySpeedTickerScreen extends Up double finalPower = PowerUtils.computeFinalPowerForProduct(effectiveSpeed, energyCardCount); double remainingRatio = PowerUtils.getRemainingRatio(energyCardCount); + // 如果网络能量不足,优先显示警告信息并在能量值处显示 0 + if (!getMenu().networkEnergySufficient) { + setTextContent("enable", Component.translatable("screen.extendedae_plus.entity_speed_ticker.warning_network_energy_insufficient")); + }else { + setTextContent("enable", null); + } + setTextContent("speed", Component.translatable("screen.extendedae_plus.entity_speed_ticker.speed", effectiveSpeed)); setTextContent("energy", Component.translatable("screen.extendedae_plus.entity_speed_ticker.energy", Platform.formatPower(finalPower, false))); setTextContent("power_ratio", Component.translatable("screen.extendedae_plus.entity_speed_ticker.power_ratio", PowerUtils.formatPercentage(remainingRatio))); diff --git a/src/main/resources/assets/ae2/screens/entity_speed_ticker.json b/src/main/resources/assets/ae2/screens/entity_speed_ticker.json index aaeab6c..352842a 100644 --- a/src/main/resources/assets/ae2/screens/entity_speed_ticker.json +++ b/src/main/resources/assets/ae2/screens/entity_speed_ticker.json @@ -51,8 +51,7 @@ "left": 88 }, "align": "CENTER" - } - , + }, "multiplier": { "position": { "top": 80, diff --git a/src/main/resources/assets/extendedae_plus/lang/en_us.json b/src/main/resources/assets/extendedae_plus/lang/en_us.json index 8775525..c8d3754 100644 --- a/src/main/resources/assets/extendedae_plus/lang/en_us.json +++ b/src/main/resources/assets/extendedae_plus/lang/en_us.json @@ -53,6 +53,7 @@ "screen.extendedae_plus.entity_speed_ticker.power_ratio": "Power Ratio: %s", "screen.extendedae_plus.entity_speed_ticker.speed": "Current Acceleration Multiplier: %d", "screen.extendedae_plus.entity_speed_ticker.multiplier": "Additional Consumption Multiplier: %s", + "screen.extendedae_plus.entity_speed_ticker.warning_network_energy_insufficient": "§c§lInsufficient network energy", "item.extendedae_plus.entity_speed_ticker.tip.requirement": "Requires Entity Speed Card to Enable Acceleration", "item.extendedae_plus.entity_speed_ticker.tip.max": "Up to 1024x Acceleration", diff --git a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json index fe2d4a8..3df2054 100644 --- a/src/main/resources/assets/extendedae_plus/lang/zh_cn.json +++ b/src/main/resources/assets/extendedae_plus/lang/zh_cn.json @@ -53,6 +53,7 @@ "screen.extendedae_plus.entity_speed_ticker.power_ratio": "功耗比例: %s", "screen.extendedae_plus.entity_speed_ticker.speed": "当前加速倍率: %d", "screen.extendedae_plus.entity_speed_ticker.multiplier": "额外消耗倍率: %s", + "screen.extendedae_plus.entity_speed_ticker.warning_network_energy_insufficient": "§c§l网络能量不足", "item.extendedae_plus.entity_speed_ticker.tip.requirement": "需要放入实体加速卡以启用加速", "item.extendedae_plus.entity_speed_ticker.tip.max": "最高可达 1024x 加速",