Flywheel battery status GUI

This commit is contained in:
DBotThePony 2025-02-24 22:40:03 +07:00
parent 2c741b45c3
commit 4a711783f5
Signed by: DBot
GPG Key ID: DCC23B5715498507
14 changed files with 358 additions and 28 deletions

View File

@ -145,6 +145,9 @@ private fun sounds(provider: MatteryLanguageProvider) {
private fun misc(provider: MatteryLanguageProvider) { private fun misc(provider: MatteryLanguageProvider) {
with(provider.english) { with(provider.english) {
misc("misc.yes", "Yes")
misc("misc.no", "No")
misc("pwr_alert1", "[%s]") misc("pwr_alert1", "[%s]")
misc("pwr_alert2", "PWR: ALERT") misc("pwr_alert2", "PWR: ALERT")
misc("pwr_alert3", "WARNING ERROR:") misc("pwr_alert3", "WARNING ERROR:")
@ -941,6 +944,13 @@ private fun androidFeatures(provider: MatteryLanguageProvider) {
private fun gui(provider: MatteryLanguageProvider) { private fun gui(provider: MatteryLanguageProvider) {
with(provider.english) { 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("flow_direction_set", "Flow direction set to %s")
gui("tick_timer_set", "Timer set to %s ticks") gui("tick_timer_set", "Timer set to %s ticks")

View File

@ -159,6 +159,9 @@ private fun sounds(provider: MatteryLanguageProvider) {
private fun misc(provider: MatteryLanguageProvider) { private fun misc(provider: MatteryLanguageProvider) {
with(provider.russian) { with(provider.russian) {
misc("misc.yes", "Да")
misc("misc.no", "Нет")
misc("pwr_alert2", "ПТН: ВНИМАНИЕ") misc("pwr_alert2", "ПТН: ВНИМАНИЕ")
misc("pwr_alert3", "ПРЕДУПРЕЖДЕНИЕ ОБ ОШИБКЕ:") misc("pwr_alert3", "ПРЕДУПРЕЖДЕНИЕ ОБ ОШИБКЕ:")
misc("pwr_alert5", "Ошибка %s была обнаружена по адресу %s:%s в %s") misc("pwr_alert5", "Ошибка %s была обнаружена по адресу %s:%s в %s")
@ -934,6 +937,13 @@ private fun androidFeatures(provider: MatteryLanguageProvider) {
private fun gui(provider: MatteryLanguageProvider) { private fun gui(provider: MatteryLanguageProvider) {
with(provider.russian) { 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("flow_direction_set", "Направление потока установлено на %s")
gui("tick_timer_set", "Таймер установлен на %s тиков") gui("tick_timer_set", "Таймер установлен на %s тиков")

View File

@ -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.Int2ObjectFunction
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap
import it.unimi.dsi.fastutil.objects.Reference2IntMap
import net.minecraft.core.BlockPos import net.minecraft.core.BlockPos
import net.minecraft.core.Vec3i 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 net.minecraft.world.level.block.state.BlockState
import ru.dbotthepony.mc.otm.block.entity.MatteryBlockEntity 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.FlowDirection
import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage import ru.dbotthepony.mc.otm.capability.energy.IMatteryEnergyStorage
import ru.dbotthepony.mc.otm.capability.energy.ProfiledEnergyStorage 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.Strategy
import ru.dbotthepony.mc.otm.core.multiblock.shapedMultiblock import ru.dbotthepony.mc.otm.core.multiblock.shapedMultiblock
import ru.dbotthepony.mc.otm.data.FlywheelMaterials 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.MBlockEntities
import ru.dbotthepony.mc.otm.registry.game.MBlocks 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 multiblock: ShapedMultiblock? = null
private var lastHeight = -1 private var lastHeight = -1
var batteryLevel = Decimal.ZERO var batteryLevel = Decimal.ZERO
private var cachedChargeEfficiency = Decimal.ONE 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<Block>? get() {
return multiblock?.blocks(FLYWHEEL_MATERIAL)?.reference2IntEntrySet()?.firstOrNull()
}
var currentLossPerTick: Decimal = Decimal.ZERO
private set
private inner class Storage : IMatteryEnergyStorage { private inner class Storage : IMatteryEnergyStorage {
override fun extractEnergy(howMuch: Decimal, simulate: Boolean): Decimal { override fun extractEnergy(howMuch: Decimal, simulate: Boolean): Decimal {
if (batteryLevel <= Decimal.ZERO) { if (batteryLevel <= Decimal.ZERO) {
@ -117,13 +136,19 @@ class FlywheelBatteryBlockEntity(blockPos: BlockPos, blockState: BlockState) : M
val material = FlywheelMaterials[entry.key]!! val material = FlywheelMaterials[entry.key]!!
energy.parent.maxBatteryLevel = material.storage * entry.intValue energy.parent.maxBatteryLevel = material.storage * entry.intValue
cachedChargeEfficiency = material.receiveEfficiency 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 { } else {
energy.parent.maxBatteryLevel = Decimal.ZERO 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 { companion object {
private val FLYWHEEL_MATERIAL = Any() private val FLYWHEEL_MATERIAL = Any()
private val outerRing = listOf( private val outerRing = listOf(

View File

@ -44,6 +44,42 @@ data class DockProperty(val left: Float = 0f, val top: Float = 0f, val right: Fl
val horizontal get() = left + right val horizontal get() = left + right
val vertical get() = top + bottom 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 { companion object {
val EMPTY = DockProperty() val EMPTY = DockProperty()
} }
@ -1391,8 +1427,8 @@ open class EditablePanel<out S : Screen>(
* Attempts to tightly fit dimensions to all children * Attempts to tightly fit dimensions to all children
*/ */
open fun sizeToContents() { open fun sizeToContents() {
if (visibleChildrenInternal.isEmpty() || visibleChildrenInternal.any { it.dock == Dock.FILL }) { if (visibleChildrenInternal.isEmpty()) {
// nothing to size against OR there is "fill" children // nothing to size against
return return
} }
@ -1407,16 +1443,7 @@ open class EditablePanel<out S : Screen>(
for (child in visibleChildrenInternal) { for (child in visibleChildrenInternal) {
when (child.dock) { when (child.dock) {
Dock.NONE -> { Dock.NONE, Dock.FILL -> {}
if (!child.ignoreWhenSizingToContents) {
width = maxOf(width, child.x + child.width)
height = maxOf(height, child.y + child.height)
}
}
Dock.FILL -> {
throw RuntimeException()
} // do nothing
Dock.LEFT, Dock.RIGHT -> { Dock.LEFT, Dock.RIGHT -> {
if (previousDock != 1) { if (previousDock != 1) {
@ -1454,6 +1481,13 @@ open class EditablePanel<out S : Screen>(
height = max(height, accumulatedHeight) 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.width = width + dockPadding.left + dockPadding.right
this.height = height + dockPadding.top + dockPadding.bottom this.height = height + dockPadding.top + dockPadding.bottom

View File

@ -16,7 +16,7 @@ open class BackgroundPanel<out S : Screen>(
height: Float = 10f, height: Float = 10f,
) : EditablePanel<S>(screen, parent, x, y, width, height) { ) : EditablePanel<S>(screen, parent, x, y, width, height) {
init { init {
dockPadding = DockProperty(3f, 3f, 3f, 3f) dockPadding = DEFAULT_PADDING
} }
var drawBackground = true var drawBackground = true
@ -33,6 +33,9 @@ open class BackgroundPanel<out S : Screen>(
} }
companion object { companion object {
private val DEFAULT_PADDING = DockProperty(3f, 3f, 3f, 3f)
private val BLOCK = DEFAULT_PADDING + 2f
fun <S : Screen> padded( fun <S : Screen> padded(
screen: S, screen: S,
parent: EditablePanel<*>?, parent: EditablePanel<*>?,
@ -42,6 +45,17 @@ open class BackgroundPanel<out S : Screen>(
height: Float = 10f, height: Float = 10f,
) = BackgroundPanel(screen, parent, x, y, width + 6f, height + 6f) ) = BackgroundPanel(screen, parent, x, y, width + 6f, height + 6f)
fun <S : Screen> 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 <S : Screen> paddedCenter( fun <S : Screen> paddedCenter(
screen: S, screen: S,
parent: EditablePanel<*>?, parent: EditablePanel<*>?,

View File

@ -1,10 +1,12 @@
package ru.dbotthepony.mc.otm.client.screen.tech package ru.dbotthepony.mc.otm.client.screen.tech
import net.minecraft.ChatFormatting
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import net.minecraft.world.entity.player.Inventory import net.minecraft.world.entity.player.Inventory
import ru.dbotthepony.mc.otm.block.entity.blackhole.BlackHoleGeneratorBlockEntity import ru.dbotthepony.mc.otm.block.entity.blackhole.BlackHoleGeneratorBlockEntity
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen 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.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.FramePanel
import ru.dbotthepony.mc.otm.client.screen.panels.Label import ru.dbotthepony.mc.otm.client.screen.panels.Label
import ru.dbotthepony.mc.otm.client.screen.panels.button.BooleanButtonPanel 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.TranslatableComponent
import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.menu.tech.BlackHoleGeneratorMenu import ru.dbotthepony.mc.otm.menu.tech.BlackHoleGeneratorMenu
import java.util.function.Supplier
class BlackHoleGeneratorScreen(menu: BlackHoleGeneratorMenu, inventory: Inventory, title: Component) : MatteryScreen<BlackHoleGeneratorMenu>(menu, inventory, title) { class BlackHoleGeneratorScreen(menu: BlackHoleGeneratorMenu, inventory: Inventory, title: Component) : MatteryScreen<BlackHoleGeneratorMenu>(menu, inventory, title) {
override fun makeMainFrame(): FramePanel<MatteryScreen<*>> { override fun makeMainFrame(): FramePanel<MatteryScreen<*>> {
val frame = FramePanel.padded(this, 240f, 130f, title) val frame = FramePanel.padded(this, 240f, 150f, title)
frame.behaveAsWindow() frame.behaveAsWindow()
frame.onClose { onClose() } frame.onClose { onClose() }
@ -32,6 +35,19 @@ class BlackHoleGeneratorScreen(menu: BlackHoleGeneratorMenu, inventory: Inventor
it.tooltips.add(TranslatableComponent("otm.gui.black_hole_generator.help3")) 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 energy = ProfiledPowerGaugePanel(this, frame, menu.energy)
val matter = ProfiledMatterGaugePanel(this, frame, menu.matter) val matter = ProfiledMatterGaugePanel(this, frame, menu.matter)

View File

@ -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<FlywheelBatteryMenu>(menu, inventory, title) {
override fun makeMainFrame(): FramePanel<MatteryScreen<*>> {
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<FlywheelBatteryScreen>(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
}
}

View File

@ -282,6 +282,10 @@ fun FriendlyByteBuf.writeBlockType(value: Block) {
writeType(BuiltInRegistries.BLOCK, value) writeType(BuiltInRegistries.BLOCK, value)
} }
fun FriendlyByteBuf.writeBlockState(value: BlockState) {
writeVarInt(Block.BLOCK_STATE_REGISTRY.getIdOrThrow(value))
}
fun FriendlyByteBuf.writeItemType(value: Item) { fun FriendlyByteBuf.writeItemType(value: Item) {
writeType(BuiltInRegistries.ITEM, value) writeType(BuiltInRegistries.ITEM, value)
} }
@ -307,6 +311,10 @@ fun FriendlyByteBuf.readBlockType(): Block {
return readType(BuiltInRegistries.BLOCK) return readType(BuiltInRegistries.BLOCK)
} }
fun FriendlyByteBuf.readBlockState(): BlockState {
return Block.BLOCK_STATE_REGISTRY.byIdOrThrow(readVarInt())
}
fun FriendlyByteBuf.readItemType(): Item { fun FriendlyByteBuf.readItemType(): Item {
return readType(BuiltInRegistries.ITEM) return readType(BuiltInRegistries.ITEM)
} }

View File

@ -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.input.EnumInputWithFeedback
import ru.dbotthepony.mc.otm.menu.widget.CombinedProfiledLevelGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.CombinedProfiledLevelGaugeWidget
import ru.dbotthepony.mc.otm.registry.game.MMenus import ru.dbotthepony.mc.otm.registry.game.MMenus
import java.util.function.BooleanSupplier
class BlackHoleGeneratorMenu( class BlackHoleGeneratorMenu(
p_38852_: Int, p_38852_: Int,
inventory: Inventory, inventory: Inventory,
tile: BlackHoleGeneratorBlockEntity? = null, tile: BlackHoleGeneratorBlockEntity? = null,
) : MatteryMenu(MMenus.BLACK_HOLE_GENERATOR, p_38852_, inventory, tile) { ) : 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 drawBuildingGuide = BooleanInputWithFeedback(this, tile?.let { it::drawBuildingGuide })
val energy = CombinedProfiledLevelGaugeWidget(this, tile?.energy) val energy = CombinedProfiledLevelGaugeWidget(this, tile?.energy)
val matter = CombinedProfiledLevelGaugeWidget(this, tile?.matter) val matter = CombinedProfiledLevelGaugeWidget(this, tile?.matter)

View File

@ -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()
}
}

View File

@ -74,6 +74,8 @@ fun FriendlyByteBuf.readByteList(): ByteArrayList {
} }
fun <S : ByteBuf, V> StreamCodec<S, V>.wrap(): MatteryStreamCodec<S, V> = MatteryStreamCodec.Wrapper(this) fun <S : ByteBuf, V> StreamCodec<S, V>.wrap(): MatteryStreamCodec<S, V> = MatteryStreamCodec.Wrapper(this)
@Deprecated("Redundant wrapping", level = DeprecationLevel.ERROR, replaceWith = ReplaceWith("this"))
fun <S : ByteBuf, V> MatteryStreamCodec<S, V>.wrap(): MatteryStreamCodec<S, V> = this
fun <S : ByteBuf, V> MatteryStreamCodec<S, V>.nullable(): MatteryStreamCodec<S, V?> = MatteryStreamCodec.Nullable(this) fun <S : ByteBuf, V> MatteryStreamCodec<S, V>.nullable(): MatteryStreamCodec<S, V?> = MatteryStreamCodec.Nullable(this)
fun <S : ByteBuf, V : Any> MatteryStreamCodec<S, V>.optional(): MatteryStreamCodec<S, Optional<V>> = MatteryStreamCodec.Optional(this) fun <S : ByteBuf, V : Any> MatteryStreamCodec<S, V>.optional(): MatteryStreamCodec<S, Optional<V>> = MatteryStreamCodec.Optional(this)

View File

@ -25,6 +25,76 @@ interface MatteryStreamCodec<in S : ByteBuf, V> : StreamCodec<@UnsafeVariance S,
override fun decode(stream: S): V override fun decode(stream: S): V
override fun encode(stream: S, value: V) override fun encode(stream: S, value: V)
class Of<in S : ByteBuf, V>(private val writer: S.(V) -> Unit, private val reader: S.() -> V) : MatteryStreamCodec<S, V> {
override fun decode(stream: S): V {
return reader(stream)
}
override fun encode(stream: S, value: V) {
return writer(stream, value)
}
}
abstract class AbstractPair<in S : ByteBuf, A, B, P>(private val first: MatteryStreamCodec<S, A>, private val second: MatteryStreamCodec<S, B>) : MatteryStreamCodec<S, P> {
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<in S : ByteBuf, A, B>(first: MatteryStreamCodec<S, A>, second: MatteryStreamCodec<S, B>) : AbstractPair<S, A, B, kotlin.Pair<A, B>>(first, second) {
override fun getFirst(value: kotlin.Pair<A, B>): A {
return value.first
}
override fun getSecond(value: kotlin.Pair<A, B>): B {
return value.second
}
override fun construct(a: A, b: B): kotlin.Pair<A, B> {
return a to b
}
}
class MapEntry<in S : ByteBuf, A, B>(first: MatteryStreamCodec<S, A>, second: MatteryStreamCodec<S, B>) : AbstractPair<S, A, B, Map.Entry<A, B>>(first, second) {
override fun getFirst(value: Map.Entry<A, B>): A {
return value.key
}
override fun getSecond(value: Map.Entry<A, B>): B {
return value.value
}
override fun construct(a: A, b: B): Map.Entry<A, B> {
return object : Map.Entry<A, B> {
override val key: A = a
override val value: B = b
}
}
}
class Wrapper<in S : ByteBuf, V>(parent: StreamCodec<S, V>) : MatteryStreamCodec<S, V>, StreamCodec<@UnsafeVariance S, V> by parent class Wrapper<in S : ByteBuf, V>(parent: StreamCodec<S, V>) : MatteryStreamCodec<S, V>, StreamCodec<@UnsafeVariance S, V> by parent
class Nullable<in S : ByteBuf, V>(val parent: MatteryStreamCodec<S, V>) : MatteryStreamCodec<S, V?> { class Nullable<in S : ByteBuf, V>(val parent: MatteryStreamCodec<S, V>) : MatteryStreamCodec<S, V?> {

View File

@ -6,27 +6,34 @@ import net.minecraft.network.FriendlyByteBuf
import net.minecraft.network.codec.ByteBufCodecs import net.minecraft.network.codec.ByteBufCodecs
import net.minecraft.network.codec.StreamCodec import net.minecraft.network.codec.StreamCodec
import net.minecraft.resources.ResourceLocation 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.kommons.math.RGBAColor
import ru.dbotthepony.mc.otm.core.math.readDecimal import ru.dbotthepony.mc.otm.core.math.readDecimal
import ru.dbotthepony.mc.otm.core.math.writeDecimal 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.readItemType
import ru.dbotthepony.mc.otm.core.writeBlockType
import ru.dbotthepony.mc.otm.core.writeItemType import ru.dbotthepony.mc.otm.core.writeItemType
import java.util.*
object StreamCodecs { object StreamCodecs {
val NOTHING: MatteryStreamCodec<ByteBuf, Nothing?> = StreamCodec.of<ByteBuf, Nothing?>({ _, _ -> }, { null }).wrap() val NOTHING: MatteryStreamCodec<ByteBuf, Nothing?> = MatteryStreamCodec.Of({}, { null })
val BYTE: MatteryStreamCodec<ByteBuf, Byte> = StreamCodec.of({ s, v -> s.writeByte(v.toInt()) }, ByteBuf::readByte).wrap() val BYTE: MatteryStreamCodec<ByteBuf, Byte> = MatteryStreamCodec.Of({ v -> writeByte(v.toInt()) }, ByteBuf::readByte)
val SHORT = ByteBufCodecs.SHORT.wrap() val SHORT: MatteryStreamCodec<ByteBuf, Short> = ByteBufCodecs.SHORT.wrap()
val INT = ByteBufCodecs.INT.wrap() val INT: MatteryStreamCodec<ByteBuf, Int> = ByteBufCodecs.INT.wrap()
val VAR_INT = ByteBufCodecs.VAR_INT.wrap() val VAR_INT: MatteryStreamCodec<ByteBuf, Int> = ByteBufCodecs.VAR_INT.wrap()
val LONG = StreamCodec.of(ByteBuf::writeLong, ByteBuf::readLong).wrap() val LONG = StreamCodec.of(ByteBuf::writeLong, ByteBuf::readLong).wrap()
val VAR_LONG = ByteBufCodecs.VAR_LONG.wrap() val VAR_LONG: MatteryStreamCodec<ByteBuf, Long> = ByteBufCodecs.VAR_LONG.wrap()
val DOUBLE = ByteBufCodecs.DOUBLE.wrap() val DOUBLE: MatteryStreamCodec<ByteBuf, Double> = ByteBufCodecs.DOUBLE.wrap()
val FLOAT = ByteBufCodecs.FLOAT.wrap() val FLOAT: MatteryStreamCodec<ByteBuf, Float> = ByteBufCodecs.FLOAT.wrap()
val BOOLEAN = ByteBufCodecs.BOOL.wrap() val BOOLEAN: MatteryStreamCodec<ByteBuf, Boolean> = ByteBufCodecs.BOOL.wrap()
val STRING = ByteBufCodecs.STRING_UTF8.wrap() val STRING: MatteryStreamCodec<ByteBuf, String> = ByteBufCodecs.STRING_UTF8.wrap()
val UUID = UUIDUtil.STREAM_CODEC.wrap() val UUID: MatteryStreamCodec<ByteBuf, UUID> = UUIDUtil.STREAM_CODEC.wrap()
val RESOURCE_LOCATION = ResourceLocation.STREAM_CODEC.wrap() val RESOURCE_LOCATION = ResourceLocation.STREAM_CODEC.wrap()
val BLOCK_STATE: MatteryStreamCodec<ByteBuf, BlockState> = ByteBufCodecs.idMapper(Block.BLOCK_STATE_REGISTRY).wrap()
val BLOCK_TYPE = MatteryStreamCodec.Of(FriendlyByteBuf::writeBlockType, FriendlyByteBuf::readBlockType)
val RGBA: MatteryStreamCodec<ByteBuf, RGBAColor> = StreamCodec.of<ByteBuf, RGBAColor>( val RGBA: MatteryStreamCodec<ByteBuf, RGBAColor> = StreamCodec.of<ByteBuf, RGBAColor>(
{ s, v -> s.writeFloat(v.red); s.writeFloat(v.green); s.writeFloat(v.blue); s.writeFloat(v.alpha) }, { s, v -> s.writeFloat(v.red); s.writeFloat(v.green); s.writeFloat(v.blue); s.writeFloat(v.alpha) },

View File

@ -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.EnergyHatchScreen
import ru.dbotthepony.mc.otm.client.screen.tech.EnergyServoScreen 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.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.ItemHatchScreen
import ru.dbotthepony.mc.otm.client.screen.tech.MatterHatchScreen import ru.dbotthepony.mc.otm.client.screen.tech.MatterHatchScreen
import ru.dbotthepony.mc.otm.menu.decorative.CargoCrateMenu 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.EnergyHatchMenu
import ru.dbotthepony.mc.otm.menu.tech.EnergyServoMenu import ru.dbotthepony.mc.otm.menu.tech.EnergyServoMenu
import ru.dbotthepony.mc.otm.menu.tech.EssenceStorageMenu 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.ItemHatchMenu
import ru.dbotthepony.mc.otm.menu.tech.MatterHatchMenu import ru.dbotthepony.mc.otm.menu.tech.MatterHatchMenu
import ru.dbotthepony.mc.otm.menu.tech.PlatePressMenu 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_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 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 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_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) } 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_INPUT_HATCH, ::EnergyHatchScreen)
event.register(ENERGY_OUTPUT_HATCH, ::EnergyHatchScreen) event.register(ENERGY_OUTPUT_HATCH, ::EnergyHatchScreen)
event.register(BLACK_HOLE_GENERATOR, ::BlackHoleGeneratorScreen) event.register(BLACK_HOLE_GENERATOR, ::BlackHoleGeneratorScreen)
event.register(FLYWHEEL_BATTERY, ::FlywheelBatteryScreen)
} }
} }