From 4a711783f5fcf54df3e039096be9cf53e4567efd Mon Sep 17 00:00:00 2001 From: DBotThePony Date: Mon, 24 Feb 2025 22:40:03 +0700 Subject: [PATCH] Flywheel battery status GUI --- .../mc/otm/datagen/lang/English.kt | 10 ++ .../mc/otm/datagen/lang/Russian.kt | 10 ++ .../entity/tech/FlywheelBatteryBlockEntity.kt | 31 +++++- .../otm/client/screen/panels/EditablePanel.kt | 58 ++++++++--- .../screen/panels/util/BackgroundPanel.kt | 16 ++- .../screen/tech/BlackHoleGeneratorScreen.kt | 18 +++- .../screen/tech/FlywheelBatteryScreen.kt | 99 +++++++++++++++++++ .../kotlin/ru/dbotthepony/mc/otm/core/Ext.kt | 8 ++ .../otm/menu/tech/BlackHoleGeneratorMenu.kt | 2 + .../mc/otm/menu/tech/FlywheelBatteryMenu.kt | 29 ++++++ .../ru/dbotthepony/mc/otm/network/Ext.kt | 2 + .../mc/otm/network/MatteryStreamCodec.kt | 70 +++++++++++++ .../mc/otm/network/StreamCodecs.kt | 29 +++--- .../mc/otm/registry/game/MMenus.kt | 4 + 14 files changed, 358 insertions(+), 28 deletions(-) create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/FlywheelBatteryScreen.kt create mode 100644 src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/FlywheelBatteryMenu.kt 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 316efeb0e..45f548eb3 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,9 @@ private fun sounds(provider: MatteryLanguageProvider) { private fun misc(provider: MatteryLanguageProvider) { with(provider.english) { + misc("misc.yes", "Yes") + misc("misc.no", "No") + misc("pwr_alert1", "[%s]") misc("pwr_alert2", "PWR: ALERT") misc("pwr_alert3", "WARNING ERROR:") @@ -941,6 +944,13 @@ private fun androidFeatures(provider: MatteryLanguageProvider) { private fun gui(provider: MatteryLanguageProvider) { with(provider.english) { + gui("multiblock.formed", "Multiblock is formed: %s") + + gui("flywheel.current_loss_t", "Current energy loss per tick:") + gui("flywheel.current_loss_s", "Current energy loss per second:") + gui("flywheel.core_material", "Core material:") + gui("flywheel.core_material_count", "(Core block count: %s)") + gui("flow_direction_set", "Flow direction set to %s") gui("tick_timer_set", "Timer set to %s ticks") 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 4da51e7bd..5aa057e8f 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,9 @@ private fun sounds(provider: MatteryLanguageProvider) { private fun misc(provider: MatteryLanguageProvider) { with(provider.russian) { + misc("misc.yes", "Да") + misc("misc.no", "Нет") + misc("pwr_alert2", "ПТН: ВНИМАНИЕ") misc("pwr_alert3", "ПРЕДУПРЕЖДЕНИЕ ОБ ОШИБКЕ:") misc("pwr_alert5", "Ошибка %s была обнаружена по адресу %s:%s в %s") @@ -934,6 +937,13 @@ private fun androidFeatures(provider: MatteryLanguageProvider) { private fun gui(provider: MatteryLanguageProvider) { with(provider.russian) { + gui("multiblock.formed", "Мультиблок сформирован: %s") + + gui("flywheel.current_loss_t", "Текущая потеря энергии в тик:") + gui("flywheel.current_loss_s", "Текущая потеря энергии в секунду:") + gui("flywheel.core_material", "Материал сердечника:") + gui("flywheel.core_material_count", "(Используется блоков сердечника: %s)") + gui("flow_direction_set", "Направление потока установлено на %s") gui("tick_timer_set", "Таймер установлен на %s тиков") diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/FlywheelBatteryBlockEntity.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/FlywheelBatteryBlockEntity.kt index 37b1322cc..6e6084a5b 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/FlywheelBatteryBlockEntity.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/block/entity/tech/FlywheelBatteryBlockEntity.kt @@ -2,10 +2,17 @@ package ru.dbotthepony.mc.otm.block.entity.tech import it.unimi.dsi.fastutil.ints.Int2ObjectFunction import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap +import it.unimi.dsi.fastutil.objects.Reference2IntMap import net.minecraft.core.BlockPos import net.minecraft.core.Vec3i +import net.minecraft.world.entity.player.Inventory +import net.minecraft.world.entity.player.Player +import net.minecraft.world.inventory.AbstractContainerMenu +import net.minecraft.world.level.block.Block +import net.minecraft.world.level.block.Blocks import net.minecraft.world.level.block.state.BlockState import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity +import ru.dbotthepony.mc.otm.block.entity.MatteryDeviceBlockEntity import ru.dbotthepony.mc.otm.capability.FlowDirection import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage @@ -19,15 +26,27 @@ import ru.dbotthepony.mc.otm.core.multiblock.ShapedMultiblockFactory import ru.dbotthepony.mc.otm.core.multiblock.Strategy import ru.dbotthepony.mc.otm.core.multiblock.shapedMultiblock import ru.dbotthepony.mc.otm.data.FlywheelMaterials +import ru.dbotthepony.mc.otm.menu.tech.FlywheelBatteryMenu import ru.dbotthepony.mc.otm.registry.game.MBlockEntities import ru.dbotthepony.mc.otm.registry.game.MBlocks -class FlywheelBatteryBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryBlockEntity(MBlockEntities.FLYWHEEL_BATTERY, blockPos, blockState), EnergyInterfaceBlockEntity.Target { +class FlywheelBatteryBlockEntity(blockPos: BlockPos, blockState: BlockState) : MatteryDeviceBlockEntity(MBlockEntities.FLYWHEEL_BATTERY, blockPos, blockState), EnergyInterfaceBlockEntity.Target { private var multiblock: ShapedMultiblock? = null private var lastHeight = -1 var batteryLevel = Decimal.ZERO private var cachedChargeEfficiency = Decimal.ONE + val formed: Boolean + get() = multiblock?.isValid == true + + // dangerous as Reference2IntMap.Entry reference live data, and its behavior is undefined once flywheel updates again + val currentlyUsedCore: Reference2IntMap.Entry? get() { + return multiblock?.blocks(FLYWHEEL_MATERIAL)?.reference2IntEntrySet()?.firstOrNull() + } + + var currentLossPerTick: Decimal = Decimal.ZERO + private set + private inner class Storage : IMatteryEnergyStorage { override fun extractEnergy(howMuch: Decimal, simulate: Boolean): Decimal { if (batteryLevel <= Decimal.ZERO) { @@ -117,13 +136,19 @@ class FlywheelBatteryBlockEntity(blockPos: BlockPos, blockState: BlockState) : M val material = FlywheelMaterials[entry.key]!! energy.parent.maxBatteryLevel = material.storage * entry.intValue cachedChargeEfficiency = material.receiveEfficiency - energy.extractEnergy(energy.parent.batteryLevel * MachinesConfig.Flywheel.PASSIVE_LOSS * material.momentumLossSpeed, false) + currentLossPerTick = energy.parent.batteryLevel * MachinesConfig.Flywheel.PASSIVE_LOSS * material.momentumLossSpeed + energy.extractEnergy(currentLossPerTick, false) } else { energy.parent.maxBatteryLevel = Decimal.ZERO - energy.extractEnergy(energy.parent.batteryLevel * MachinesConfig.Flywheel.ACTIVE_LOSS, false) + currentLossPerTick = energy.parent.batteryLevel * MachinesConfig.Flywheel.ACTIVE_LOSS + energy.extractEnergy(currentLossPerTick, false) } } + override fun createMenu(containerID: Int, inventory: Inventory, ply: Player): AbstractContainerMenu { + return FlywheelBatteryMenu(containerID, inventory, this) + } + companion object { private val FLYWHEEL_MATERIAL = Any() private val outerRing = listOf( diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/EditablePanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/EditablePanel.kt index 0450286a6..bd1493163 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/EditablePanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/EditablePanel.kt @@ -44,6 +44,42 @@ data class DockProperty(val left: Float = 0f, val top: Float = 0f, val right: Fl val horizontal get() = left + right val vertical get() = top + bottom + operator fun plus(other: DockProperty): DockProperty { + return DockProperty( + left + other.left, + top + other.top, + right + other.right, + bottom + other.bottom + ) + } + + operator fun minus(other: DockProperty): DockProperty { + return DockProperty( + left - other.left, + top - other.top, + right - other.right, + bottom - other.bottom + ) + } + + operator fun plus(other: Float): DockProperty { + return DockProperty( + left + other, + top + other, + right + other, + bottom + other + ) + } + + operator fun minus(other: Float): DockProperty { + return DockProperty( + left - other, + top - other, + right - other, + bottom - other + ) + } + companion object { val EMPTY = DockProperty() } @@ -1391,8 +1427,8 @@ open class EditablePanel( * Attempts to tightly fit dimensions to all children */ open fun sizeToContents() { - if (visibleChildrenInternal.isEmpty() || visibleChildrenInternal.any { it.dock == Dock.FILL }) { - // nothing to size against OR there is "fill" children + if (visibleChildrenInternal.isEmpty()) { + // nothing to size against return } @@ -1407,16 +1443,7 @@ open class EditablePanel( for (child in visibleChildrenInternal) { when (child.dock) { - Dock.NONE -> { - if (!child.ignoreWhenSizingToContents) { - width = maxOf(width, child.x + child.width) - height = maxOf(height, child.y + child.height) - } - } - - Dock.FILL -> { - throw RuntimeException() - } // do nothing + Dock.NONE, Dock.FILL -> {} Dock.LEFT, Dock.RIGHT -> { if (previousDock != 1) { @@ -1454,6 +1481,13 @@ open class EditablePanel( height = max(height, accumulatedHeight) } + for (child in visibleChildrenInternal) { + if ((child.dock == Dock.NONE || child.dock == Dock.FILL) && !child.ignoreWhenSizingToContents) { + width = maxOf(width, child.x + child.width) + height = maxOf(height, child.y + child.height) + } + } + this.width = width + dockPadding.left + dockPadding.right this.height = height + dockPadding.top + dockPadding.bottom diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/util/BackgroundPanel.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/util/BackgroundPanel.kt index 1086cf02b..89961c65a 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/util/BackgroundPanel.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/panels/util/BackgroundPanel.kt @@ -16,7 +16,7 @@ open class BackgroundPanel( height: Float = 10f, ) : EditablePanel(screen, parent, x, y, width, height) { init { - dockPadding = DockProperty(3f, 3f, 3f, 3f) + dockPadding = DEFAULT_PADDING } var drawBackground = true @@ -33,6 +33,9 @@ open class BackgroundPanel( } companion object { + private val DEFAULT_PADDING = DockProperty(3f, 3f, 3f, 3f) + private val BLOCK = DEFAULT_PADDING + 2f + fun padded( screen: S, parent: EditablePanel<*>?, @@ -42,6 +45,17 @@ open class BackgroundPanel( height: Float = 10f, ) = BackgroundPanel(screen, parent, x, y, width + 6f, height + 6f) + fun block( + screen: S, + parent: EditablePanel<*>?, + x: Float = 0f, + y: Float = 0f, + width: Float = 10f, + height: Float = 10f, + ) = BackgroundPanel(screen, parent, x, y, width + 6f, height + 6f).also { + it.dockPadding = BLOCK + } + fun paddedCenter( screen: S, parent: EditablePanel<*>?, diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/BlackHoleGeneratorScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/BlackHoleGeneratorScreen.kt index df72120ea..7ebc0a72c 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/BlackHoleGeneratorScreen.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/BlackHoleGeneratorScreen.kt @@ -1,10 +1,12 @@ package ru.dbotthepony.mc.otm.client.screen.tech +import net.minecraft.ChatFormatting import net.minecraft.network.chat.Component import net.minecraft.world.entity.player.Inventory import ru.dbotthepony.mc.otm.block.entity.blackhole.BlackHoleGeneratorBlockEntity 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.DynamicLabel import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel import ru.dbotthepony.mc.otm.client.screen.panels.Label import ru.dbotthepony.mc.otm.client.screen.panels.button.BooleanButtonPanel @@ -17,10 +19,11 @@ import ru.dbotthepony.mc.otm.core.TextComponent import ru.dbotthepony.mc.otm.core.TranslatableComponent import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.menu.tech.BlackHoleGeneratorMenu +import java.util.function.Supplier class BlackHoleGeneratorScreen(menu: BlackHoleGeneratorMenu, inventory: Inventory, title: Component) : MatteryScreen(menu, inventory, title) { override fun makeMainFrame(): FramePanel> { - val frame = FramePanel.padded(this, 240f, 130f, title) + val frame = FramePanel.padded(this, 240f, 150f, title) frame.behaveAsWindow() frame.onClose { onClose() } @@ -32,6 +35,19 @@ class BlackHoleGeneratorScreen(menu: BlackHoleGeneratorMenu, inventory: Inventor it.tooltips.add(TranslatableComponent("otm.gui.black_hole_generator.help3")) } + DynamicLabel(this, frame, textSupplier = Supplier { + TranslatableComponent( + "otm.gui.multiblock.formed", + if (menu.formed.get()) + TranslatableComponent("otm.misc.yes").withStyle(ChatFormatting.DARK_GREEN) + else + TranslatableComponent("otm.misc.no") + ) + }).also { + it.dock = Dock.TOP + it.dockTop = 4f + } + val energy = ProfiledPowerGaugePanel(this, frame, menu.energy) val matter = ProfiledMatterGaugePanel(this, frame, menu.matter) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/FlywheelBatteryScreen.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/FlywheelBatteryScreen.kt new file mode 100644 index 000000000..ba2289602 --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/client/screen/tech/FlywheelBatteryScreen.kt @@ -0,0 +1,99 @@ +package ru.dbotthepony.mc.otm.client.screen.tech + +import net.minecraft.ChatFormatting +import net.minecraft.network.chat.Component +import net.minecraft.world.entity.player.Inventory +import net.minecraft.world.item.ItemStack +import net.minecraft.world.item.Items +import ru.dbotthepony.mc.otm.client.render.RenderGravity +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.DockProperty +import ru.dbotthepony.mc.otm.client.screen.panels.DockResizeMode +import ru.dbotthepony.mc.otm.client.screen.panels.DynamicLabel +import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel +import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel +import ru.dbotthepony.mc.otm.client.screen.panels.Label +import ru.dbotthepony.mc.otm.client.screen.panels.slot.AbstractSlotPanel +import ru.dbotthepony.mc.otm.client.screen.panels.util.BackgroundPanel +import ru.dbotthepony.mc.otm.client.screen.widget.TallHorizontalProfiledPowerGaugePanel +import ru.dbotthepony.mc.otm.core.TranslatableComponent +import ru.dbotthepony.mc.otm.core.util.formatPower +import ru.dbotthepony.mc.otm.menu.tech.FlywheelBatteryMenu +import java.util.function.Supplier + +class FlywheelBatteryScreen(menu: FlywheelBatteryMenu, inventory: Inventory, title: Component) : MatteryScreen(menu, inventory, title) { + override fun makeMainFrame(): FramePanel> { + val frame = FramePanel.padded(this, 240f, 0f, title) + + frame.behaveAsWindow() + frame.onClose { onClose() } + + DynamicLabel(this, frame, textSupplier = Supplier { + TranslatableComponent( + "otm.gui.multiblock.formed", + if (menu.formed.get()) + TranslatableComponent("otm.misc.yes").withStyle(ChatFormatting.DARK_GREEN) + else + TranslatableComponent("otm.misc.no") + ) + }).also { + it.dock = Dock.TOP + it.dockTop = 4f + } + + Label(this, frame, TranslatableComponent("otm.gui.flywheel.current_loss_t")).also { + it.dock = Dock.TOP + } + + DynamicLabel(this, frame, textSupplier = Supplier { menu.currentLossPerTick.get().formatPower(decimalPlaces = 6) }).also { + it.dock = Dock.TOP + } + + Label(this, frame, TranslatableComponent("otm.gui.flywheel.current_loss_s")).also { + it.dock = Dock.TOP + } + + DynamicLabel(this, frame, textSupplier = Supplier { (menu.currentLossPerTick.get() * 20).formatPower() }).also { + it.dock = Dock.TOP + } + + TallHorizontalProfiledPowerGaugePanel(this, frame, menu.energy).also { + it.dock = Dock.TOP + } + + val coreStrip = BackgroundPanel.block(this, frame) + + coreStrip.dock = Dock.TOP + coreStrip.dockTop = 4f + + val leftStrip = EditablePanel(this, coreStrip) + leftStrip.dock = Dock.FILL + + object : AbstractSlotPanel(this@FlywheelBatteryScreen, coreStrip) { + override val itemStack: ItemStack + get() = menu.core.get()?.key?.asItem()?.let { ItemStack(it) } ?: ItemStack.EMPTY + + init { + dock = Dock.RIGHT + dockResize = DockResizeMode.NONE + } + } + + Label(this, leftStrip, text = TranslatableComponent("otm.gui.flywheel.core_material")).also { + it.dock = Dock.TOP + it.gravity = RenderGravity.CENTER_LEFT + } + + DynamicLabel(this, leftStrip, textSupplier = Supplier { TranslatableComponent("otm.gui.flywheel.core_material_count", (menu.core.get()?.value ?: 0).toString()) }).also { + it.dock = Dock.TOP + } + + leftStrip.sizeToContents() + coreStrip.sizeToContents() + + frame.sizeToContents() + + 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 b66c2aeb7..d27971e20 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/core/Ext.kt @@ -282,6 +282,10 @@ fun FriendlyByteBuf.writeBlockType(value: Block) { writeType(BuiltInRegistries.BLOCK, value) } +fun FriendlyByteBuf.writeBlockState(value: BlockState) { + writeVarInt(Block.BLOCK_STATE_REGISTRY.getIdOrThrow(value)) +} + fun FriendlyByteBuf.writeItemType(value: Item) { writeType(BuiltInRegistries.ITEM, value) } @@ -307,6 +311,10 @@ fun FriendlyByteBuf.readBlockType(): Block { return readType(BuiltInRegistries.BLOCK) } +fun FriendlyByteBuf.readBlockState(): BlockState { + return Block.BLOCK_STATE_REGISTRY.byIdOrThrow(readVarInt()) +} + fun FriendlyByteBuf.readItemType(): Item { return readType(BuiltInRegistries.ITEM) } diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/BlackHoleGeneratorMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/BlackHoleGeneratorMenu.kt index 676b520df..49b9039ed 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/BlackHoleGeneratorMenu.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/BlackHoleGeneratorMenu.kt @@ -8,12 +8,14 @@ import ru.dbotthepony.mc.otm.menu.input.DecimalInputWithFeedback import ru.dbotthepony.mc.otm.menu.input.EnumInputWithFeedback import ru.dbotthepony.mc.otm.menu.widget.CombinedProfiledLevelGaugeWidget import ru.dbotthepony.mc.otm.registry.game.MMenus +import java.util.function.BooleanSupplier class BlackHoleGeneratorMenu( p_38852_: Int, inventory: Inventory, tile: BlackHoleGeneratorBlockEntity? = null, ) : MatteryMenu(MMenus.BLACK_HOLE_GENERATOR, p_38852_, inventory, tile) { + val formed = mSynchronizer.computedBoolean(BooleanSupplier { tile?.multiblock?.isValid ?: false }) val drawBuildingGuide = BooleanInputWithFeedback(this, tile?.let { it::drawBuildingGuide }) val energy = CombinedProfiledLevelGaugeWidget(this, tile?.energy) val matter = CombinedProfiledLevelGaugeWidget(this, tile?.matter) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/FlywheelBatteryMenu.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/FlywheelBatteryMenu.kt new file mode 100644 index 000000000..66de4494e --- /dev/null +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/menu/tech/FlywheelBatteryMenu.kt @@ -0,0 +1,29 @@ +package ru.dbotthepony.mc.otm.menu.tech + +import net.minecraft.world.entity.player.Inventory +import net.minecraft.world.level.block.Blocks +import ru.dbotthepony.mc.otm.block.entity.tech.FlywheelBatteryBlockEntity +import ru.dbotthepony.mc.otm.core.math.Decimal +import ru.dbotthepony.mc.otm.menu.MatteryMenu +import ru.dbotthepony.mc.otm.menu.widget.ProfiledLevelGaugeWidget +import ru.dbotthepony.mc.otm.network.MatteryStreamCodec +import ru.dbotthepony.mc.otm.network.StreamCodecs +import ru.dbotthepony.mc.otm.network.nullable +import ru.dbotthepony.mc.otm.registry.game.MMenus +import java.util.function.BooleanSupplier +import java.util.function.Supplier + +class FlywheelBatteryMenu( + containerId: Int, + inventory: Inventory, + tile: FlywheelBatteryBlockEntity? = null +) : MatteryMenu(MMenus.FLYWHEEL_BATTERY, containerId, inventory, tile) { + val formed = mSynchronizer.computedBoolean(BooleanSupplier { tile?.formed ?: false }) + val energy = ProfiledLevelGaugeWidget(this, tile?.energyInterfaceTarget) + val core = mSynchronizer.computed(Supplier { tile?.currentlyUsedCore }, CORE_TYPE_CODEC) + val currentLossPerTick = mSynchronizer.computedDecimal(Supplier { tile?.currentLossPerTick ?: Decimal.ZERO }) + + companion object { + private val CORE_TYPE_CODEC = MatteryStreamCodec.MapEntry(StreamCodecs.BLOCK_TYPE, StreamCodecs.VAR_INT).nullable() + } +} diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/network/Ext.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/network/Ext.kt index 15495e0cf..b9d4f2bad 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/network/Ext.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/Ext.kt @@ -74,6 +74,8 @@ fun FriendlyByteBuf.readByteList(): ByteArrayList { } fun StreamCodec.wrap(): MatteryStreamCodec = MatteryStreamCodec.Wrapper(this) +@Deprecated("Redundant wrapping", level = DeprecationLevel.ERROR, replaceWith = ReplaceWith("this")) +fun MatteryStreamCodec.wrap(): MatteryStreamCodec = this fun MatteryStreamCodec.nullable(): MatteryStreamCodec = MatteryStreamCodec.Nullable(this) fun MatteryStreamCodec.optional(): MatteryStreamCodec> = MatteryStreamCodec.Optional(this) diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryStreamCodec.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryStreamCodec.kt index d01605af8..aff3394b6 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryStreamCodec.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/MatteryStreamCodec.kt @@ -25,6 +25,76 @@ interface MatteryStreamCodec : StreamCodec<@UnsafeVariance S, override fun decode(stream: S): V override fun encode(stream: S, value: V) + class Of(private val writer: S.(V) -> Unit, private val reader: S.() -> V) : MatteryStreamCodec { + override fun decode(stream: S): V { + return reader(stream) + } + + override fun encode(stream: S, value: V) { + return writer(stream, value) + } + } + + abstract class AbstractPair(private val first: MatteryStreamCodec, private val second: MatteryStreamCodec) : MatteryStreamCodec { + protected abstract fun getFirst(value: P): A + protected abstract fun getSecond(value: P): B + protected abstract fun construct(a: A, b: B): P + + override fun decode(stream: S): P { + return construct(first.decode(stream), second.decode(stream)) + } + + override fun encode(stream: S, value: P) { + first.encode(stream, getFirst(value)) + second.encode(stream, getSecond(value)) + } + + override fun copy(value: P): P { + val a = first.copy(getFirst(value)) + val b = second.copy(getSecond(value)) + + if (a === getFirst(value) && b === getSecond(value)) + return value + + return construct(a, b) + } + + override fun compare(a: P, b: P): Boolean { + return first.compare(getFirst(a), getFirst(b)) && second.compare(getSecond(a), getSecond(b)) + } + } + + class Pair(first: MatteryStreamCodec, second: MatteryStreamCodec) : AbstractPair>(first, second) { + override fun getFirst(value: kotlin.Pair): A { + return value.first + } + + override fun getSecond(value: kotlin.Pair): B { + return value.second + } + + override fun construct(a: A, b: B): kotlin.Pair { + return a to b + } + } + + class MapEntry(first: MatteryStreamCodec, second: MatteryStreamCodec) : AbstractPair>(first, second) { + override fun getFirst(value: Map.Entry): A { + return value.key + } + + override fun getSecond(value: Map.Entry): B { + return value.value + } + + override fun construct(a: A, b: B): Map.Entry { + return object : Map.Entry { + override val key: A = a + override val value: B = b + } + } + } + class Wrapper(parent: StreamCodec) : MatteryStreamCodec, StreamCodec<@UnsafeVariance S, V> by parent class Nullable(val parent: MatteryStreamCodec) : MatteryStreamCodec { diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/network/StreamCodecs.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/network/StreamCodecs.kt index cb5085cd2..1e0b59ff9 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/network/StreamCodecs.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/network/StreamCodecs.kt @@ -6,27 +6,34 @@ import net.minecraft.network.FriendlyByteBuf import net.minecraft.network.codec.ByteBufCodecs import net.minecraft.network.codec.StreamCodec import net.minecraft.resources.ResourceLocation +import net.minecraft.world.level.block.Block +import net.minecraft.world.level.block.state.BlockState import ru.dbotthepony.kommons.math.RGBAColor import ru.dbotthepony.mc.otm.core.math.readDecimal import ru.dbotthepony.mc.otm.core.math.writeDecimal +import ru.dbotthepony.mc.otm.core.readBlockType import ru.dbotthepony.mc.otm.core.readItemType +import ru.dbotthepony.mc.otm.core.writeBlockType import ru.dbotthepony.mc.otm.core.writeItemType +import java.util.* object StreamCodecs { - val NOTHING: MatteryStreamCodec = StreamCodec.of({ _, _ -> }, { null }).wrap() + val NOTHING: MatteryStreamCodec = MatteryStreamCodec.Of({}, { null }) - val BYTE: MatteryStreamCodec = StreamCodec.of({ s, v -> s.writeByte(v.toInt()) }, ByteBuf::readByte).wrap() - val SHORT = ByteBufCodecs.SHORT.wrap() - val INT = ByteBufCodecs.INT.wrap() - val VAR_INT = ByteBufCodecs.VAR_INT.wrap() + val BYTE: MatteryStreamCodec = MatteryStreamCodec.Of({ v -> writeByte(v.toInt()) }, ByteBuf::readByte) + val SHORT: MatteryStreamCodec = ByteBufCodecs.SHORT.wrap() + val INT: MatteryStreamCodec = ByteBufCodecs.INT.wrap() + val VAR_INT: MatteryStreamCodec = ByteBufCodecs.VAR_INT.wrap() val LONG = StreamCodec.of(ByteBuf::writeLong, ByteBuf::readLong).wrap() - val VAR_LONG = ByteBufCodecs.VAR_LONG.wrap() - val DOUBLE = ByteBufCodecs.DOUBLE.wrap() - val FLOAT = ByteBufCodecs.FLOAT.wrap() - val BOOLEAN = ByteBufCodecs.BOOL.wrap() - val STRING = ByteBufCodecs.STRING_UTF8.wrap() - val UUID = UUIDUtil.STREAM_CODEC.wrap() + val VAR_LONG: MatteryStreamCodec = ByteBufCodecs.VAR_LONG.wrap() + val DOUBLE: MatteryStreamCodec = ByteBufCodecs.DOUBLE.wrap() + val FLOAT: MatteryStreamCodec = ByteBufCodecs.FLOAT.wrap() + val BOOLEAN: MatteryStreamCodec = ByteBufCodecs.BOOL.wrap() + val STRING: MatteryStreamCodec = ByteBufCodecs.STRING_UTF8.wrap() + val UUID: MatteryStreamCodec = UUIDUtil.STREAM_CODEC.wrap() val RESOURCE_LOCATION = ResourceLocation.STREAM_CODEC.wrap() + val BLOCK_STATE: MatteryStreamCodec = ByteBufCodecs.idMapper(Block.BLOCK_STATE_REGISTRY).wrap() + val BLOCK_TYPE = MatteryStreamCodec.Of(FriendlyByteBuf::writeBlockType, FriendlyByteBuf::readBlockType) val RGBA: MatteryStreamCodec = StreamCodec.of( { s, v -> s.writeFloat(v.red); s.writeFloat(v.green); s.writeFloat(v.blue); s.writeFloat(v.alpha) }, diff --git a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MMenus.kt b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MMenus.kt index 0d91332d9..5c0011609 100644 --- a/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MMenus.kt +++ b/src/main/kotlin/ru/dbotthepony/mc/otm/registry/game/MMenus.kt @@ -39,6 +39,7 @@ import ru.dbotthepony.mc.otm.client.screen.tech.EnergyCounterScreen import ru.dbotthepony.mc.otm.client.screen.tech.EnergyHatchScreen import ru.dbotthepony.mc.otm.client.screen.tech.EnergyServoScreen import ru.dbotthepony.mc.otm.client.screen.tech.EssenceStorageScreen +import ru.dbotthepony.mc.otm.client.screen.tech.FlywheelBatteryScreen import ru.dbotthepony.mc.otm.client.screen.tech.ItemHatchScreen import ru.dbotthepony.mc.otm.client.screen.tech.MatterHatchScreen import ru.dbotthepony.mc.otm.menu.decorative.CargoCrateMenu @@ -73,6 +74,7 @@ import ru.dbotthepony.mc.otm.menu.tech.EnergyCounterMenu import ru.dbotthepony.mc.otm.menu.tech.EnergyHatchMenu import ru.dbotthepony.mc.otm.menu.tech.EnergyServoMenu import ru.dbotthepony.mc.otm.menu.tech.EssenceStorageMenu +import ru.dbotthepony.mc.otm.menu.tech.FlywheelBatteryMenu import ru.dbotthepony.mc.otm.menu.tech.ItemHatchMenu import ru.dbotthepony.mc.otm.menu.tech.MatterHatchMenu import ru.dbotthepony.mc.otm.menu.tech.PlatePressMenu @@ -122,6 +124,7 @@ object MMenus { val ENERGY_INPUT_HATCH by registry.register(MNames.ENERGY_INPUT_HATCH) { MenuType(EnergyHatchMenu::input, FeatureFlags.VANILLA_SET) } val ENERGY_OUTPUT_HATCH by registry.register(MNames.ENERGY_OUTPUT_HATCH) { MenuType(EnergyHatchMenu::output, FeatureFlags.VANILLA_SET) } val BLACK_HOLE_GENERATOR by registry.register(MNames.BLACK_HOLE_GENERATOR) { MenuType(::BlackHoleGeneratorMenu, FeatureFlags.VANILLA_SET) } + val FLYWHEEL_BATTERY by registry.register(MNames.FLYWHEEL_BATTERY) { MenuType(::FlywheelBatteryMenu, FeatureFlags.VANILLA_SET) } val STORAGE_BUS by registry.register(MNames.STORAGE_BUS) { MenuType(::StorageBusMenu, FeatureFlags.VANILLA_SET) } val STORAGE_IMPORTER_EXPORTER by registry.register(MNames.STORAGE_IMPORTER) { MenuType(::StorageImporterExporterMenu, FeatureFlags.VANILLA_SET) } @@ -175,5 +178,6 @@ object MMenus { event.register(ENERGY_INPUT_HATCH, ::EnergyHatchScreen) event.register(ENERGY_OUTPUT_HATCH, ::EnergyHatchScreen) event.register(BLACK_HOLE_GENERATOR, ::BlackHoleGeneratorScreen) + event.register(FLYWHEEL_BATTERY, ::FlywheelBatteryScreen) } }