From 9107f63d9dd6cc3f4b9ea96728108eee93dd7a1e Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 7 Mar 2025 17:26:35 +0700 Subject: [PATCH 01/22] "Accept wireless charging" button in exopack --- .../mc/otm/datagen/lang/English.kt | 3 +++ .../mc/otm/datagen/lang/Russian.kt | 3 +++ .../entity/tech/AndroidChargerBlockEntity.kt | 2 +- .../mc/otm/capability/MatteryPlayer.kt | 2 ++ .../mc/otm/client/render/Widgets18.kt | 2 ++ .../mc/otm/client/screen/MatteryScreen.kt | 15 ++++++++++++++- .../mc/otm/menu/ExopackInventoryMenu.kt | 9 ++++++++- .../ru/dbotthepony/mc/otm/menu/MatteryMenu.kt | 4 +++- .../textures/gui/widgets/widget_18.png | Bin 1098 -> 1292 bytes .../textures/gui/widgets/widget_18.xcf | Bin 7343 -> 9864 bytes 10 files changed, 36 insertions(+), 4 deletions(-) diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt index b7797fb52..f217db8fe 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt @@ -982,6 +982,9 @@ private fun androidFeatures(provider: MatteryLanguageProvider) { private fun gui(provider: MatteryLanguageProvider) { with(provider.english) { + gui("exopack.accept_wireless_charge", "Accept wireless charging") + gui("exopack.dont_accept_wireless_charge", "Do not accept wireless charging") + gui("multiblock.formed", "Multiblock is formed: %s") gui("flywheel.current_loss_t", "Current energy loss per tick:") diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt index 0efb16145..a5e49ff4c 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt @@ -975,6 +975,9 @@ private fun androidFeatures(provider: MatteryLanguageProvider) { private fun gui(provider: MatteryLanguageProvider) { with(provider.russian) { + gui("exopack.accept_wireless_charge", "Принимать заряд от беспроводных зарядников") + gui("exopack.dont_accept_wireless_charge", "Не принимать заряд от беспроводных зарядников") + gui("multiblock.formed", "Мультиблок сформирован: %s") gui("flywheel.current_loss_t", "Текущая потеря энергии в тик:") diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AndroidChargerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AndroidChargerBlockEntity.kt index 3c687d365..8d2df30aa 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AndroidChargerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AndroidChargerBlockEntity.kt @@ -56,7 +56,7 @@ class AndroidChargerBlockEntity(blockPos: BlockPos, blockState: BlockState) : Ma if (!available.isPositive) return } - if (ply.hasExopack) { + if (ply.hasExopack && ply.acceptExopackChargeFromWirelessCharger) { val received = ply.exopackEnergy.receiveEnergyChecked(available, false) available -= received energyConfig.energy.extractEnergy(received, false) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayer.kt index d3c8ae76f..717b6d975 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/MatteryPlayer.kt @@ -565,6 +565,7 @@ class MatteryPlayer(val ply: Player) { val exopackEnergy = ProfiledEnergyStorage(BatteryBackedEnergyStorage(ply, syncher, Decimal.ZERO, ExopackConfig.ENERGY_CAPACITY, false, onChange = { for (v in smelters) v.notify(MachineJobEventLoop.IdleReason.POWER) })) val exopackChargeSlots = MatteryContainer(4) + var acceptExopackChargeFromWirelessCharger = true init { savetables.int(::ticksIExist) @@ -578,6 +579,7 @@ class MatteryPlayer(val ply: Player) { savetables.bool(::isExopackVisible, "displayExoSuit") savetables.bool(::isExopackCraftingUpgraded, "isExoSuitCraftingUpgraded") savetables.bool(::isExopackEnderAccessInstalled, "isExopackEnderAccessUpgraded") + savetables.bool(::acceptExopackChargeFromWirelessCharger) savetables.int(::nextDischargeHurt) savetables.int(::nextHealTick) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/Widgets18.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/Widgets18.kt index 2d52e5824..5949f6962 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/Widgets18.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/Widgets18.kt @@ -43,6 +43,8 @@ object Widgets18 { val CURIOS_INVENTORY = miscGrid.next() val STATISTICS_TAB = miscGrid.next() val SETTINGS_TAB = miscGrid.next() + val WIRELESS_CHARGING_ENABLED = miscGrid.next() + val WIRELESS_CHARGING_DISABLED = miscGrid.next() private val slotBgGrid = WidgetLocation.SLOT_BACKGROUNDS.grid(4, 4) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/MatteryScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/MatteryScreen.kt index 2eeccb3e4..dac9e5539 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/MatteryScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/MatteryScreen.kt @@ -24,6 +24,7 @@ import ru.dbotthepony.mc.otm.client.render.WidgetLocation import ru.dbotthepony.mc.otm.client.render.Widgets18 import ru.dbotthepony.mc.otm.client.render.translation import ru.dbotthepony.mc.otm.client.screen.panels.* +import ru.dbotthepony.mc.otm.client.screen.panels.button.BooleanButtonPanel import ru.dbotthepony.mc.otm.client.screen.panels.button.DeviceControls import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel import ru.dbotthepony.mc.otm.client.screen.panels.slot.BatterySlotPanel @@ -172,13 +173,25 @@ abstract class MatteryScreen(menu: T, inventory: Inventory, tit } protected fun makeChargePanels(frame: EditablePanel<*>) { - val chargeWidth = HorizontalPowerGaugePanel.GAUGE_BACKGROUND_TALL.width + AbstractSlotPanel.SIZE + 6f + ProgressGaugePanel.GAUGE_BACKGROUND.width * 2f + val chargeWidth = HorizontalPowerGaugePanel.GAUGE_BACKGROUND_TALL.width + AbstractSlotPanel.SIZE * 2 + 8f + ProgressGaugePanel.GAUGE_BACKGROUND.width * 2f val chargeStrip = BackgroundPanel.paddedCenter(this, frame, frame.width - chargeWidth - 6f, frame.height + 2f, chargeWidth, AbstractSlotPanel.SIZE) val chargeStrip2 = BackgroundPanel.paddedCenter(this, frame, frame.width + 2f, frame.height - AbstractSlotPanel.SIZE * 3f + 2f, AbstractSlotPanel.SIZE, AbstractSlotPanel.SIZE * 4f) chargeStrip.customDock { chargeStrip.setPos(frame.width - chargeWidth - 6f, frame.height + 2f) } chargeStrip2.customDock { chargeStrip2.setPos(frame.width + 2f, frame.height - AbstractSlotPanel.SIZE * 3f + 2f) } + BooleanButtonPanel.square18( + this, chargeStrip, + prop = menu.acceptExopackChargeFromWirelessCharger, + iconActive = Widgets18.WIRELESS_CHARGING_ENABLED, + iconInactive = Widgets18.WIRELESS_CHARGING_DISABLED, + tooltipActive = TranslatableComponent("otm.gui.exopack.accept_wireless_charge"), + tooltipInactive = TranslatableComponent("otm.gui.exopack.dont_accept_wireless_charge"), + ).also { + it.dock = Dock.LEFT + it.dockRight = 2f + } + BatterySlotPanel(this, chargeStrip, menu.exopackChargeSlots[0]).also { it.dock = Dock.LEFT } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/ExopackInventoryMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/ExopackInventoryMenu.kt index 6d27c6177..0d8e58e48 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/ExopackInventoryMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/ExopackInventoryMenu.kt @@ -7,7 +7,14 @@ import net.minecraft.server.level.ServerPlayer import net.minecraft.world.Container import net.minecraft.world.entity.ExperienceOrb import net.minecraft.world.entity.player.Player -import net.minecraft.world.inventory.* +import net.minecraft.world.inventory.AbstractContainerMenu +import net.minecraft.world.inventory.ContainerSynchronizer +import net.minecraft.world.inventory.CraftingContainer +import net.minecraft.world.inventory.CraftingMenu +import net.minecraft.world.inventory.ResultContainer +import net.minecraft.world.inventory.ResultSlot +import net.minecraft.world.inventory.Slot +import net.minecraft.world.inventory.TransientCraftingContainer import net.minecraft.world.item.ItemStack import net.neoforged.neoforge.network.PacketDistributor import ru.dbotthepony.mc.otm.capability.MatteryPlayer diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt index 674e64ea6..4a65058ae 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/MatteryMenu.kt @@ -44,6 +44,7 @@ import ru.dbotthepony.mc.otm.container.sortWithIndices import ru.dbotthepony.mc.otm.core.ResourceLocation import ru.dbotthepony.mc.otm.core.collect.ConditionalSet import ru.dbotthepony.mc.otm.core.math.Decimal +import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget import ru.dbotthepony.mc.otm.network.MatteryStreamCodec import ru.dbotthepony.mc.otm.network.MenuDataPacket @@ -207,7 +208,8 @@ abstract class MatteryMenu( var sortInventoryInput: SortInput? = null private set - val playerSortSettings = IItemStackSortingSettings.inputs(this, player.matteryPlayer?.sortingSettings) + val playerSortSettings = IItemStackSortingSettings.inputs(this, player.matteryPlayer.sortingSettings) + val acceptExopackChargeFromWirelessCharger = BooleanInputWithFeedback(this, true, player.matteryPlayer::acceptExopackChargeFromWirelessCharger) var offhandSlot: InventorySlot? = null protected set diff --git a/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/widget_18.png b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/widget_18.png index 4ecb9767763641c75945cefd7d7059fb44900c6a..984eb0090e4df0f04d252134f3d0924fb5fc0f9c 100644 GIT binary patch delta 1229 zcmV;;1Ty=|2#gAlB!7cxLqkwWLqi~Na&Km7Y-IodD3N`UJxIeq9K~N#r79H%JBT=B zXr1h$B95gMi(sL&6nNgNw7S4z7YA_yOWBI4QbFiT_Iq zEn+-4?#H`(kGpq((5f-j?27@aW*M1eT+A0%#lS242w)IFM1Le^>Z$Bv4xZ!d9zMR_ zMR}I@xj)CSQZyOh6NzI?H!R`};<-&r=e$oGViidtJ|~_s=z_$LT$f#b<6L%F;F%#K zmq`$Zh{bXb%RS60hDtn399C3~@`b$13g<1(YOTRK_v9}O7PXZu*J(~5i6x|vh6ouA zR8fP4D6JYPCVw)tANTN&JN`7eWO7x($gzMrR7j2={11M2YnEoF-K1a~=zp>8j|dRh z1=>y9{yw(t_6gvB2ClTOzup4oKS^(PweS%zvJG5ZcQttrxZDB8o^;8O9LY~pD3yTs zGy0|iFnS9Nt+~B*_Hp_E7xV5I#qF2`09VY=|d74D@m7fLPiQvGE2> zJjQh>L5{I~XZu18zE7%DC+^k$^7;M}0{{pDKol_}hV^x0H6a!6iSd1qy#BJN{|wy1SvsEkU|Mkf|Q`=qYqW(xp1rUT)0(vE{3W+7Y4Lp zrlAY-AF z9M{gPkVHD-TqhZuFX3<{?ZljPQGXOGS$GX3x#}asyhI+9vfx^kG+7i&UFa+Nq$=7S z&;I`kg`z1S@Lm*z=A~Yb29wb5>{6o=LM7&uWzxRf#+OJjS{!(@V{Y?CuY`;-5BCK( z&h9U{sX?rR;Uy?mWD=ni?I}Jp7KtfGlKRO`E|XIOn+O|BV=e)A!rXD9&ws+idr4&m zJBN~1kY@wA3Mz8?J_15}w6FIs?woz|4W$&j{o?u~*Z0&+kX$4p+AT51+*hO&6NpG$ zC7DtJeZ_X~n>@%a6y}+gIw0abj1Q*laccX(zWp17ypH1MXEP#U6Eq}=Bh~D7?_cP0j@iAKv&b=DUq%&V6V;e--;kAS~9hypiZMz0zob2 rIedZ|k5+siwA%qr__c&W(H4FItj!@O+d8RZ00000NkvXXu0mjf)QLNm delta 1033 zcmV+k1or!k3d#tOB!7izLqkwWLqi~Na&Km7Y-IodD3N`UJxIeq9K~N-rG8W$>>%Qh zp?0zkD&knGSOg2Dt*F8LZ zy^HWH_j7-a0Xc6lz#|YxnWme>8^p7lrp9@nILJz(Ongo}q0I7loMJ6P&qR?-#X8RC$vsFd%`IxKVE;;d9^taVTR!a!bKNpqd%7~)t$0!avv zP(v9Nn26A-l7C_#Mf))q|ETRxl1n028H^kYs6v5g`@#R%la4x z{JTK2Zdu>Qmeo7~e9yp@+V)o)z}zS4^|lr|0*1DMi|e)~?E#lNz{ry(>Y^?AXnG3; z;QfrgDF+PS0)1;vZ>@ctJ^&f&YWW5@I0V8)%3gPQcM(r#Z~vZY_4fnhY;x2!K@2*R zumLcC=nD!4IV=``f6)K{0!B$hK~#9!?V3%F!Y~Yl?TSmV;s)#xCqSGTaRS7yH(LPQ6LZmfP~8w#iWj|F(xhIx}*2^0|0&s zLwP?GgvLofZ&yh#NKlP2b(OTQw(%8G8CM+UWrttmWXJCjnxI%tR_R z_7I;LOGL>lnfmKn&)9W^U0-C>8Lj|t!Q8emW*K4MI(Cp}0;M~sHs}|zS$S}5_Kk0Q z76Z%ML7|mr;ZEvzCEPhk=f;?y4bl>Ux~KWzKQE*T#Z0l^h2Zp<+g1$Jrp0T<9b$^K z?GuL+G0U`?(;BiEe`%os000000000000000fUf)jLz8#uM`5kc00000NkvXXu0mjf DPl()M diff --git a/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/widget_18.xcf b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/widget_18.xcf index ceec2f67e7ca9d94341498a229bea1b0fd481172..f9b632cf4e2692ec0fb220f9b0dec6b29aea08fc 100644 GIT binary patch literal 9864 zcmeHN-EUMy6rZ~v-H-0FbdiQiZEo$7w3-GsM2Jr&W*XTDP4~|qO%6@SdN~dlsnZoe#iOMm* zGBNVf=oFur92=V&J?5+S4z0=C8*|Q1^5%6R_KC*H9*sL+*Es)~##>+2cw1HD?Nb^* z@uJ5535^F{)A+WW+8|I?+rkgRYvJ|qa_zkDkURMRb;8sEpdKWkpY(In$e}9$`RpfU zXdv;VL-#s#+M#`i?sVvkLuVa22b$wC?ExeJ9Gm^`Ff@=Tkd{cm0}k!3C9rLZ{Aej) zD;M^Q6!}AAmD@TLqWrxo<%K6Z0iKA+6d(df0AheRpaT#EBmr!b7IB#oQJDo~K&K6# z^=!xXe2&kvANI$7Ju^-oQ&b}cX2igZ7?=?QGh$#y3^+n0$Owr%D4fM2+XL$_i5fhF1@8gkXdz)B5;ULmU<8`xk|vMPxhjs!VX-lfx_s_N z9x1JpEQCsdCjb#8;CrPIEDzW21|L#m<37Xvq}9FVX>BGpPd#fXU@IT9*QEA0sRJuD zZu#r9$iFeh_bc(;EUx=x^xv9!{I<^XfSs(PvBi}Vv?8!D_5rw%xVbgF$Stb3x;EXx zFx{4oiZ7Q=%A9iwRvyNvGM98+{=+71z{>oj`CaCvng^BvnJP(<+q*1euH?y_SeB(^ zby@7q9$4BdWGOqlRKot1eP#)TYGQVy=3dL-PU&l{Z0KhF*V=||+Sd=Prkm5TX_+W> zRAnhXyIfs+)=^EC+P%Ni;sQ<`>gA1r2`2l(#l14?90XOQqn(a;eBi*O6<2V9ziCc(ZkgE~5&RZfB@reeW`HmuQgWwwltr~>Q48vVEme7BPyw-asEkH_tT)41mqr)>K+i?-+8CUs!-d~W$0e*8X0 z;~(J80exEC(*U-+et)6%MtIdn+aChXlpWMl?^|_xMI^=?dOvMa z2UhQb<)8LS(!wB|bPWDCZm_)+4v_EpZTA5ULe(k1XPQO(h+Y3IUroNXAL1ZOjbllfW z|7g~?66*;dZ*IcePZMgtj;cJV_h#(DNr&sUSdCuo$@(~f*cg>^Rc}A{Ny5%rpbOj* zUWCJ&shv?bc~|h(dl}rea(y(3wU`B$zLWZAoI-l=Pbhc_f~NRJRTSo5eA+b)IYI@Ol|b~Dj^Yl-udhZUDdGsuPS(+I+AFavzc!RmI} z8MsW>Vgmeh#7TuWokD{N6h3ZJ2UbD(1=eXFtv{>KzMiM7B(J7{0lbc;eXIseo7PRl g?g9_@2z5uHm#kg7*1+iq{wr;rN24=YOL>R*7w>i~hX4Qo delta 367 zcmeD1U2i!dgHdZ@=4+3+3}C=<5khk>g3x?3A++Eu2rXO>p~ax;C6_?>aB^}jx6b4T zj58)%@_4&3ZH0?7Fn9pjLO{#{5o5Xup*fC1XfO#=1LQFMgov|W+r zHS=ErYEELDd|D)LbFnlhBa_ftu(Z%gu(Z&_&6{M_F*1ov1dEES1&MNsz??bxzkK;5 tg)$)8q)^VtB)$TyO8f{|ulSwKYZcEjF-ffki%J~_i%Q+!yg}s#BLJobO& Date: Fri, 7 Mar 2025 17:29:32 +0700 Subject: [PATCH 02/22] Delay cable blockstate update by 4 ticks --- .../mc/otm/block/entity/cable/EnergyCableBlockEntity.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/cable/EnergyCableBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/cable/EnergyCableBlockEntity.kt index 1fcbf265f..693ec5090 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/cable/EnergyCableBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/cable/EnergyCableBlockEntity.kt @@ -165,7 +165,7 @@ abstract class EnergyCableBlockEntity(type: BlockEntityType<*>, blockPos: BlockP if (!SERVER_IS_LIVE) return val level = level - level?.once { + level?.once(4) { if (!node.isValid) return@once val newState = blockState From 4861513797971e3220c61b919cfa6b57a579946b Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 7 Mar 2025 17:30:20 +0700 Subject: [PATCH 03/22] Delay redstone signal level lookup update by 4 ticks --- .../mc/otm/block/entity/MatteryDeviceBlockEntity.kt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryDeviceBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryDeviceBlockEntity.kt index 4580fcefe..a0c42c6b0 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryDeviceBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/MatteryDeviceBlockEntity.kt @@ -7,6 +7,7 @@ import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.NbtOps import net.minecraft.network.chat.Component import net.minecraft.network.chat.ComponentSerialization +import net.minecraft.server.level.ServerLevel import net.minecraft.world.MenuProvider import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Player @@ -83,9 +84,11 @@ abstract class MatteryDeviceBlockEntity(blockEntityType: BlockEntityType<*>, blo override fun setLevel(level: Level) { super.setLevel(level) - level.once { - if (!isRemoved && this.level == level) { - redstoneControl.redstoneSignal = level.getBestNeighborSignal(blockPos) + if (level is ServerLevel) { + level.once(4) { + if (!isRemoved && this.level == level) { + redstoneControl.redstoneSignal = level.getBestNeighborSignal(blockPos) + } } } } From f866f2a401623b373335d22d705bfdfcf6d5da59 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Fri, 7 Mar 2025 21:00:01 +0700 Subject: [PATCH 04/22] Add "Charge androids" and "Charge exopacks" buttons --- .../mc/otm/datagen/lang/English.kt | 6 ++++ .../mc/otm/datagen/lang/Russian.kt | 6 ++++ .../entity/tech/AndroidChargerBlockEntity.kt | 20 +++++++++-- .../entity/tech/AndroidStationBlockEntity.kt | 29 +++++++++++----- .../mc/otm/client/render/Widgets18.kt | 2 ++ .../screen/tech/AndroidChargerScreen.kt | 31 +++++++++++++++++- .../screen/tech/AndroidStationScreen.kt | 14 +++++++- .../kotlin/ru/dbotthepony/mc/otm/core/Ext.kt | 9 +++-- .../mc/otm/menu/tech/AndroidChargerMenu.kt | 10 ++++++ .../mc/otm/menu/tech/AndroidStationMenu.kt | 6 ++-- .../textures/gui/widgets/widget_18.png | Bin 1292 -> 1412 bytes .../textures/gui/widgets/widget_18.xcf | Bin 9864 -> 12474 bytes 12 files changed, 114 insertions(+), 19 deletions(-) diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt index f217db8fe..673379cff 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt @@ -985,6 +985,12 @@ private fun gui(provider: MatteryLanguageProvider) { gui("exopack.accept_wireless_charge", "Accept wireless charging") gui("exopack.dont_accept_wireless_charge", "Do not accept wireless charging") + gui("charge_androids", "Charge Androids") + gui("dont_charge_androids", "Do not charge Androids") + + gui("charge_exopacks", "Charge Exopacks") + gui("dont_charge_exopacks", "Do not charge Exopacks") + gui("multiblock.formed", "Multiblock is formed: %s") gui("flywheel.current_loss_t", "Current energy loss per tick:") diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt index a5e49ff4c..ae0d7b49b 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt @@ -978,6 +978,12 @@ private fun gui(provider: MatteryLanguageProvider) { gui("exopack.accept_wireless_charge", "Принимать заряд от беспроводных зарядников") gui("exopack.dont_accept_wireless_charge", "Не принимать заряд от беспроводных зарядников") + gui("charge_androids", "Заряжать андроидов") + gui("dont_charge_androids", "Не заряжать андроидов") + + gui("charge_exopacks", "Заряжать экзопаки") + gui("dont_charge_exopacks", "Не заряжать экзопаки") + gui("multiblock.formed", "Мультиблок сформирован: %s") gui("flywheel.current_loss_t", "Текущая потеря энергии в тик:") diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AndroidChargerBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AndroidChargerBlockEntity.kt index 8d2df30aa..17d1f79da 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AndroidChargerBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AndroidChargerBlockEntity.kt @@ -30,14 +30,28 @@ class AndroidChargerBlockEntity(blockPos: BlockPos, blockState: BlockState) : Ma override val energy = ProfiledEnergyStorage(WorkerEnergyStorage(this::markDirtyFast, MachinesConfig.ANDROID_CHARGER)) val energyConfig = ConfigurableEnergy(energy, modesTop = FlowDirection.NONE) + var chargeAndroids = true + set(value) { + field = value + markDirtyFast() + } + + var chargeExopacks = true + set(value) { + field = value + markDirtyFast() + } + init { savetables.stateful(energyConfig::energy, ENERGY_KEY) + savetablesConfig.bool(::chargeAndroids) + savetablesConfig.bool(::chargeExopacks) } override fun tick() { super.tick() - if (redstoneControl.isBlockedByRedstone) return + if (redstoneControl.isBlockedByRedstone || !chargeAndroids && !chargeExopacks) return val level = level ?: return var available = energyConfig.energy.extractEnergy(energyConfig.energy.batteryLevel, true) if (!available.isPositive) return @@ -49,14 +63,14 @@ class AndroidChargerBlockEntity(blockPos: BlockPos, blockState: BlockState) : Ma for ((ent) in ents) { val ply = (ent as Player).matteryPlayer - if (ply.isAndroid) { + if (chargeAndroids && ply.isAndroid) { val received = ply.androidEnergy.receiveEnergyChecked(available, false) available -= received energyConfig.energy.extractEnergy(received, false) if (!available.isPositive) return } - if (ply.hasExopack && ply.acceptExopackChargeFromWirelessCharger) { + if (chargeExopacks && ply.hasExopack && ply.acceptExopackChargeFromWirelessCharger) { val received = ply.exopackEnergy.receiveEnergyChecked(available, false) available -= received energyConfig.energy.extractEnergy(received, false) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AndroidStationBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AndroidStationBlockEntity.kt index 42b2e62a0..3ef4f37e5 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AndroidStationBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/AndroidStationBlockEntity.kt @@ -17,21 +17,26 @@ import ru.dbotthepony.mc.otm.capability.matteryPlayer import ru.dbotthepony.mc.otm.capability.moveEnergy import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.core.math.Decimal +import ru.dbotthepony.mc.otm.core.otmRandom +import ru.dbotthepony.mc.otm.core.shuffle +import ru.dbotthepony.mc.otm.core.util.countingLazy import ru.dbotthepony.mc.otm.menu.tech.AndroidStationMenu import ru.dbotthepony.mc.otm.registry.game.MBlockEntities -class AndroidStationBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : - MatteryPoweredBlockEntity(MBlockEntities.ANDROID_STATION, p_155229_, p_155230_), MenuProvider { - +class AndroidStationBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : MatteryPoweredBlockEntity(MBlockEntities.ANDROID_STATION, p_155229_, p_155230_), MenuProvider { override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { return AndroidStationMenu(containerID, inventory, this) } + private val workerState by countingLazy(blockStateChangesCounter) { + blockState.getValue(WorkerState.SEMI_WORKER_STATE) + } + override val energy: ProfiledEnergyStorage = ProfiledEnergyStorage(object : WorkerEnergyStorage(::markDirtyFast, MachinesConfig.AndroidStation.VALUES) { override fun extractEnergy(howMuch: Decimal, simulate: Boolean): Decimal { return super.extractEnergy(howMuch, simulate).also { if (!simulate && this.batteryLevel.isZero) { - if (blockState.getValue(WorkerState.SEMI_WORKER_STATE) != WorkerState.IDLE) { + if (workerState != WorkerState.IDLE) { level?.setBlock(blockPos, blockState.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.IDLE), Block.UPDATE_CLIENTS) } } @@ -41,7 +46,7 @@ class AndroidStationBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : override fun receiveEnergy(howMuch: Decimal, simulate: Boolean): Decimal { return super.receiveEnergy(howMuch, simulate).also { if (!simulate && it.isPositive) { - if (blockState.getValue(WorkerState.SEMI_WORKER_STATE) != WorkerState.WORKING) { + if (workerState != WorkerState.WORKING) { level?.setBlock(blockPos, blockState.setValue( WorkerState.SEMI_WORKER_STATE, WorkerState.WORKING @@ -53,9 +58,15 @@ class AndroidStationBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : }) val energyConfig = ConfigurableEnergy(energy) + var chargeAndroids = true + set(value) { + field = value + markDirtyFast() + } init { savetables.stateful(::energy, ENERGY_KEY) + savetablesConfig.bool(::chargeAndroids) } private var tickedOnce = false @@ -66,20 +77,20 @@ class AndroidStationBlockEntity(p_155229_: BlockPos, p_155230_: BlockState) : if (!tickedOnce) { tickedOnce = true - if (energy.batteryLevel.isPositive && blockState.getValue(WorkerState.SEMI_WORKER_STATE) != WorkerState.WORKING) { + if (energy.batteryLevel.isPositive && workerState != WorkerState.WORKING) { level?.setBlock(blockPos, blockState.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.WORKING), Block.UPDATE_CLIENTS) - } else if (energy.batteryLevel.isZero && blockState.getValue(WorkerState.SEMI_WORKER_STATE) != WorkerState.IDLE) { + } else if (!energy.batteryLevel.isPositive && workerState != WorkerState.IDLE) { level?.setBlock(blockPos, blockState.setValue(WorkerState.SEMI_WORKER_STATE, WorkerState.IDLE), Block.UPDATE_CLIENTS) } } - if (redstoneControl.isBlockedByRedstone) return + if (redstoneControl.isBlockedByRedstone || !chargeAndroids) return val level = level ?: return val x = blockPos.x.toDouble() val y = blockPos.y.toDouble() val z = blockPos.z.toDouble() - for (ent in level.getEntitiesOfClass(ServerPlayer::class.java, AABB(x, y, z, x + 1.0, y + 2.0, z + 1.0))) { + for (ent in level.getEntitiesOfClass(ServerPlayer::class.java, AABB(x, y, z, x + 1.0, y + 2.0, z + 1.0)).shuffle(level.otmRandom)) { if (ent.matteryPlayer.isAndroid) moveEnergy(energy, ent.matteryPlayer.androidEnergy, amount = energy.batteryLevel, simulate = false, ignoreFlowRestrictions = true) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/Widgets18.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/Widgets18.kt index 5949f6962..06bab6193 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/Widgets18.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/render/Widgets18.kt @@ -45,6 +45,8 @@ object Widgets18 { val SETTINGS_TAB = miscGrid.next() val WIRELESS_CHARGING_ENABLED = miscGrid.next() val WIRELESS_CHARGING_DISABLED = miscGrid.next() + val WIRELESS_CHARGING_ANDROIDS_ENABLED = miscGrid.next() + val WIRELESS_CHARGING_ANDROIDS_DISABLED = miscGrid.next() private val slotBgGrid = WidgetLocation.SLOT_BACKGROUNDS.grid(4, 4) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/AndroidChargerScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/AndroidChargerScreen.kt index 27b80cb22..a7e6b9fb4 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/AndroidChargerScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/AndroidChargerScreen.kt @@ -2,6 +2,7 @@ package ru.dbotthepony.mc.otm.client.screen.tech import net.minecraft.network.chat.Component import net.minecraft.world.entity.player.Inventory +import ru.dbotthepony.mc.otm.client.render.Widgets18 import ru.dbotthepony.mc.otm.client.screen.MatteryScreen import ru.dbotthepony.mc.otm.client.screen.panels.Dock import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel @@ -10,8 +11,10 @@ import ru.dbotthepony.mc.otm.client.screen.panels.button.makeDeviceControls import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel import ru.dbotthepony.mc.otm.client.screen.panels.slot.BatterySlotPanel import ru.dbotthepony.mc.otm.client.screen.panels.SpritePanel +import ru.dbotthepony.mc.otm.client.screen.panels.button.BooleanButtonPanel import ru.dbotthepony.mc.otm.client.screen.widget.ProgressGaugePanel import ru.dbotthepony.mc.otm.client.screen.widget.TallHorizontalProfiledPowerGaugePanel +import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.menu.tech.AndroidChargerMenu class AndroidChargerScreen(menu: AndroidChargerMenu, inventory: Inventory, title: Component) : MatteryScreen(menu, inventory, title) { @@ -40,7 +43,33 @@ class AndroidChargerScreen(menu: AndroidChargerMenu, inventory: Inventory, title it.dockRight = 2f } - makeDeviceControls(this, frame, redstoneConfig = menu.redstoneConfig, energyConfig = menu.energyConfig) + val controls = makeDeviceControls(this, frame, redstoneConfig = menu.redstoneConfig, energyConfig = menu.energyConfig) + + if (menu.chargeExopacks != null) { + controls.addButton( + BooleanButtonPanel.square18( + this, frame, + prop = menu.chargeExopacks!!, + iconActive = Widgets18.WIRELESS_CHARGING_ENABLED, + iconInactive = Widgets18.WIRELESS_CHARGING_DISABLED, + tooltipActive = TranslatableComponent("otm.gui.charge_exopacks"), + tooltipInactive = TranslatableComponent("otm.gui.dont_charge_exopacks"), + ) + ) + } + + if (menu.chargeAndroids != null) { + controls.addButton( + BooleanButtonPanel.square18( + this, frame, + prop = menu.chargeAndroids!!, + iconActive = Widgets18.WIRELESS_CHARGING_ANDROIDS_ENABLED, + iconInactive = Widgets18.WIRELESS_CHARGING_ANDROIDS_DISABLED, + tooltipActive = TranslatableComponent("otm.gui.charge_androids"), + tooltipInactive = TranslatableComponent("otm.gui.dont_charge_androids"), + ) + ) + } return frame } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/AndroidStationScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/AndroidStationScreen.kt index 16acceee3..08190ec3c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/AndroidStationScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/AndroidStationScreen.kt @@ -34,6 +34,7 @@ import ru.dbotthepony.mc.otm.client.screen.widget.WideProfiledPowerGaugePanel import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.kommons.math.RGBAColor import ru.dbotthepony.mc.otm.capability.matteryPlayer +import ru.dbotthepony.mc.otm.client.screen.panels.button.BooleanButtonPanel import ru.dbotthepony.mc.otm.core.RandomSource2Generator import ru.dbotthepony.mc.otm.menu.tech.AndroidStationMenu import ru.dbotthepony.mc.otm.network.AndroidResearchRequestPacket @@ -717,7 +718,18 @@ class AndroidStationScreen(p_97741_: AndroidStationMenu, p_97742_: Inventory, p_ this.playerStrip = playerStrip - makeDeviceControls(this, frame, redstoneConfig = menu.redstoneConfig, energyConfig = menu.energyConfig) + val controls = makeDeviceControls(this, frame, redstoneConfig = menu.redstoneConfig, energyConfig = menu.energyConfig) + + controls.addButton( + BooleanButtonPanel.square18( + this, frame, + prop = menu.chargeAndroids, + iconActive = Widgets18.WIRELESS_CHARGING_ANDROIDS_ENABLED, + iconInactive = Widgets18.WIRELESS_CHARGING_ANDROIDS_DISABLED, + tooltipActive = TranslatableComponent("otm.gui.charge_androids"), + tooltipInactive = TranslatableComponent("otm.gui.dont_charge_androids"), + ) + ) return frame } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt index 718e617b1..97326b9b1 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt @@ -188,17 +188,20 @@ fun > T.prev(values: Array): T { return values[next] } -fun IntArray.shuffle(random: RandomSource) { +fun IntArray.shuffle(random: RandomSource): IntArray { for (i in lastIndex downTo 1) { val j = random.nextInt(i + 1) val copy = this[i] this[i] = this[j] this[j] = copy } + + return this } -fun MutableList.shuffle(random: RandomSource) { - return Util.shuffle(this, random) +fun > L.shuffle(random: RandomSource): L { + Util.shuffle(this, random) + return this } fun List.random(random: RandomGenerator): T { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/AndroidChargerMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/AndroidChargerMenu.kt index 196526d4d..be2b8c24e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/AndroidChargerMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/AndroidChargerMenu.kt @@ -5,6 +5,7 @@ import ru.dbotthepony.mc.otm.block.entity.tech.AndroidChargerBlockEntity import ru.dbotthepony.mc.otm.block.entity.tech.AndroidChargerMiddleBlockEntity import ru.dbotthepony.mc.otm.block.entity.tech.AndroidChargerTopBlockEntity import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu +import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget import ru.dbotthepony.mc.otm.registry.game.MMenus @@ -13,6 +14,9 @@ class AndroidChargerMenu : MatteryPoweredMenu { val energyConfig: EnergyConfigPlayerInput val profiledEnergy: ProfiledLevelGaugeWidget<*> + val chargeAndroids: BooleanInputWithFeedback? + val chargeExopacks: BooleanInputWithFeedback? + constructor( p_38852_: Int, inventory: Inventory, @@ -20,6 +24,8 @@ class AndroidChargerMenu : MatteryPoweredMenu { ) : super(MMenus.ANDROID_CHARGER, p_38852_, inventory, tile) { energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig) profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energyConfig?.energy, energyWidget) + chargeAndroids = BooleanInputWithFeedback(this, tile?.let { it::chargeAndroids }) + chargeExopacks = BooleanInputWithFeedback(this, tile?.let { it::chargeExopacks }) } constructor( @@ -29,6 +35,8 @@ class AndroidChargerMenu : MatteryPoweredMenu { ) : super(MMenus.ANDROID_CHARGER, p_38852_, inventory, tile?.lastTileEntity) { energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig) profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.lastTileEntity?.energyConfig?.energy, energyWidget) + chargeAndroids = null + chargeExopacks = null } constructor( @@ -38,6 +46,8 @@ class AndroidChargerMenu : MatteryPoweredMenu { ) : super(MMenus.ANDROID_CHARGER, p_38852_, inventory, tile?.lastTileEntity) { energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig) profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.lastTileEntity?.energyConfig?.energy, energyWidget) + chargeAndroids = null + chargeExopacks = null } init { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/AndroidStationMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/AndroidStationMenu.kt index 9b3f0da7e..974fa4823 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/AndroidStationMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/AndroidStationMenu.kt @@ -13,6 +13,7 @@ import ru.dbotthepony.mc.otm.capability.matteryPlayer import ru.dbotthepony.mc.otm.config.MachinesConfig import ru.dbotthepony.mc.otm.menu.MatteryPoweredMenu import ru.dbotthepony.mc.otm.menu.MatterySlot +import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.EnergyConfigPlayerInput import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget import ru.dbotthepony.mc.otm.registry.game.MMenus @@ -25,7 +26,7 @@ class AndroidStationMenu @JvmOverloads constructor( ) : MatteryPoweredMenu(MMenus.ANDROID_STATION, containerID, inventory, tile) { private fun container(target: (MatteryPlayer) -> KMutableProperty0): Container { if (player is ServerPlayer) - return PartContainer(target.invoke(player.matteryPlayer ?: throw NullPointerException("OTM player capability is missing"))) + return PartContainer(target.invoke(player.matteryPlayer)) else return SimpleContainer(1) } @@ -115,6 +116,7 @@ class AndroidStationMenu @JvmOverloads constructor( val equipment = makeEquipmentSlots() val energyConfig = EnergyConfigPlayerInput(this, tile?.energyConfig) val profiledEnergy = ProfiledLevelGaugeWidget(this, tile?.energy, energyWidget) + val chargeAndroids = BooleanInputWithFeedback(this, tile?.let { it::chargeAndroids }) init { addInventorySlots() @@ -122,6 +124,6 @@ class AndroidStationMenu @JvmOverloads constructor( } override fun stillValid(player: Player): Boolean { - return super.stillValid(player) && player.matteryPlayer?.isAndroid == true + return super.stillValid(player) && player.matteryPlayer.isAndroid } } diff --git a/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/widget_18.png b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/widget_18.png index 984eb0090e4df0f04d252134f3d0924fb5fc0f9c..f311ac0c68739fb05aed8308bc39f3da1659b8b2 100644 GIT binary patch delta 944 zcmV;h15f;n3WN)=;{ksRISRm|KSKZj1A<9JK~#9!?OHpIA~6sxqdvqEkxfX3H~}JH zj>`myWH&@)+<=H<)CNnB+{T~!bx)(MCyg{so1*+&uAdzM0Kou=CSuI6+wDx`bN~R` z?N%k^a=Dl&bv~Z~03d{5vRLc&S|#UpyZs{w0ARIRiG-EEt8yvQ zs$7b`DwiUFH_RNf0Y0Jqo>b1LJ}6cAWiMv>p#8Y?9U@{N_DyR)X9~|8Ji@otOZ2~S7>W;Epo;pNwQ@FhvA&BsZBCR1eF{Kp<2ty zS~5kE*5@^)ONwzPYDH2@*Yy2@vf3I`Z~2$80zgSdYlo!o7gXhcI^0^4WE$qRNn6WF z{{%^91ceA%a#A_(LQ>NaOPyqGyoJNHlv8ukswk#Wd=7skrPkLB^A>p!N8!0z(r8hP ztLQuWq*=5(rv810!|`7Mfp$<(8pr*-8ca(6lS_@65Na_-mr3Vxn_MDAXmQ|EPI!(R z90`RGUfvr{oZMeZQ-fLuBTG=N$ZUjCjECgJL?m*yWb03yT(VPxn1~oeVJQLMgr(0+ zpM}hKtTKOtoI_b#P-X&B3sO1#908>{#-Dd@?woVuL(5X)_DkxIQr|OYg6twuquo+- z%-xJEB@`kO)sljiz+AE2YK-7?xzAwv zxz)+8!{KnuuNbOy-tcfhJRHnBcvI-ZfvltW`8ltZ98n)KL4A@qSf%4pl+LGJOUYT5 zl|Je`XwZ&~lnGy7>~rwAD73gGrqRdTf-F}`V>x5!!?K|4g@nvXQSK+!R=@Up9C9@J zun2!Du4d!_sb<`|8>G42I>ojs7OO9lNtEHNQmOJM9vx-JYxFUz=4)omx$E5O1#{)R z_?!?_cdtcT%+ic=hjEfgAR-R(oX8gpu{0!KW9ZxbYlRvd7D zRz*gR$D_!i4u=B(02pIL9@b*9D6(@tpZ^E~0GQ9`Sw=3G%V>YR*=(}x?DzZ8c)46= z**Tp~qw#Du%d&I5UI75014R@{kP@T>DM3n*5~KtvK}wK92~vWTpy#6xRpq&GtMXj9 zRe3Iksyr74v|*;G26#j1-{snw)Cai>emIMsKIkydy@!Zsn0?b25h-?FB8u6Y;V8hK zWB+Zcou?DzKDB?8r^wx0h@7cOO10H-jHDW+Hb;>&6-hZq)}%1(^EI(e`iS6?lS62! za=c3BEQGoqTXbk)sT-9diCU|BzvDdZ5~)-EWvT!WvO%2?_kPD+{C|gANs>gvd}-1~ zIqCl(NsJ(4p_Clg&a03_I^tX>8JjQRa3$@;oODqXD_MVd4J5hhBg4Ez9+a}+T9q_e z6iZ#`EBd4=+8xjS{|beoDIoA(6olrbUXKQo(C_S0qY^?T=9Fd9zTC!_NHJO*c(Y?} z^G2_Pj4==Q1vk#_FS)5ftb^etC{|<=p%m>YJ~I}HDMym}$xbelQv;g_8%$#^0e8aO zaiY({#Cv~9Wd=Kkl2(vs1Gx$+a{4|3LVL8Y_b=|8ee(^a6ubT6`Xkr()J%|EBqG`^ zF~{6jq!bf~NL(eEQUZO&cJG@!$SxG-nUy*q;ysKHrtEQQ`^G~8PN}q7oHW-7XNCFF zo_HTiq+*F8Gn7UZBe zb*VSI3WY*ZUojNvyy13>xZS?}8-%=$;^${GB4HCWB#9%{>~`;8=yHzPy_mDeF<)Os z6=W0Dm~w&&@_vxuQ4Z((#J3_SScF;*xs_uTELI;nZ;o^#i0Z#a}ghJ64egUk_At&29sbc^D002ovPDHLkV1gnR Be{TQ) diff --git a/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/widget_18.xcf b/src/main/resources/assets/overdrive_that_matters/textures/gui/widgets/widget_18.xcf index f9b632cf4e2692ec0fb220f9b0dec6b29aea08fc..ad1bff632cc93ed840d5d52d044f945e448f2ce0 100644 GIT binary patch delta 1391 zcmd^8O=uHA6rP!6(`-#`OxhHa)NV|SX`;a&sED9QK>|_)@hs>`5xgiCdP(a=kwU8j z3Zm#iK@V+1Hr7y3Q?Qpxabi6PX%B_kfQt1XSZM3`_D!P6O?!2CJKx*y&3iL%zTN9R z6K96c(e9h)Kc{C14*P3`&eIAvEi2qStI%^?VQWTVa86;zh{ElU6z+JeaOVw$@h1v* zk14F1J%sROrtt!`yTanGcqv|qd~wL&Q*=y=z|t@cU=-;-}qkL&ulKfz}jep zm%IaJpRJ2_c8dGrnIWEwOtHT>B*p=+76%QH5idlp*bn9NA_sGp53~>0)IVBZU;Bvl z9Te*Om}4tn(N3kPTqBZ5MyPZUo0Nos&!mm40!x5#!n10*;Qf#VSwOS=CAoy=Bu*LU zQtSEGVv}+b%_>%wWwZ?!!y{Hs`Nvl$3-NqI^FbGp&=-|<>`zLatV54>U>bm-fL7<4 z#X`?I_^R(lP95IEI$5)B#3tj`t%Ab%P{4?|^LNTvNlN)6;MEMh50nYe+bE1a`kx7N za>K$@q-y*vSydvQqr3RDXOLfJCzwm(ci$Ai>uuU!`LR-rHUGqj+m8|VK66DoU}N43 z$a=3K>wN%nq|HVBAv@+P)QFY>-%`}BINzeepiqc&bq&03$0GZub|$>AwX4$njKS<2tETr@8QbjqT6 z3`gH%IQqrR21hB2-9t8(w^%(^JtvnPy|;`jU|FM=vV@7N5^pg#Q8q_HGmIt2kxjls LHu=fSL_W}8h9uie delta 517 zcmdm$*x@@NgVA_m=Ig+%3}C>r5JGcELTK(f2raYIXo(^SEnN(uWg{T8LK%cs zuARJ>QGW72Zkfr4f)@$^Bg2a_H^ zQV57yAYwe5Ahggt2n{A-YJeP`OAv9vRh$2a-DYDFUJtfR_%zHi;m4bKui5;5! zMnOtS>>iRiB0x6CE+7#5wpl^3o{34a9IRh*GEBeZYM}lk#>s!>@-{D3&rIgq?C5710Gn42dXYL!pkqxlAi%QmmjVq|1eYy_)SoC`BV paqH&$+Gm-VR9e6iDhptSsO$i{kAY$GTK(k7>-3X0uhZvY1OTUmZoU8j From ebdff6811d914558dddb9267245ca843aaa4f885 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Thu, 6 Mar 2025 16:49:10 +0700 Subject: [PATCH 05/22] Don't scramble xoshiro on fork since seed is already enough random --- .../ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt index 5095ac2fe..a6c595115 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt @@ -92,7 +92,7 @@ class Xoshiro256SSRandom private constructor( } override fun fork(): RandomSource { - return Xoshiro256SSRandom(nextLong(), nextLong(), nextLong(), nextLong()) + return Xoshiro256SSRandom(nextLong(), nextLong(), nextLong(), nextLong(), null) } override fun forkPositional(): PositionalRandomFactory { From 322d89f2a2923a7efd243b7a06959a6e2da93077 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 8 Mar 2025 14:12:32 +0700 Subject: [PATCH 06/22] Micro optimization --- src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LCG64Random.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LCG64Random.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LCG64Random.kt index d6edf5afc..eb939ab0b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LCG64Random.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LCG64Random.kt @@ -33,7 +33,7 @@ class LCG64Random(private var seed: Long = RandomSupport.generateUniqueSeed()) : } override fun nextLong(): Long { - val a = nextInt().toLong() and 0xFFFFFFFFL + val a = nextInt().toLong() val b = nextInt().toLong() and 0xFFFFFFFFL return a.shl(32) or b } From 430bc70c7e520deac442384574f1aa3c1e1bcf87 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 8 Mar 2025 16:45:38 +0700 Subject: [PATCH 07/22] =?UTF-8?q?Move=20PRNG=20implementation=20to=20Kommo?= =?UTF-8?q?ns=20Yurie=20=E2=80=94=20=D0=A1=D0=B5=D0=B3=D0=BE=D0=B4=D0=BD?= =?UTF-8?q?=D1=8F,=20=D0=B2=2015:09=20=D0=B2=D0=BE=D0=BF=D1=80=D0=BE=D1=81?= =?UTF-8?q?=20=D0=BF=D0=BE=D1=87=D0=B5=D0=BC=D1=83=20=D0=B2=D1=81=D0=B5=20?= =?UTF-8?q?=D1=8D=D1=82=D0=B8=20=D1=80=D0=B0=D0=BD=D0=B4=D0=BE=D0=BC=D1=8B?= =?UTF-8?q?=20=D0=BD=D0=B5=20=D0=B2=20kommons?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- gradle.properties | 2 +- .../dbotthepony/mc/otm/mixin/LevelMixin.java | 4 +- .../mc/otm/core/util/CMWCRandom.kt | 1 + .../otm/core/util/IRandomSourceGenerator.kt | 30 ++++ .../{LCG64Random.kt => LCG64RandomSource.kt} | 43 +----- .../mc/otm/core/util/Xoshiro256Random.kt | 93 ++++++++++++ .../mc/otm/core/util/Xoshiro256SSRandom.kt | 138 ------------------ 7 files changed, 133 insertions(+), 178 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/core/util/IRandomSourceGenerator.kt rename src/main/kotlin/ru/dbotthepony/mc/otm/core/util/{LCG64Random.kt => LCG64RandomSource.kt} (63%) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256Random.kt delete mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt diff --git a/gradle.properties b/gradle.properties index 47fdf3e3e..fa23fe2bf 100644 --- a/gradle.properties +++ b/gradle.properties @@ -22,7 +22,7 @@ mixin_version=0.8.5 neogradle.subsystems.parchment.minecraftVersion=1.21.1 neogradle.subsystems.parchment.mappingsVersion=2024.11.17 -kommons_version=3.1.3 +kommons_version=3.2.1 caffeine_cache_version=3.1.5 jei_version=19.16.4.171 diff --git a/src/main/java/ru/dbotthepony/mc/otm/mixin/LevelMixin.java b/src/main/java/ru/dbotthepony/mc/otm/mixin/LevelMixin.java index 8f60b5a71..e03b7aba2 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/mixin/LevelMixin.java +++ b/src/main/java/ru/dbotthepony/mc/otm/mixin/LevelMixin.java @@ -5,11 +5,11 @@ import net.minecraft.world.level.Level; import org.jetbrains.annotations.NotNull; import org.spongepowered.asm.mixin.Mixin; import ru.dbotthepony.mc.otm.core.IMatteryLevel; -import ru.dbotthepony.mc.otm.core.util.Xoshiro256SSRandom; +import ru.dbotthepony.mc.otm.core.util.Xoshiro256Random; @Mixin(Level.class) public abstract class LevelMixin implements IMatteryLevel { - public final RandomSource otm_random = new Xoshiro256SSRandom(); + public final RandomSource otm_random = new Xoshiro256Random(); @Override public @NotNull RandomSource getOtmRandom() { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/CMWCRandom.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/CMWCRandom.kt index 16d885b7e..c2891df03 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/CMWCRandom.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/CMWCRandom.kt @@ -5,6 +5,7 @@ import net.minecraft.util.RandomSource import net.minecraft.world.level.levelgen.MarsagliaPolarGaussian import net.minecraft.world.level.levelgen.PositionalRandomFactory import net.minecraft.world.level.levelgen.RandomSupport +import ru.dbotthepony.kommons.random.LCG64Random import java.lang.StringBuilder import java.util.random.RandomGenerator diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/IRandomSourceGenerator.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/IRandomSourceGenerator.kt new file mode 100644 index 000000000..999e39cfd --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/IRandomSourceGenerator.kt @@ -0,0 +1,30 @@ +package ru.dbotthepony.mc.otm.core.util + +import net.minecraft.util.RandomSource +import java.util.random.RandomGenerator + +interface IRandomSourceGenerator : RandomSource, RandomGenerator { + override fun nextInt(): Int + + override fun nextInt(bound: Int): Int { + return super.nextInt(bound) + } + + override fun nextInt(origin: Int, bound: Int): Int { + return super.nextInt(origin, bound) + } + + override fun nextBoolean(): Boolean { + return super.nextBoolean() + } + + override fun nextFloat(): Float { + return super.nextFloat() + } + + override fun nextDouble(): Double { + return super.nextDouble() + } + + override fun nextGaussian(): Double +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LCG64Random.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LCG64RandomSource.kt similarity index 63% rename from src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LCG64Random.kt rename to src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LCG64RandomSource.kt index eb939ab0b..af4f1bdec 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LCG64Random.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LCG64RandomSource.kt @@ -6,8 +6,8 @@ import net.minecraft.world.level.levelgen.LegacyRandomSource import net.minecraft.world.level.levelgen.MarsagliaPolarGaussian import net.minecraft.world.level.levelgen.PositionalRandomFactory import net.minecraft.world.level.levelgen.RandomSupport +import ru.dbotthepony.kommons.random.LCG64Random import java.lang.StringBuilder -import java.util.random.RandomGenerator /** * Simple and insanely fast random number generator, which can be used for seeding (initializing internal state) of other number generators. @@ -19,7 +19,7 @@ import java.util.random.RandomGenerator * * Always use upper 32 bits instead of implementing BitRandomSource and sampling some upper bits * * Uses all bits from provided seed */ -class LCG64Random(private var seed: Long = RandomSupport.generateUniqueSeed()) : RandomGenerator, RandomSource { +class LCG64RandomSource(seed: Long = RandomSupport.generateUniqueSeed()) : LCG64Random(seed), IRandomSourceGenerator { private val gaussian = MarsagliaPolarGaussian(this) override fun setSeed(seed: Long) { @@ -27,43 +27,12 @@ class LCG64Random(private var seed: Long = RandomSupport.generateUniqueSeed()) : gaussian.reset() } - override fun nextInt(): Int { - this.seed = MULTIPLIER * this.seed + INCREMENT - return this.seed.ushr(32).toInt() - } - - override fun nextLong(): Long { - val a = nextInt().toLong() - val b = nextInt().toLong() and 0xFFFFFFFFL - return a.shl(32) or b - } - - override fun nextInt(bound: Int): Int { - return super.nextInt(bound) - } - - override fun nextInt(origin: Int, bound: Int): Int { - return super.nextInt(origin, bound) - } - - override fun nextBoolean(): Boolean { - return super.nextBoolean() - } - - override fun nextFloat(): Float { - return super.nextFloat() - } - - override fun nextDouble(): Double { - return super.nextDouble() - } - override fun nextGaussian(): Double { return gaussian.nextGaussian() } override fun fork(): RandomSource { - return LCG64Random(nextLong()) + return LCG64RandomSource(nextLong()) } override fun forkPositional(): PositionalRandomFactory { @@ -72,15 +41,15 @@ class LCG64Random(private var seed: Long = RandomSupport.generateUniqueSeed()) : class Positional(val seed: Long) : PositionalRandomFactory { override fun at(x: Int, y: Int, z: Int): RandomSource { - return LCG64Random(Mth.getSeed(x, y, z).xor(seed)) + return LCG64RandomSource(Mth.getSeed(x, y, z).xor(seed)) } override fun fromHashOf(name: String): RandomSource { - return LCG64Random(name.hashCode().toLong().xor(seed)) + return LCG64RandomSource(name.hashCode().toLong().xor(seed)) } override fun fromSeed(seed: Long): RandomSource { - return LCG64Random(seed) + return LCG64RandomSource(seed) } override fun parityConfigString(builder: StringBuilder) { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256Random.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256Random.kt new file mode 100644 index 000000000..5d1e2ee28 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256Random.kt @@ -0,0 +1,93 @@ +package ru.dbotthepony.mc.otm.core.util + +import it.unimi.dsi.fastutil.HashCommon +import net.minecraft.util.Mth +import net.minecraft.util.RandomSource +import net.minecraft.world.level.levelgen.MarsagliaPolarGaussian +import net.minecraft.world.level.levelgen.PositionalRandomFactory +import net.minecraft.world.level.levelgen.RandomSupport +import ru.dbotthepony.kommons.random.LCG64Random +import ru.dbotthepony.kommons.random.Xoshiro256StarStarRandom + +/** + * Excellent number generator with guaranteed period of 2^255 + */ +class Xoshiro256Random : Xoshiro256StarStarRandom, IRandomSourceGenerator { + private val gaussian = MarsagliaPolarGaussian(this) + + // raw + private constructor(s0: Long, s1: Long, s2: Long, s3: Long, marker: Nothing?): super(s0, s1, s2, s3, null) + // normal + constructor(s0: Long, s1: Long, s2: Long, s3: Long) : super(s0, s1, s2, s3) + + // 64-bit seeded + constructor(seed: Long) : super(1L, 2L, 3L, 4L, null) { + setSeed(seed) + } + + // completely random + constructor() : super(RandomSupport.generateUniqueSeed(), RandomSupport.generateUniqueSeed(), RandomSupport.generateUniqueSeed(), RandomSupport.generateUniqueSeed(), null) + + override fun setSeed(seed: Long) { + val rng = LCG64Random(seed) + s0 = rng.nextLong() + s1 = rng.nextLong() + s2 = rng.nextLong() + s3 = rng.nextLong() + gaussian.reset() + } + + override fun nextInt(): Int { + // sample upper bits + return nextLong().ushr(32).toInt() + } + + override fun nextGaussian(): Double { + return gaussian.nextGaussian() + } + + override fun fork(): RandomSource { + return Xoshiro256Random(nextLong(), nextLong(), nextLong(), nextLong(), null) + } + + override fun forkPositional(): PositionalRandomFactory { + return Positional(nextLong(), nextLong(), nextLong(), nextLong()) + } + + class Positional( + val s0: Long, + val s1: Long, + val s2: Long, + val s3: Long, + ) : PositionalRandomFactory { + override fun at(x: Int, y: Int, z: Int): RandomSource { + val rng = LCG64RandomSource(Mth.getSeed(x, y, z)) + + return Xoshiro256Random( + s0.rotateLeft(11).xor(rng.nextLong()), + s1.rotateLeft(22).xor(rng.nextLong()), + s2.rotateLeft(33).xor(rng.nextLong()), + s3.rotateLeft(44).xor(rng.nextLong()), + ) + } + + override fun fromHashOf(name: String): RandomSource { + return Xoshiro256Random(s0, HashCommon.murmurHash3(name.hashCode().toLong()).xor(s1), s2, s3) + } + + override fun fromSeed(seed: Long): RandomSource { + return Xoshiro256Random(seed) + } + + override fun parityConfigString(builder: StringBuilder) { + throw UnsupportedOperationException() + } + } + + companion object { + @JvmStatic + fun raw(s0: Long, s1: Long, s2: Long, s3: Long): Xoshiro256Random { + return Xoshiro256Random(s0, s1, s2, s3, null) + } + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt deleted file mode 100644 index a6c595115..000000000 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/Xoshiro256SSRandom.kt +++ /dev/null @@ -1,138 +0,0 @@ -package ru.dbotthepony.mc.otm.core.util - -import it.unimi.dsi.fastutil.HashCommon -import net.minecraft.util.Mth -import net.minecraft.util.RandomSource -import net.minecraft.world.level.levelgen.MarsagliaPolarGaussian -import net.minecraft.world.level.levelgen.PositionalRandomFactory -import net.minecraft.world.level.levelgen.RandomSupport -import java.util.random.RandomGenerator - -/** - * Excellent number generator with guaranteed period of 2^255 - */ -class Xoshiro256SSRandom private constructor( - private var s0: Long, - private var s1: Long, - private var s2: Long, - private var s3: Long, - marker: Nothing? -) : RandomGenerator, RandomSource { - private val gaussian = MarsagliaPolarGaussian(this) - - init { - if (s0 or s1 or s2 or s3 == 0L) { - s0 = 0x73CF3D83FFF44FF3L - s1 = 0x6412312B70F3CD37L - s2 = -0X6BB4C4E1327BFDCFL - s3 = -0X4BE0F5BB5F3F5240L - } - } - - constructor(s0: Long, s1: Long, s2: Long, s3: Long) : this(s0, s1, s2, s3, null) { - // discard some values so generator can get going if provided seed was "weak" - for (i in 0 until 32) - nextLong() - } - - constructor(seed: Long) : this(1L, 2L, 3L, 4L, null) { - setSeed(seed) - } - - constructor() : this(RandomSupport.generateUniqueSeed(), RandomSupport.generateUniqueSeed(), RandomSupport.generateUniqueSeed(), RandomSupport.generateUniqueSeed(), null) - - override fun setSeed(seed: Long) { - val rng = LCG64Random(seed) - s0 = rng.nextLong() - s1 = rng.nextLong() - s2 = rng.nextLong() - s3 = rng.nextLong() - gaussian.reset() - } - - override fun nextInt(): Int { - // sample upper bits - return nextLong().ushr(32).toInt() - } - - override fun nextLong(): Long { - val result = (s1 * 5).rotateLeft(7) * 9 - val t = s1.shl(17) - s2 = s2.xor(s0) - s3 = s3.xor(s1) - s1 = s1.xor(s2) - s0 = s0.xor(s3) - s2 = s2.xor(t) - s3 = s3.rotateLeft(45) - return result - } - - override fun nextInt(bound: Int): Int { - return super.nextInt(bound) - } - - override fun nextInt(origin: Int, bound: Int): Int { - return super.nextInt(origin, bound) - } - - override fun nextBoolean(): Boolean { - return super.nextBoolean() - } - - override fun nextFloat(): Float { - return super.nextFloat() - } - - override fun nextDouble(): Double { - return super.nextDouble() - } - - override fun nextGaussian(): Double { - return gaussian.nextGaussian() - } - - override fun fork(): RandomSource { - return Xoshiro256SSRandom(nextLong(), nextLong(), nextLong(), nextLong(), null) - } - - override fun forkPositional(): PositionalRandomFactory { - return Positional(nextLong(), nextLong(), nextLong(), nextLong()) - } - - class Positional( - val s0: Long, - val s1: Long, - val s2: Long, - val s3: Long, - ) : PositionalRandomFactory { - override fun at(x: Int, y: Int, z: Int): RandomSource { - val rng = LCG64Random(Mth.getSeed(x, y, z)) - - return Xoshiro256SSRandom( - s0.rotateLeft(11).xor(rng.nextLong()), - s1.rotateLeft(22).xor(rng.nextLong()), - s2.rotateLeft(33).xor(rng.nextLong()), - s3.rotateLeft(44).xor(rng.nextLong()), - ) - } - - override fun fromHashOf(name: String): RandomSource { - return Xoshiro256SSRandom(s0, HashCommon.murmurHash3(name.hashCode().toLong()).xor(s1), s2, s3) - } - - override fun fromSeed(seed: Long): RandomSource { - return Xoshiro256SSRandom(seed) - } - - override fun parityConfigString(builder: StringBuilder) { - throw UnsupportedOperationException() - } - } - - companion object { - @JvmStatic - fun raw(s0: Long, s1: Long, s2: Long, s3: Long): Xoshiro256SSRandom { - return Xoshiro256SSRandom(s0, s1, s2, s3, null) - } - } -} From 1ca2348adf88fc693406d28e6c64d8860e164010 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 8 Mar 2025 17:18:45 +0700 Subject: [PATCH 08/22] Provide PCG32 wrapper of RandomSource --- gradle.properties | 2 +- .../mc/otm/core/util/LCG64RandomSource.kt | 5 -- .../mc/otm/core/util/PCG32RandomSource.kt | 53 +++++++++++++++++++ 3 files changed, 54 insertions(+), 6 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/core/util/PCG32RandomSource.kt diff --git a/gradle.properties b/gradle.properties index fa23fe2bf..4b7460417 100644 --- a/gradle.properties +++ b/gradle.properties @@ -22,7 +22,7 @@ mixin_version=0.8.5 neogradle.subsystems.parchment.minecraftVersion=1.21.1 neogradle.subsystems.parchment.mappingsVersion=2024.11.17 -kommons_version=3.2.1 +kommons_version=3.3.0 caffeine_cache_version=3.1.5 jei_version=19.16.4.171 diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LCG64RandomSource.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LCG64RandomSource.kt index af4f1bdec..60f07343c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LCG64RandomSource.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/LCG64RandomSource.kt @@ -56,9 +56,4 @@ class LCG64RandomSource(seed: Long = RandomSupport.generateUniqueSeed()) : LCG64 throw UnsupportedOperationException() } } - - companion object { - const val MULTIPLIER = 6364136223846793005 - const val INCREMENT = 1442695040888963407 - } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/PCG32RandomSource.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/PCG32RandomSource.kt new file mode 100644 index 000000000..da61dbff2 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/PCG32RandomSource.kt @@ -0,0 +1,53 @@ +package ru.dbotthepony.mc.otm.core.util + +import net.minecraft.util.Mth +import net.minecraft.util.RandomSource +import net.minecraft.world.level.levelgen.LegacyRandomSource +import net.minecraft.world.level.levelgen.MarsagliaPolarGaussian +import net.minecraft.world.level.levelgen.PositionalRandomFactory +import net.minecraft.world.level.levelgen.RandomSupport +import ru.dbotthepony.kommons.random.LCG64Random +import ru.dbotthepony.kommons.random.PCG32Random +import java.lang.StringBuilder + +/** + * @see PCG32Random + */ +class PCG32RandomSource(seed: Long = RandomSupport.generateUniqueSeed()) : PCG32Random(seed), IRandomSourceGenerator { + private val gaussian = MarsagliaPolarGaussian(this) + + override fun setSeed(seed: Long) { + this.seed = seed + gaussian.reset() + } + + override fun nextGaussian(): Double { + return gaussian.nextGaussian() + } + + override fun fork(): RandomSource { + return PCG32RandomSource(nextLong()) + } + + override fun forkPositional(): PositionalRandomFactory { + return Positional(nextLong()) + } + + class Positional(val seed: Long) : PositionalRandomFactory { + override fun at(x: Int, y: Int, z: Int): RandomSource { + return PCG32RandomSource(Mth.getSeed(x, y, z).xor(seed)) + } + + override fun fromHashOf(name: String): RandomSource { + return PCG32RandomSource(name.hashCode().toLong().xor(seed)) + } + + override fun fromSeed(seed: Long): RandomSource { + return PCG32RandomSource(seed) + } + + override fun parityConfigString(builder: StringBuilder) { + throw UnsupportedOperationException() + } + } +} From 3bcfd5515443d765a871a9ab6936c7d591891f13 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 8 Mar 2025 17:30:25 +0700 Subject: [PATCH 09/22] Bump kommons --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 4b7460417..34773b4c6 100644 --- a/gradle.properties +++ b/gradle.properties @@ -22,7 +22,7 @@ mixin_version=0.8.5 neogradle.subsystems.parchment.minecraftVersion=1.21.1 neogradle.subsystems.parchment.mappingsVersion=2024.11.17 -kommons_version=3.3.0 +kommons_version=3.3.1 caffeine_cache_version=3.1.5 jei_version=19.16.4.171 From 7251760800aa37810824f66ee5e0754945bdff42 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 8 Mar 2025 17:32:42 +0700 Subject: [PATCH 10/22] Try PCG as otm provided random --- src/main/java/ru/dbotthepony/mc/otm/mixin/LevelMixin.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/ru/dbotthepony/mc/otm/mixin/LevelMixin.java b/src/main/java/ru/dbotthepony/mc/otm/mixin/LevelMixin.java index e03b7aba2..30172b5cb 100644 --- a/src/main/java/ru/dbotthepony/mc/otm/mixin/LevelMixin.java +++ b/src/main/java/ru/dbotthepony/mc/otm/mixin/LevelMixin.java @@ -5,11 +5,11 @@ import net.minecraft.world.level.Level; import org.jetbrains.annotations.NotNull; import org.spongepowered.asm.mixin.Mixin; import ru.dbotthepony.mc.otm.core.IMatteryLevel; -import ru.dbotthepony.mc.otm.core.util.Xoshiro256Random; +import ru.dbotthepony.mc.otm.core.util.PCG32RandomSource; @Mixin(Level.class) public abstract class LevelMixin implements IMatteryLevel { - public final RandomSource otm_random = new Xoshiro256Random(); + public final RandomSource otm_random = new PCG32RandomSource(); @Override public @NotNull RandomSource getOtmRandom() { From 65d076f6346aee782a02cc3e7b67d404ad638ed5 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 8 Mar 2025 17:45:09 +0700 Subject: [PATCH 11/22] Bump Kommons --- gradle.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle.properties b/gradle.properties index 34773b4c6..e0c63b221 100644 --- a/gradle.properties +++ b/gradle.properties @@ -22,7 +22,7 @@ mixin_version=0.8.5 neogradle.subsystems.parchment.minecraftVersion=1.21.1 neogradle.subsystems.parchment.mappingsVersion=2024.11.17 -kommons_version=3.3.1 +kommons_version=3.3.2 caffeine_cache_version=3.1.5 jei_version=19.16.4.171 From 85aecaf79b2fc032d06c44e4cd3752d07c8b9434 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sat, 8 Mar 2025 19:23:11 +0700 Subject: [PATCH 12/22] Cache toInt() and toLong() results in Decimal$Regular --- .../dbotthepony/mc/otm/core/math/Decimal.kt | 40 +++++++++++++------ 1 file changed, 28 insertions(+), 12 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/math/Decimal.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/math/Decimal.kt index 457874d17..4c4289757 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/math/Decimal.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/math/Decimal.kt @@ -240,24 +240,40 @@ sealed class Decimal : Number(), Comparable { return mag.signum() } + private var intCache = 0 + private var intComputed = false + override fun toInt(): Int { - return if (whole > BI_INT_MAX) { - Int.MAX_VALUE - } else if (whole < BI_INT_MIN) { - Int.MIN_VALUE - } else { - whole.toInt() + if (!intComputed) { + intCache = if (whole > BI_INT_MAX) { + Int.MAX_VALUE + } else if (whole < BI_INT_MIN) { + Int.MIN_VALUE + } else { + whole.toInt() + } + + intComputed = true } + + return intCache } + private var longCache = 0L + private var longComputed = false + override fun toLong(): Long { - return if (whole > BI_LONG_MAX) { - Long.MAX_VALUE - } else if (whole < BI_LONG_MIN) { - Long.MIN_VALUE - } else { - whole.toLong() + if (!longComputed) { + longCache = if (whole > BI_LONG_MAX) { + Long.MAX_VALUE + } else if (whole < BI_LONG_MIN) { + Long.MIN_VALUE + } else { + whole.toLong() + } } + + return longCache } override fun compareTo(other: Decimal): Int { From 67ea3b977b35fdbd3330f487459c3af9a08fd68b Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sun, 9 Mar 2025 16:00:51 +0700 Subject: [PATCH 13/22] Further improve performance of UpgradeContainer --- .../mc/otm/container/UpgradeContainer.kt | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/container/UpgradeContainer.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/container/UpgradeContainer.kt index 0c0070806..06879d676 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/container/UpgradeContainer.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/container/UpgradeContainer.kt @@ -39,9 +39,9 @@ class UpgradeContainer( } override val speedBonus: Double - get() = iterator().map { (it.getCapability(MatteryCapability.UPGRADE)?.speedBonus ?: 0.0) * it.count }.reduce(0.0) { a, b -> a + b } + get() = if (isEmpty) 0.0 else iterator().map { (it.getCapability(MatteryCapability.UPGRADE)?.speedBonus ?: 0.0) * it.count }.reduce(0.0) { a, b -> a + b } override val processingItems: Int - get() = iterator().map { (it.getCapability(MatteryCapability.UPGRADE)?.processingItems ?: 0).coerceAtLeast(0) * it.count }.reduce(0) { a, b -> a + b } + get() = if (isEmpty) 0 else iterator().map { (it.getCapability(MatteryCapability.UPGRADE)?.processingItems ?: 0).coerceAtLeast(0) * it.count }.reduce(0) { a, b -> a + b } override val energyStorageFlat: Decimal get() = positiveDecimals(IMatteryUpgrade::energyStorageFlat, Decimal::plus) override val energyStorage: Decimal @@ -53,7 +53,7 @@ class UpgradeContainer( override val energyConsumed: Decimal get() = anyDecimals(IMatteryUpgrade::energyConsumed, Decimal::plus) override val failureMultiplier: Double - get() = iterator().map { (it.getCapability(MatteryCapability.UPGRADE)?.failureMultiplier ?: 1.0).coerceAtLeast(0.0).pow(it.count.toDouble()) }.reduce(1.0) { a, b -> a * b } + get() = if (isEmpty) 1.0 else iterator().map { (it.getCapability(MatteryCapability.UPGRADE)?.failureMultiplier ?: 1.0).coerceAtLeast(0.0).pow(it.count.toDouble()) }.reduce(1.0) { a, b -> a * b } override val energyThroughputFlat: Decimal get() = positiveDecimals(IMatteryUpgrade::energyThroughputFlat, Decimal::plus) override val energyThroughput: Decimal @@ -62,24 +62,24 @@ class UpgradeContainer( fun transform(values: EnergyBalanceValues): EnergyBalanceValues { return object : EnergyBalanceValues { override val energyCapacity: Decimal - get() = values.energyCapacity * (energyStorage + Decimal.ONE) + energyStorageFlat + get() = if (isEmpty) values.energyCapacity else values.energyCapacity * (energyStorage + Decimal.ONE) + energyStorageFlat override val energyThroughput: Decimal - get() = values.energyThroughput * (this@UpgradeContainer.energyThroughput + Decimal.ONE) + energyThroughputFlat + get() = if (isEmpty) values.energyThroughput else values.energyThroughput * (this@UpgradeContainer.energyThroughput + Decimal.ONE) + energyThroughputFlat } } fun transform(values: VerboseEnergyBalanceValues): VerboseEnergyBalanceValues { return object : VerboseEnergyBalanceValues { override val energyCapacity: Decimal - get() = values.energyCapacity * (energyStorage + Decimal.ONE) + energyStorageFlat + get() = if (isEmpty) values.energyCapacity else values.energyCapacity * (energyStorage + Decimal.ONE) + energyStorageFlat override val maxEnergyReceive: Decimal - get() = values.maxEnergyReceive * (energyThroughput + Decimal.ONE) + energyThroughputFlat + get() = if (isEmpty) values.maxEnergyReceive else values.maxEnergyReceive * (energyThroughput + Decimal.ONE) + energyThroughputFlat override val maxEnergyExtract: Decimal - get() = values.maxEnergyExtract * (energyThroughput + Decimal.ONE) + energyThroughputFlat + get() =if (isEmpty) values.maxEnergyExtract else values.maxEnergyExtract * (energyThroughput + Decimal.ONE) + energyThroughputFlat } } fun matterCapacity(value: () -> Decimal): () -> Decimal { - return { value.invoke() * (matterStorage + Decimal.ONE) + matterStorageFlat } + return { if (isEmpty) value.invoke() else value.invoke() * (matterStorage + Decimal.ONE) + matterStorageFlat } } } From e97967903b11f82008571cc11478d84794bcb0c3 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sun, 9 Mar 2025 16:12:24 +0700 Subject: [PATCH 14/22] Update WitheredSkeletonSpawnHandler implementation --- .../ru/dbotthepony/mc/otm/entity/SpawnModifiers.kt | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/entity/SpawnModifiers.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/entity/SpawnModifiers.kt index 6ceaea61b..d1faa29ae 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/entity/SpawnModifiers.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/entity/SpawnModifiers.kt @@ -6,23 +6,24 @@ import net.minecraft.world.item.ItemStack import net.minecraft.world.item.Items import net.neoforged.bus.api.SubscribeEvent import net.neoforged.neoforge.event.entity.EntityJoinLevelEvent +import ru.dbotthepony.mc.otm.core.otmRandom import ru.dbotthepony.mc.otm.registry.game.MItems object WitheredSkeletonSpawnHandler { - @SubscribeEvent fun onEntityJoin(event: EntityJoinLevelEvent) { val entity = event.entity - if (entity is WitherSkeleton){ - val giveHelmet = entity.random.nextFloat() < 0.1f - val giveSword = entity.random.nextFloat() < 0.24f + if (entity is WitherSkeleton) { + val giveHelmet = event.level.otmRandom.nextFloat() < 0.1f + val giveSword = event.level.otmRandom.nextFloat() < 0.24f if (giveHelmet) { entity.setItemSlot(EquipmentSlot.HEAD, ItemStack(Items.NETHERITE_HELMET)) - entity.setItemSlot(EquipmentSlot.MAINHAND, ItemStack(MItems.WITHERED_STEEL_SWORD)) - } else if (giveSword) { + } + + if (giveSword || giveHelmet) { entity.setItemSlot(EquipmentSlot.MAINHAND, ItemStack(MItems.WITHERED_STEEL_SWORD)) } } From 6f2adfd6d3d8b467a59e08598332c9a9cab656a1 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sun, 9 Mar 2025 16:17:27 +0700 Subject: [PATCH 15/22] Withered Steel Sword fixes --- .../mc/otm/datagen/tags/EquipmentTags.kt | 7 ++++++- .../otm/item/weapon/WitheredSteelSwordItem.kt | 19 +++++++------------ 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/tags/EquipmentTags.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/tags/EquipmentTags.kt index 3b2d9d3eb..3b3ae39d3 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/tags/EquipmentTags.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/tags/EquipmentTags.kt @@ -34,7 +34,12 @@ fun addEquipmentTags(tagsProvider: TagsProvider) { .add(MItems.TRITANIUM_BOOTS) .add(MItems.SIMPLE_TRITANIUM_BOOTS) - tagsProvider.items.Appender(ItemTags.SWORDS).add(MItems.TRITANIUM_SWORD).add(MItems.ENERGY_SWORD) + tagsProvider.items.Appender(ItemTags.SWORDS) + .add(MItems.TRITANIUM_SWORD) + .add(MItems.ENERGY_SWORD) + .add(MItems.FALLING_SUN) + .add(MItems.WITHERED_STEEL_SWORD) + tagsProvider.items.Appender(ItemTags.AXES).add(MItems.TRITANIUM_AXE) tagsProvider.items.Appender(ItemTags.PICKAXES).add(MItems.TRITANIUM_PICKAXE) tagsProvider.items.Appender(ItemTags.SHOVELS).add(MItems.TRITANIUM_SHOVEL) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/item/weapon/WitheredSteelSwordItem.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/item/weapon/WitheredSteelSwordItem.kt index 8960a05fb..60101524a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/item/weapon/WitheredSteelSwordItem.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/weapon/WitheredSteelSwordItem.kt @@ -13,23 +13,19 @@ import net.minecraft.world.item.Tiers import net.minecraft.world.item.component.ItemAttributeModifiers import ru.dbotthepony.mc.otm.registry.game.MItems -class WitheredSteelSwordItem(properties: Item.Properties) : SwordItem(Tiers.IRON, properties){ +class WitheredSteelSwordItem(properties: Properties) : SwordItem(Tiers.IRON, properties) { private val attributes: ItemAttributeModifiers init { - var builder = ItemAttributeModifiers.builder() + val builder = ItemAttributeModifiers.builder() builder.add(Attributes.ATTACK_DAMAGE, AttributeModifier(BASE_ATTACK_DAMAGE_ID, 4.5, AttributeModifier.Operation.ADD_VALUE), EquipmentSlotGroup.MAINHAND) builder.add(Attributes.ATTACK_SPEED, AttributeModifier(BASE_ATTACK_SPEED_ID, -2.4, AttributeModifier.Operation.ADD_VALUE), EquipmentSlotGroup.MAINHAND) attributes = builder.build() } - override fun getMaxDamage(stack: ItemStack): Int { - return 420 - } - - override fun isEnchantable(p_41456_: ItemStack): Boolean { - return p_41456_.count == 1 + override fun isEnchantable(stack: ItemStack): Boolean { + return stack.count == 1 } override fun getEnchantmentValue(stack: ItemStack): Int { @@ -41,13 +37,12 @@ class WitheredSteelSwordItem(properties: Item.Properties) : SwordItem(Tiers.IRON } override fun hurtEnemy(stack: ItemStack, target: LivingEntity, attacker: LivingEntity): Boolean { - target.addEffect(MobEffectInstance(MobEffects.WITHER, 100, 0)) - return super.hurtEnemy(stack, target, attacker) + val status = super.hurtEnemy(stack, target, attacker) + if (status) target.addEffect(MobEffectInstance(MobEffects.WITHER, 100, 0)) + return status } override fun getDefaultAttributeModifiers(stack: ItemStack): ItemAttributeModifiers { return attributes } - - } From df7465a59f260f80840107759bc40e66a3a7f107 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sun, 9 Mar 2025 16:20:58 +0700 Subject: [PATCH 16/22] Wither skeleton sword and helmet server config --- .../ru/dbotthepony/mc/otm/config/ServerConfig.kt | 8 ++++++++ .../ru/dbotthepony/mc/otm/entity/SpawnModifiers.kt | 11 +++++++---- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/config/ServerConfig.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/config/ServerConfig.kt index 78c37014b..64766db67 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/config/ServerConfig.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/config/ServerConfig.kt @@ -76,4 +76,12 @@ object ServerConfig : AbstractConfig("misc") { builder.pop() } } + + val WITHER_SKELETON_HELMET_CHANCE: Double by builder + .comment("Chance of Wither Skeleton spawning with Netherite Helmet AND Withered Steel sword") + .defineInRange("WITHER_SKELETON_HELMET_CHANCE", 0.1, 0.0, 1.0) + + val WITHER_SKELETON_SWORD_CHANCE: Double by builder + .comment("Chance of Wither Skeleton spawning with Withered Steel sword") + .defineInRange("WITHER_SKELETON_HELMET_CHANCE", 0.24, 0.0, 1.0) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/entity/SpawnModifiers.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/entity/SpawnModifiers.kt index d1faa29ae..d7d1bb5d4 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/entity/SpawnModifiers.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/entity/SpawnModifiers.kt @@ -6,6 +6,7 @@ import net.minecraft.world.item.ItemStack import net.minecraft.world.item.Items import net.neoforged.bus.api.SubscribeEvent import net.neoforged.neoforge.event.entity.EntityJoinLevelEvent +import ru.dbotthepony.mc.otm.config.ServerConfig import ru.dbotthepony.mc.otm.core.otmRandom import ru.dbotthepony.mc.otm.registry.game.MItems @@ -16,15 +17,17 @@ object WitheredSkeletonSpawnHandler { val entity = event.entity if (entity is WitherSkeleton) { - val giveHelmet = event.level.otmRandom.nextFloat() < 0.1f - val giveSword = event.level.otmRandom.nextFloat() < 0.24f + val giveHelmet = event.level.otmRandom.nextFloat() < ServerConfig.WITHER_SKELETON_HELMET_CHANCE + val giveSword = event.level.otmRandom.nextFloat() < ServerConfig.WITHER_SKELETON_SWORD_CHANCE if (giveHelmet) { - entity.setItemSlot(EquipmentSlot.HEAD, ItemStack(Items.NETHERITE_HELMET)) + if (!entity.hasItemInSlot(EquipmentSlot.HEAD)) + entity.setItemSlot(EquipmentSlot.HEAD, ItemStack(Items.NETHERITE_HELMET)) } if (giveSword || giveHelmet) { - entity.setItemSlot(EquipmentSlot.MAINHAND, ItemStack(MItems.WITHERED_STEEL_SWORD)) + if (!entity.hasItemInSlot(EquipmentSlot.MAINHAND) || entity.getItemBySlot(EquipmentSlot.MAINHAND).item == Items.STONE_SWORD) + entity.setItemSlot(EquipmentSlot.MAINHAND, ItemStack(MItems.WITHERED_STEEL_SWORD)) } } } From f1c87ed5ad485629558e518a643ddc2f19336847 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sun, 9 Mar 2025 16:22:11 +0700 Subject: [PATCH 17/22] Specify effect source as attacker in Wither Steel Sword --- .../ru/dbotthepony/mc/otm/item/weapon/WitheredSteelSwordItem.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/item/weapon/WitheredSteelSwordItem.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/item/weapon/WitheredSteelSwordItem.kt index 60101524a..7de70f248 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/item/weapon/WitheredSteelSwordItem.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/weapon/WitheredSteelSwordItem.kt @@ -38,7 +38,7 @@ class WitheredSteelSwordItem(properties: Properties) : SwordItem(Tiers.IRON, pro override fun hurtEnemy(stack: ItemStack, target: LivingEntity, attacker: LivingEntity): Boolean { val status = super.hurtEnemy(stack, target, attacker) - if (status) target.addEffect(MobEffectInstance(MobEffects.WITHER, 100, 0)) + if (status) target.addEffect(MobEffectInstance(MobEffects.WITHER, 100, 0), attacker) return status } From 3f677ad35357e74a6fccb65678e169b5bc62f67d Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sun, 9 Mar 2025 18:35:55 +0700 Subject: [PATCH 18/22] Update bread item --- .../{ImperfectBread.kt => ImperfectBreadItem.kt} | 14 +++++--------- .../ru/dbotthepony/mc/otm/registry/game/MItems.kt | 8 +------- 2 files changed, 6 insertions(+), 16 deletions(-) rename src/main/kotlin/ru/dbotthepony/mc/otm/item/consumables/{ImperfectBread.kt => ImperfectBreadItem.kt} (66%) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/item/consumables/ImperfectBread.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/item/consumables/ImperfectBreadItem.kt similarity index 66% rename from src/main/kotlin/ru/dbotthepony/mc/otm/item/consumables/ImperfectBread.kt rename to src/main/kotlin/ru/dbotthepony/mc/otm/item/consumables/ImperfectBreadItem.kt index d67ae84e9..0ad85e2ea 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/item/consumables/ImperfectBread.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/consumables/ImperfectBreadItem.kt @@ -1,5 +1,6 @@ package ru.dbotthepony.mc.otm.item.consumables +import net.minecraft.server.level.ServerPlayer import net.minecraft.world.effect.MobEffectInstance import net.minecraft.world.effect.MobEffects import net.minecraft.world.level.Level @@ -9,17 +10,12 @@ import net.minecraft.world.food.FoodProperties import net.minecraft.world.item.Item import net.minecraft.world.item.ItemStack -class ImperfectBread(properties: Item.Properties) : Item(properties) { +class ImperfectBreadItem(properties: Item.Properties) : Item(properties) { override fun finishUsingItem(stack: ItemStack, level: Level, entity: LivingEntity): ItemStack { - if (entity is Player) { - entity.addEffect(MobEffectInstance(MobEffects.POISON, 80, 0)) + if (entity is ServerPlayer) { + entity.addEffect(MobEffectInstance(MobEffects.POISON, 80, 2)) } + return super.finishUsingItem(stack, level, entity) } } - -val IMPERFECT_BREAD_FOOD: FoodProperties = FoodProperties.Builder() - .nutrition(5) - .saturationModifier(0.6f) - .build() - diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MItems.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MItems.kt index cbd83e673..5857a511e 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MItems.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MItems.kt @@ -26,18 +26,12 @@ import net.minecraft.world.item.Tiers import net.minecraft.world.item.crafting.Ingredient import net.minecraft.world.level.block.Block import net.neoforged.bus.api.IEventBus -import net.neoforged.neoforge.common.DeferredSpawnEggItem import net.neoforged.neoforge.common.SimpleTier -import ru.dbotthepony.mc.otm.block.MatteryBlock -import ru.dbotthepony.mc.otm.block.addSimpleDescription -import ru.dbotthepony.mc.otm.block.tech.FlywheelBatteryBlock import ru.dbotthepony.mc.otm.capability.ITieredUpgradeSet import ru.dbotthepony.mc.otm.capability.MatteryPlayer import ru.dbotthepony.mc.otm.capability.UpgradeType import ru.dbotthepony.mc.otm.config.CablesConfig import ru.dbotthepony.mc.otm.config.ItemsConfig -import ru.dbotthepony.mc.otm.core.addAll -import ru.dbotthepony.mc.otm.core.asSupplierArray import ru.dbotthepony.mc.otm.core.collect.SupplierList import ru.dbotthepony.mc.otm.core.collect.SupplierMap import ru.dbotthepony.mc.otm.core.math.Decimal @@ -429,7 +423,7 @@ object MItems { val PILL_HEAL: Item by registry.register(MNames.PILL_HEAL) { HealPillItem() } val PILL_NOT_NORMAL: Item by registry.register(MNames.PILL_NOT_NORMAL) { NotNormalPill() } - val IMPERFECT_BREAD: Item by registry.register(MNames.IMPERFECT_BREAD) { ImperfectBread(Item.Properties().food(IMPERFECT_BREAD_FOOD)) } + val IMPERFECT_BREAD: Item by registry.register(MNames.IMPERFECT_BREAD) { ImperfectBreadItem(Item.Properties().food(FoodProperties.Builder().nutrition(5).saturationModifier(0.6f).build())) } val PILLS = SupplierList( MItems::PILL_ANDROID, From 1a30f4d2037d6ffc02292db1ab71df89bd86affa Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sun, 9 Mar 2025 19:54:03 +0700 Subject: [PATCH 19/22] Gold Disk, for spawning in dungeons, add Imperfect Bread to dungeons as Gold Disk --- .../ru/dbotthepony/mc/otm/datagen/DataGen.kt | 5 ++ .../mc/otm/datagen/items/ItemModels.kt | 2 + .../mc/otm/datagen/lang/English.kt | 3 + .../mc/otm/datagen/lang/Russian.kt | 3 + .../mc/otm/datagen/loot/LootModifiersData.kt | 13 +++ .../otm/capability/matter/IPatternStorage.kt | 22 +++++ .../mc/otm/item/matter/GoldDiskItem.kt | 84 +++++++++++++++++++ .../mc/otm/item/matter/PatternStorageItem.kt | 36 +++----- .../mc/otm/registry/game/MItems.kt | 3 + 9 files changed, 147 insertions(+), 24 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/item/matter/GoldDiskItem.kt diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/DataGen.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/DataGen.kt index 206133507..8ce8671ac 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/DataGen.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/DataGen.kt @@ -34,6 +34,7 @@ import ru.dbotthepony.mc.otm.datagen.items.MatteryItemModelProvider import ru.dbotthepony.mc.otm.datagen.lang.AddEnglishLanguage import ru.dbotthepony.mc.otm.datagen.models.MatteryBlockModelProvider import ru.dbotthepony.mc.otm.core.registryName +import ru.dbotthepony.mc.otm.core.util.PCG32RandomSource import ru.dbotthepony.mc.otm.data.FlywheelMaterialDataProvider import ru.dbotthepony.mc.otm.datagen.advancements.addAdvancements import ru.dbotthepony.mc.otm.datagen.advancements.addAndroidAdvancements @@ -68,6 +69,10 @@ internal fun modLootTable(string: String) = ResourceKey.create(Registries.LOOT_T object DataGen { const val MOD_ID = OverdriveThatMatters.MOD_ID + // for things which need to be random (e.g. UUIDs), + // so builds continue to be reproducible + val random = PCG32RandomSource(822393994030754753L) + var blockModelProvider: MatteryBlockModelProvider by WriteOnce() private set var itemModelProvider: MatteryItemModelProvider by WriteOnce() diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/items/ItemModels.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/items/ItemModels.kt index 1c4bc7248..94c9b76ab 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/items/ItemModels.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/items/ItemModels.kt @@ -194,6 +194,8 @@ fun addItemModels(provider: MatteryItemModelProvider) { provider.generated(MItems.PATTERN_DRIVE_CREATIVE) provider.generated(MItems.PATTERN_DRIVE_CREATIVE2) + provider.withExistingParent(MItems.GOLD_DISK, MItems.PATTERN_DRIVE_CREATIVE.registryName!!) + provider.generated(MItems.MATTER_DUST) provider.generated(MItems.TRITANIUM_DOOR.values) diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt index 673379cff..f3f095f07 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt @@ -879,6 +879,9 @@ private fun items(provider: MatteryLanguageProvider) { add(MItems.PATTERN_DRIVE_QUAD, "Quad-Level Pattern Drive") add(MItems.PATTERN_DRIVE_CREATIVE, "Creative Pattern Drive") + add(MItems.GOLD_DISK, "Gold Disk") + add(MItems.GOLD_DISK, "single_item", "Gold Disk (%s)") + add(MItems.PATTERN_DRIVE_CREATIVE2, "Omni-Present Pattern Drive") add(MItems.PATTERN_DRIVE_CREATIVE2, "description1", "Creative-only item") add(MItems.PATTERN_DRIVE_CREATIVE2, "description2", "Holds pattern for every item that have matter value") diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt index ae0d7b49b..faf9ae2b1 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt @@ -872,6 +872,9 @@ private fun items(provider: MatteryLanguageProvider) { add(MItems.PATTERN_DRIVE_QUAD, "Четырёхуровневый диск шаблонов") add(MItems.PATTERN_DRIVE_CREATIVE, "Творческий диск шаблонов") + add(MItems.GOLD_DISK, "Золотой диск") + add(MItems.GOLD_DISK, "single_item", "Золотой диск (%s)") + add(MItems.PATTERN_DRIVE_CREATIVE2, "Вездесущий диск шаблонов") add(MItems.PATTERN_DRIVE_CREATIVE2, "description1", "Предмет режима творчества") add(MItems.PATTERN_DRIVE_CREATIVE2, "description2", "Содержит в себе шаблоны всех предметов, которые имеют значение материи") diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/loot/LootModifiersData.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/loot/LootModifiersData.kt index 3305a8958..d186819db 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/loot/LootModifiersData.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/loot/LootModifiersData.kt @@ -5,6 +5,7 @@ import net.minecraft.resources.ResourceLocation import net.minecraft.util.valueproviders.UniformInt import net.minecraft.world.entity.EntityType import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.Items import net.minecraft.world.level.storage.loot.BuiltInLootTables import net.minecraft.world.level.storage.loot.LootTable import net.minecraft.world.level.storage.loot.predicates.LootItemCondition @@ -18,9 +19,11 @@ import ru.dbotthepony.mc.otm.data.condition.HasExoPackCondition import ru.dbotthepony.mc.otm.data.condition.ItemInInventoryCondition import ru.dbotthepony.mc.otm.data.condition.KilledByRealPlayerOrIndirectly import ru.dbotthepony.mc.otm.data.loot.LootPoolAppender +import ru.dbotthepony.mc.otm.datagen.DataGen import ru.dbotthepony.mc.otm.datagen.modLootTable import ru.dbotthepony.mc.otm.item.ProceduralBatteryItem import ru.dbotthepony.mc.otm.item.exopack.ProceduralExopackSlotUpgradeItem +import ru.dbotthepony.mc.otm.item.matter.GoldDiskItem import ru.dbotthepony.mc.otm.registry.game.MItems @Suppress("FunctionName") @@ -66,6 +69,11 @@ fun addLootModifiers(it: LootModifiers) { apply(ProceduralExopackSlotUpgradeItem.Randomizer(UniformInt.of(4, 10))) }, + singleItem(MItems.GOLD_DISK) { + chanceCondition(0.1) + apply(GoldDiskItem.patterns(DataGen.random, MItems.IMPERFECT_BREAD)) + }, + singleItem(MItems.PROCEDURAL_BATTERY) { chanceCondition(0.15) @@ -122,6 +130,11 @@ fun addLootModifiers(it: LootModifiers) { chanceCondition(0.1) apply(ProceduralExopackSlotUpgradeItem.Randomizer(UniformInt.of(27, 56), UniformInt.of(2, 6))) }, + + singleItem(MItems.GOLD_DISK) { + chanceCondition(0.15) + apply(GoldDiskItem.patterns(DataGen.random, Items.ENDER_PEARL)) + }, )) it.add("dungeon_pill", PlainLootAppender( diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/matter/IPatternStorage.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/matter/IPatternStorage.kt index 70238b168..d5ebbd7fb 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/capability/matter/IPatternStorage.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/capability/matter/IPatternStorage.kt @@ -1,7 +1,13 @@ package ru.dbotthepony.mc.otm.capability.matter +import net.minecraft.ChatFormatting +import net.minecraft.network.chat.Component import net.minecraft.world.item.Item +import net.minecraft.world.item.Item.TooltipContext +import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.TooltipFlag import ru.dbotthepony.kommons.math.RGBAColor +import ru.dbotthepony.mc.otm.core.TranslatableComponent import java.util.* import java.util.function.Predicate import java.util.stream.Collectors @@ -72,3 +78,19 @@ fun IPatternStorage.getBarWidth(): Int { fun IPatternStorage.getBarColor(): Int { return RGBAColor.LOW_PATTERNS.linearInterpolation((storedPatterns / patternCapacity).toFloat(), RGBAColor.FULL_PATTERNS).toBGR() } + +fun IPatternStorage.gatherTooltip( + context: TooltipContext, + components: MutableList, + tooltipType: TooltipFlag +) { + for (state in patterns) { + components.add( + TranslatableComponent( + "otm.item.pattern.line", + state.item.getName(ItemStack(state.item, 1)), + String.format("%.2f", state.researchPercent * 100.0) + ).withStyle(ChatFormatting.AQUA) + ) + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/item/matter/GoldDiskItem.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/item/matter/GoldDiskItem.kt new file mode 100644 index 000000000..dcdfda6c4 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/matter/GoldDiskItem.kt @@ -0,0 +1,84 @@ +package ru.dbotthepony.mc.otm.item.matter + +import com.google.common.collect.ImmutableList +import net.minecraft.network.chat.Component +import net.minecraft.util.RandomSource +import net.minecraft.world.item.Item +import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.Items +import net.minecraft.world.item.TooltipFlag +import net.minecraft.world.level.storage.loot.functions.LootItemConditionalFunction +import net.minecraft.world.level.storage.loot.functions.SetComponentsFunction +import net.neoforged.neoforge.capabilities.RegisterCapabilitiesEvent +import ru.dbotthepony.mc.otm.capability.MatteryCapability +import ru.dbotthepony.mc.otm.capability.matter.IPatternStorage +import ru.dbotthepony.mc.otm.capability.matter.PatternInsertFailure +import ru.dbotthepony.mc.otm.capability.matter.PatternInsertStatus +import ru.dbotthepony.mc.otm.capability.matter.PatternState +import ru.dbotthepony.mc.otm.capability.matter.gatherTooltip +import ru.dbotthepony.mc.otm.core.TextComponent +import ru.dbotthepony.mc.otm.core.TranslatableComponent +import ru.dbotthepony.mc.otm.core.stream +import ru.dbotthepony.mc.otm.item.MatteryItem +import ru.dbotthepony.mc.otm.registry.CapabilitiesRegisterListener +import ru.dbotthepony.mc.otm.registry.game.MDataComponentTypes +import java.util.* +import java.util.stream.Stream + +class GoldDiskItem(parameters: Properties) : MatteryItem(parameters), CapabilitiesRegisterListener { + override fun registerCapabilities(event: RegisterCapabilitiesEvent) { + event.registerItem(MatteryCapability.PATTERN_ITEM, { o, _ -> ItemPatternStorageCapability(o) }, this) + } + + override fun getName(stack: ItemStack): Component { + val data = stack[MDataComponentTypes.PATTERNS] + + if (data == null || data.size > 1) { + return super.getName(stack) + } else if (data.size == 0 || data[0].item == Items.AIR) { + return TranslatableComponent("$descriptionId.single_item", TextComponent("???")) + } else { + return TranslatableComponent("$descriptionId.single_item", data[0].item.getName(ItemStack(data[0].item))) + } + } + + override fun appendHoverText( + itemStack: ItemStack, + context: TooltipContext, + components: MutableList, + tooltipType: TooltipFlag + ) { + itemStack.getCapability(MatteryCapability.PATTERN_ITEM)?.gatherTooltip(context, components, tooltipType) + + super.appendHoverText(itemStack, context, components, tooltipType) + } + + class ItemPatternStorageCapability(val stack: ItemStack) : IPatternStorage { + override val patternCapacity: Int get() { + return stack[MDataComponentTypes.PATTERNS]?.size ?: 0 + } + + override val storedPatterns: Int get() { + return patternCapacity + } + + override val patterns: Stream get() { + return stack[MDataComponentTypes.PATTERNS]?.stream() ?: Stream.empty() + } + + override fun insertPattern(pattern: PatternState, onlyUpdate: Boolean, simulate: Boolean): PatternInsertStatus { + return PatternInsertFailure + } + } + + companion object { + fun patterns(random: RandomSource, vararg items: Item): LootItemConditionalFunction.Builder<*> { + return SetComponentsFunction.setComponent( + MDataComponentTypes.PATTERNS, + items + .stream() + .map { PatternState(UUID(random.nextLong(), random.nextLong()), it, 1.0) } + .collect(ImmutableList.toImmutableList())) + } + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/item/matter/PatternStorageItem.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/item/matter/PatternStorageItem.kt index eb4f62599..ee85ced91 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/item/matter/PatternStorageItem.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/matter/PatternStorageItem.kt @@ -3,7 +3,6 @@ package ru.dbotthepony.mc.otm.item.matter import com.google.common.collect.ImmutableList import net.minecraft.ChatFormatting import net.minecraft.network.chat.Component -import net.minecraft.world.item.Item import net.minecraft.world.item.ItemStack import net.minecraft.world.item.Rarity import net.minecraft.world.item.TooltipFlag @@ -15,23 +14,20 @@ import ru.dbotthepony.mc.otm.capability.matter.PatternInsertInserted import ru.dbotthepony.mc.otm.capability.matter.PatternInsertStatus import ru.dbotthepony.mc.otm.capability.matter.PatternInsertUpdated import ru.dbotthepony.mc.otm.capability.matter.PatternState +import ru.dbotthepony.mc.otm.capability.matter.gatherTooltip import ru.dbotthepony.mc.otm.capability.matter.getBarColor import ru.dbotthepony.mc.otm.capability.matter.getBarWidth import ru.dbotthepony.mc.otm.core.TranslatableComponent +import ru.dbotthepony.mc.otm.item.MatteryItem import ru.dbotthepony.mc.otm.registry.CapabilitiesRegisterListener import ru.dbotthepony.mc.otm.registry.game.MDataComponentTypes import java.util.stream.Stream -class PatternStorageItem : Item, CapabilitiesRegisterListener { +class PatternStorageItem : MatteryItem, CapabilitiesRegisterListener { private val _capacity: () -> Int val capacity get() = _capacity.invoke() var isCreative: Boolean - constructor(capacity: Int) : super(Properties().stacksTo(1)) { - _capacity = { capacity } - isCreative = false - } - constructor(capacity: () -> Int) : super(Properties().stacksTo(1)) { _capacity = capacity isCreative = false @@ -47,29 +43,21 @@ class PatternStorageItem : Item, CapabilitiesRegisterListener { } override fun appendHoverText( - p_41421_: ItemStack, - p_339594_: TooltipContext, - list: MutableList, - p_41424_: TooltipFlag + itemStack: ItemStack, + context: TooltipContext, + components: MutableList, + tooltipType: TooltipFlag ) { - p_41421_.getCapability(MatteryCapability.PATTERN_ITEM)?.let { + itemStack.getCapability(MatteryCapability.PATTERN_ITEM)?.let { if (isCreative) - list.add(TranslatableComponent("otm.item.pattern.infinite.stored", it.storedPatterns).withStyle(ChatFormatting.GRAY)) + components.add(TranslatableComponent("otm.item.pattern.infinite.stored", it.storedPatterns).withStyle(ChatFormatting.GRAY)) else - list.add(TranslatableComponent("otm.item.pattern.stored", it.storedPatterns, it.patternCapacity).withStyle(ChatFormatting.GRAY)) + components.add(TranslatableComponent("otm.item.pattern.stored", it.storedPatterns, it.patternCapacity).withStyle(ChatFormatting.GRAY)) - for (state in it.patterns) { - list.add( - TranslatableComponent( - "otm.item.pattern.line", - state.item.getName(ItemStack(state.item, 1)), - String.format("%.2f", state.researchPercent * 100.0) - ).withStyle(ChatFormatting.AQUA) - ) - } + it.gatherTooltip(context, components, tooltipType) } - super.appendHoverText(p_41421_, p_339594_, list, p_41424_) + super.appendHoverText(itemStack, context, components, tooltipType) } override fun isBarVisible(p_150899_: ItemStack): Boolean { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MItems.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MItems.kt index 5857a511e..eacba6edc 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MItems.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MItems.kt @@ -60,6 +60,7 @@ import ru.dbotthepony.mc.otm.item.exopack.ExopackSlotUpgradeItem import ru.dbotthepony.mc.otm.item.exopack.ExopackUpgradeItem import ru.dbotthepony.mc.otm.item.exopack.ProceduralExopackSlotUpgradeItem import ru.dbotthepony.mc.otm.item.matter.CreativePatternItem +import ru.dbotthepony.mc.otm.item.matter.GoldDiskItem import ru.dbotthepony.mc.otm.item.matter.MatterCapacitorItem import ru.dbotthepony.mc.otm.item.matter.MatterDustItem import ru.dbotthepony.mc.otm.item.matter.PatternStorageItem @@ -497,6 +498,8 @@ object MItems { val PATTERN_DRIVE_CREATIVE: Item by registry.register(MNames.PATTERN_DRIVE_CREATIVE) { PatternStorageItem() } val PATTERN_DRIVE_CREATIVE2: Item by registry.register(MNames.PATTERN_DRIVE_CREATIVE2) { CreativePatternItem() } + val GOLD_DISK: Item by registry.register("gold_disk") { GoldDiskItem(Properties().stacksTo(16).rarity(Rarity.RARE)) } + val PORTABLE_CONDENSATION_DRIVE: Item by registry.register(MNames.PORTABLE_CONDENSATION_DRIVE) { PortableCondensationDriveItem(4000) } val PORTABLE_DENSE_CONDENSATION_DRIVE: Item by registry.register(MNames.PORTABLE_DENSE_CONDENSATION_DRIVE) { PortableCondensationDriveItem(25000) } From 9b6fa89850474c91afd50f710af5097416081ce4 Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sun, 9 Mar 2025 19:55:35 +0700 Subject: [PATCH 20/22] Add matter value to imperfect bread so it can be replicated --- src/data/kotlin/ru/dbotthepony/mc/otm/datagen/MatterData.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/MatterData.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/MatterData.kt index d288f3e34..7958800d9 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/MatterData.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/MatterData.kt @@ -437,4 +437,6 @@ fun addMatterData(provider: MatterDataProvider) { } } } + + provider.inherit(MItems.IMPERFECT_BREAD, Items.BREAD, 1.5) } From 29edf383cda3013524646b2acbec119ce92d149b Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sun, 9 Mar 2025 20:06:49 +0700 Subject: [PATCH 21/22] Use thread local non-cryptographic random for Quantum Battery UUIDs since they dont need to be cryptographically secure --- .../kotlin/ru/dbotthepony/mc/otm/GlobalEventHandler.kt | 6 ++++++ src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt | 4 ++++ .../ru/dbotthepony/mc/otm/core/util/PCG32RandomSource.kt | 2 -- .../ru/dbotthepony/mc/otm/item/QuantumBatteryItem.kt | 9 ++++++--- 4 files changed, 16 insertions(+), 5 deletions(-) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/GlobalEventHandler.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/GlobalEventHandler.kt index 1e4a600d9..5f49c00f4 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/GlobalEventHandler.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/GlobalEventHandler.kt @@ -7,6 +7,7 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder import net.minecraft.client.server.IntegratedServer import net.minecraft.core.HolderLookup import net.minecraft.server.MinecraftServer +import net.minecraft.util.RandomSource import net.minecraft.world.level.Level import net.neoforged.api.distmarker.Dist import net.neoforged.fml.loading.FMLLoader @@ -22,12 +23,17 @@ import ru.dbotthepony.mc.otm.core.collect.WeakHashSet import ru.dbotthepony.mc.otm.core.util.AtomicallyInvalidatedLazy import ru.dbotthepony.mc.otm.core.util.IConditionalTickable import ru.dbotthepony.mc.otm.core.util.ITickable +import ru.dbotthepony.mc.otm.core.util.PCG32RandomSource import ru.dbotthepony.mc.otm.core.util.TickList import ru.dbotthepony.mc.otm.graph.GraphNodeList import java.lang.ref.Cleaner import java.util.* import java.util.concurrent.atomic.AtomicInteger +private val threadLocalRandom = ThreadLocal.withInitial { PCG32RandomSource() } +internal val THREAD_LOCAL_RANDOM: RandomSource + get() = threadLocalRandom.get() + private val preServerTick = TickList() private val postServerTick = TickList() private val preWorldTick = WeakHashMap() diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt index 97326b9b1..6203217b1 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt @@ -627,6 +627,10 @@ infix fun FluidStack.isNotSameAs(other: FluidStack): Boolean { data class DoublePair(val first: Double, val second: Double) +fun RandomSource.nextUUID(): UUID { + return UUID(nextLong(), nextLong()) +} + // normal distribution via Marsaglia polar method fun RandomGenerator.nextNormalDoubles(stddev: Double, mean: Double): DoublePair { var rand1: Double diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/PCG32RandomSource.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/PCG32RandomSource.kt index da61dbff2..7b721c195 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/PCG32RandomSource.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/util/PCG32RandomSource.kt @@ -2,11 +2,9 @@ package ru.dbotthepony.mc.otm.core.util import net.minecraft.util.Mth import net.minecraft.util.RandomSource -import net.minecraft.world.level.levelgen.LegacyRandomSource import net.minecraft.world.level.levelgen.MarsagliaPolarGaussian import net.minecraft.world.level.levelgen.PositionalRandomFactory import net.minecraft.world.level.levelgen.RandomSupport -import ru.dbotthepony.kommons.random.LCG64Random import ru.dbotthepony.kommons.random.PCG32Random import java.lang.StringBuilder diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/item/QuantumBatteryItem.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/item/QuantumBatteryItem.kt index 473813cce..76098d215 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/item/QuantumBatteryItem.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/QuantumBatteryItem.kt @@ -24,6 +24,7 @@ import net.neoforged.neoforge.event.tick.ServerTickEvent import net.neoforged.neoforge.network.PacketDistributor import net.neoforged.neoforge.network.handling.IPayloadContext import ru.dbotthepony.mc.otm.OverdriveThatMatters +import ru.dbotthepony.mc.otm.THREAD_LOCAL_RANDOM import ru.dbotthepony.mc.otm.capability.FlowDirection import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.trackedItems @@ -42,6 +43,8 @@ import ru.dbotthepony.mc.otm.core.math.readDecimal import ru.dbotthepony.mc.otm.core.math.set import ru.dbotthepony.mc.otm.core.math.writeDecimal import ru.dbotthepony.mc.otm.core.nbt.set +import ru.dbotthepony.mc.otm.core.nextUUID +import ru.dbotthepony.mc.otm.core.util.PCG32RandomSource import ru.dbotthepony.mc.otm.core.util.formatPower import ru.dbotthepony.mc.otm.isClientThread import ru.dbotthepony.mc.otm.isServerThread @@ -82,7 +85,7 @@ class QuantumBatteryItem(val savedataID: String, val balanceValues: EnergyBalanc } } - class UnboundValues(override val uuid: UUID = UUID.randomUUID()) : IValues { + class UnboundValues(override val uuid: UUID = THREAD_LOCAL_RANDOM.nextUUID()) : IValues { override var energy: Decimal = Decimal.ZERO override var passed: Decimal = Decimal.ZERO override var received: Decimal = Decimal.ZERO @@ -125,7 +128,7 @@ class QuantumBatteryItem(val savedataID: String, val balanceValues: EnergyBalanc } fun values(): Values { - return values(UUID.randomUUID()) + return values(THREAD_LOCAL_RANDOM.nextUUID()) } override fun save(nbt: CompoundTag, registry: HolderLookup.Provider): CompoundTag { @@ -160,7 +163,7 @@ class QuantumBatteryItem(val savedataID: String, val balanceValues: EnergyBalanc fun updateValues() { if (!values.isServer && isServerThread()) { - values = serverData.values(stack[MDataComponentTypes.QUANTUM_LINK_ID] ?: UUID.randomUUID().also { stack[MDataComponentTypes.QUANTUM_LINK_ID] = it }) + values = serverData.values(stack[MDataComponentTypes.QUANTUM_LINK_ID] ?: THREAD_LOCAL_RANDOM.nextUUID().also { stack[MDataComponentTypes.QUANTUM_LINK_ID] = it }) } else if (isClientThread()) { val id = stack[MDataComponentTypes.QUANTUM_LINK_ID] ?: return From 436606abf465fe9133030f65660291b9afcb755f Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Sun, 9 Mar 2025 21:11:42 +0700 Subject: [PATCH 22/22] Now Bread monster can spawn when thrown as item And when killed, inert version is dropped --- .../mc/otm/datagen/lang/English.kt | 2 + .../mc/otm/datagen/lang/Russian.kt | 2 + .../mc/otm/datagen/loot/EntityLoot.kt | 11 +++++ .../dbotthepony/mc/otm/entity/BreadMonster.kt | 3 ++ .../item/consumables/ImperfectBreadItem.kt | 41 ++++++++++++++++--- .../mc/otm/registry/game/MCreativeTabs.kt | 3 ++ .../otm/registry/game/MDataComponentTypes.kt | 3 ++ 7 files changed, 60 insertions(+), 5 deletions(-) diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt index f3f095f07..9dc45033e 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/English.kt @@ -145,6 +145,8 @@ private fun sounds(provider: MatteryLanguageProvider) { private fun misc(provider: MatteryLanguageProvider) { with(provider.english) { + misc("misc.inert", "Inert") + misc("misc.yes", "Yes") misc("misc.no", "No") diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt index faf9ae2b1..9a8cfdc09 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/lang/Russian.kt @@ -159,6 +159,8 @@ private fun sounds(provider: MatteryLanguageProvider) { private fun misc(provider: MatteryLanguageProvider) { with(provider.russian) { + misc("misc.inert", "Инертен") + misc("misc.yes", "Да") misc("misc.no", "Нет") diff --git a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/loot/EntityLoot.kt b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/loot/EntityLoot.kt index 16ce1b445..1988712d3 100644 --- a/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/loot/EntityLoot.kt +++ b/src/data/kotlin/ru/dbotthepony/mc/otm/datagen/loot/EntityLoot.kt @@ -1,7 +1,10 @@ package ru.dbotthepony.mc.otm.datagen.loot +import net.minecraft.world.level.storage.loot.functions.SetComponentsFunction import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets import ru.dbotthepony.mc.otm.datagen.modLootTable +import ru.dbotthepony.mc.otm.registry.game.MDataComponentTypes +import ru.dbotthepony.mc.otm.registry.game.MEntityTypes import ru.dbotthepony.mc.otm.registry.game.MItems fun addEntityLoot(loot: LootTables) { @@ -18,4 +21,12 @@ fun addEntityLoot(loot: LootTables) { setRolls(1) } } + + loot.builder(LootContextParamSets.ENTITY, MEntityTypes.BREAD_MONSTER.defaultLootTable) { + lootPool { + item(MItems.IMPERFECT_BREAD) { + apply(SetComponentsFunction.setComponent(MDataComponentTypes.INERT, true)) + } + } + } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/entity/BreadMonster.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/entity/BreadMonster.kt index 512563d84..1303709cd 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/entity/BreadMonster.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/entity/BreadMonster.kt @@ -21,8 +21,11 @@ import net.minecraft.world.entity.monster.Zombie import net.minecraft.world.entity.npc.Villager import net.minecraft.world.entity.player.Player import net.minecraft.world.level.Level +import ru.dbotthepony.mc.otm.registry.game.MEntityTypes class BreadMonster(type: EntityType, level: Level) : Monster(type, level) { + constructor(level: Level) : this(MEntityTypes.BREAD_MONSTER, level) + val idleState = AnimationState() init { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/item/consumables/ImperfectBreadItem.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/item/consumables/ImperfectBreadItem.kt index 0ad85e2ea..089de13fc 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/item/consumables/ImperfectBreadItem.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/item/consumables/ImperfectBreadItem.kt @@ -1,16 +1,21 @@ package ru.dbotthepony.mc.otm.item.consumables +import net.minecraft.ChatFormatting import net.minecraft.server.level.ServerPlayer import net.minecraft.world.effect.MobEffectInstance import net.minecraft.world.effect.MobEffects -import net.minecraft.world.level.Level import net.minecraft.world.entity.LivingEntity -import net.minecraft.world.entity.player.Player -import net.minecraft.world.food.FoodProperties -import net.minecraft.world.item.Item +import net.minecraft.world.entity.item.ItemEntity import net.minecraft.world.item.ItemStack +import net.minecraft.world.level.Level +import ru.dbotthepony.mc.otm.core.TranslatableComponent +import ru.dbotthepony.mc.otm.core.otmRandom +import ru.dbotthepony.mc.otm.core.position +import ru.dbotthepony.mc.otm.entity.BreadMonster +import ru.dbotthepony.mc.otm.item.MatteryItem +import ru.dbotthepony.mc.otm.registry.game.MDataComponentTypes -class ImperfectBreadItem(properties: Item.Properties) : Item(properties) { +class ImperfectBreadItem(properties: Properties) : MatteryItem(properties) { override fun finishUsingItem(stack: ItemStack, level: Level, entity: LivingEntity): ItemStack { if (entity is ServerPlayer) { entity.addEffect(MobEffectInstance(MobEffects.POISON, 80, 2)) @@ -18,4 +23,30 @@ class ImperfectBreadItem(properties: Item.Properties) : Item(properties) { return super.finishUsingItem(stack, level, entity) } + + init { + tooltips.addNormal { itemStack, context, acceptor -> + if (itemStack[MDataComponentTypes.INERT] == true) { + acceptor(TranslatableComponent("otm.misc.inert").withStyle(ChatFormatting.DARK_GRAY)) + } + } + } + + override fun onEntityItemUpdate(stack: ItemStack, entity: ItemEntity): Boolean { + if (stack[MDataComponentTypes.INERT] == true) + return super.onEntityItemUpdate(stack, entity) + + // roll multiple times so multiple bread monsters can spawn on tick + // and also chance be less biased + for (i in 0 until stack.count.coerceAtMost(16)) { + if (entity.level().otmRandom.nextFloat() < 0.001f) { + val ent = BreadMonster(entity.level()) + ent.position = entity.position + entity.level().addFreshEntity(ent) + stack.shrink(1) + } + } + + return super.onEntityItemUpdate(stack, entity) + } } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MCreativeTabs.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MCreativeTabs.kt index 0d13a7607..4d1f4f08d 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MCreativeTabs.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MCreativeTabs.kt @@ -287,6 +287,9 @@ private fun addMainCreativeTabItems(consumer: CreativeModeTab.Output) { accept(MItems.NUTRIENT_PASTE) accept(MItems.IMPERFECT_BREAD) + accept(ItemStack(MItems.IMPERFECT_BREAD).also { + it[MDataComponentTypes.INERT] = true + }) // exo accept(MItems.EXOPACK_PROBE) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MDataComponentTypes.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MDataComponentTypes.kt index 1817fed3a..4459e52e0 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MDataComponentTypes.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MDataComponentTypes.kt @@ -4,6 +4,7 @@ import com.google.common.collect.ImmutableList import com.mojang.serialization.Codec import net.minecraft.core.UUIDUtil import net.minecraft.core.component.DataComponentType +import net.minecraft.core.component.DataComponents import net.minecraft.core.registries.BuiltInRegistries import net.minecraft.nbt.CompoundTag import net.minecraft.network.RegistryFriendlyByteBuf @@ -69,6 +70,8 @@ object MDataComponentTypes { val MAX_BATTERY_OUTPUT: DataComponentType by registry.register("max_battery_output") { DecimalComponent() } val MATTER_LEVEL: DataComponentType by registry.register("matter_level") { DecimalComponent() } + val INERT: DataComponentType by registry.register("inert") { DataComponentType.builder().persistent(Codec.BOOL).build() } + val EXOPACK_SLOT_COUNT: DataComponentType by registry.register("exopack_slot_count") { DataComponentType.builder().persistent(Codec.INT).networkSynchronized(StreamCodecs.INT).build() } val EXOPACK_UPGRADE_ID: DataComponentType by registry.register("exopack_upgrade_id") { uuid() } val QUANTUM_LINK_ID: DataComponentType by registry.register("quantum_link_id") { uuid() }