Migrate player menu inputs to PlayerInput

This commit is contained in:
DBotThePony 2023-01-26 21:08:53 +07:00
parent fc1623b478
commit 34d14ec9c6
Signed by: DBot
GPG Key ID: DCC23B5715498507
16 changed files with 181 additions and 337 deletions

View File

@ -82,7 +82,7 @@ class EnergyCounterScreen(menu: EnergyCounterMenu, inventory: Inventory, title:
val button = ButtonPanel(this, frame, 0f, 0f, 0f, 20f, TranslatableComponent("block.overdrive_that_matters.energy_counter.switch")) val button = ButtonPanel(this, frame, 0f, 0f, 0f, 20f, TranslatableComponent("block.overdrive_that_matters.energy_counter.switch"))
button.dock = Dock.TOP button.dock = Dock.TOP
button.setDockMargin(4f, 0f, 4f, 0f) button.setDockMargin(4f, 0f, 4f, 0f)
button.bind { menu.switchDirection.userInput(minecraft?.player) } button.bind { menu.switchDirection.input(null) }
} }
val infoPanels = frame.fetchChildren() val infoPanels = frame.fetchChildren()
@ -91,7 +91,7 @@ class EnergyCounterScreen(menu: EnergyCounterMenu, inventory: Inventory, title:
label.dock = Dock.TOP label.dock = Dock.TOP
label.setDockMargin(4f, 0f, 0f, 0f) label.setDockMargin(4f, 0f, 0f, 0f)
val inputPanel = NumberInputPanel(this, frame, menu.maxIO) val inputPanel = NetworkNumberInputPanel(this, frame, widget = menu.maxIOInput, networkValue = menu::maxIO)
inputPanel.dock = Dock.TOP inputPanel.dock = Dock.TOP
inputPanel.setDockMargin(4f, 0f, 4f, 0f) inputPanel.setDockMargin(4f, 0f, 4f, 0f)

View File

@ -4,25 +4,50 @@ import net.minecraft.client.gui.screens.Screen
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.core.TextComponent import ru.dbotthepony.mc.otm.core.TextComponent
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen import ru.dbotthepony.mc.otm.menu.MatteryMenu
import ru.dbotthepony.mc.otm.menu.widget.NumberPlayerInputWidget
import java.math.BigDecimal import java.math.BigDecimal
import java.util.function.BooleanSupplier
open class NumberInputPanel<out S : Screen> @JvmOverloads constructor( open class NetworkNumberInputPanel<out S : Screen> @JvmOverloads constructor(
screen: S, screen: S,
parent: EditablePanel<*>?, parent: EditablePanel<*>?,
val inputWidget: NumberPlayerInputWidget, val networkValue: () -> BigDecimal,
val callback: (BigDecimal) -> Unit,
val isAvailable: BooleanSupplier = BooleanSupplier { true },
x: Float = 0f, x: Float = 0f,
y: Float = 0f, y: Float = 0f,
width: Float = 0f, width: Float = 0f,
height: Float = 20f, height: Float = 20f,
defaultText: Component = TextComponent("") defaultText: Component = TextComponent("")
) : EditBoxPanel<S>(screen, parent, x, y, width, height, defaultText) { ) : EditBoxPanel<S>(screen, parent, x, y, width, height, defaultText) {
constructor(
screen: S,
parent: EditablePanel<*>?,
widget: MatteryMenu.PlayerInput<BigDecimal>,
networkValue: () -> BigDecimal,
x: Float = 0f,
y: Float = 0f,
width: Float = 0f,
height: Float = 20f,
defaultText: Component = TextComponent("")
) : this(
screen = screen,
parent = parent,
callback = widget::input,
isAvailable = { widget.allowSpectators || minecraft.player?.isSpectator != true },
networkValue = networkValue,
x = x,
y = y,
width = width,
height = height,
defaultText = defaultText,
)
protected var nextUpdateFromServer = 0L protected var nextUpdateFromServer = 0L
protected var inputStr = "" protected var inputStr = ""
override fun mouseClickedInner(x: Double, y: Double, button: Int): Boolean { override fun mouseClickedInner(x: Double, y: Double, button: Int): Boolean {
if (inputWidget.ignoreSpectators && minecraft.player?.isSpectator == true) { if (!isAvailable.asBoolean) {
return true return true
} }
@ -33,7 +58,7 @@ open class NumberInputPanel<out S : Screen> @JvmOverloads constructor(
super.tick() super.tick()
if (isFocused) { if (isFocused) {
if (inputWidget.ignoreSpectators && minecraft.player?.isSpectator == true) { if (!isAvailable.asBoolean) {
killFocus() killFocus()
return return
} }
@ -42,14 +67,14 @@ open class NumberInputPanel<out S : Screen> @JvmOverloads constructor(
} }
if (nextUpdateFromServer < System.currentTimeMillis()) { if (nextUpdateFromServer < System.currentTimeMillis()) {
getOrCreateWidget().value = inputWidget.value.toPlainString() getOrCreateWidget().value = networkValue.invoke().toPlainString()
inputStr = getOrCreateWidget().value inputStr = getOrCreateWidget().value
} else if (!inputWidget.ignoreSpectators || minecraft.player?.isSpectator != true) { } else if (isAvailable.asBoolean) {
if (inputStr != getOrCreateWidget().value) { if (inputStr != getOrCreateWidget().value) {
inputStr = getOrCreateWidget().value inputStr = getOrCreateWidget().value
try { try {
inputWidget.userInput(BigDecimal(inputStr), minecraft.player) callback.invoke(BigDecimal(inputStr))
} catch (_: Throwable) { } } catch (_: Throwable) { }
} }
} }

View File

@ -3,12 +3,12 @@ package ru.dbotthepony.mc.otm.client.screen.panels.buttons
import net.minecraft.client.gui.screens.Screen import net.minecraft.client.gui.screens.Screen
import ru.dbotthepony.mc.otm.client.minecraft import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
import ru.dbotthepony.mc.otm.menu.widget.BooleanPlayerInputWidget import ru.dbotthepony.mc.otm.menu.widget.NetworkedBooleanInput
open class CheckBoxInputPanel<out S : Screen> @JvmOverloads constructor( open class CheckBoxInputPanel<out S : Screen> @JvmOverloads constructor(
screen: S, screen: S,
parent: EditablePanel<*>?, parent: EditablePanel<*>?,
val widget: BooleanPlayerInputWidget, val widget: NetworkedBooleanInput,
x: Float = 0f, x: Float = 0f,
y: Float = 0f, y: Float = 0f,
width: Float = REGULAR_DIMENSIONS + 120f, width: Float = REGULAR_DIMENSIONS + 120f,
@ -19,7 +19,7 @@ open class CheckBoxInputPanel<out S : Screen> @JvmOverloads constructor(
set(value) {} set(value) {}
override var isDisabled: Boolean override var isDisabled: Boolean
get() = !widget.ignoreSpectators || minecraft.player?.isSpectator == true get() = widget.input.allowSpectators || minecraft.player?.isSpectator == true
set(value) {} set(value) {}
override fun onClick() { override fun onClick() {

View File

@ -4,12 +4,12 @@ import net.minecraft.client.gui.screens.Screen
import net.minecraft.network.chat.Component import net.minecraft.network.chat.Component
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
import ru.dbotthepony.mc.otm.client.screen.panels.Label import ru.dbotthepony.mc.otm.client.screen.panels.Label
import ru.dbotthepony.mc.otm.menu.widget.BooleanPlayerInputWidget import ru.dbotthepony.mc.otm.menu.widget.NetworkedBooleanInput
open class CheckBoxLabelInputPanel<out S : Screen> @JvmOverloads constructor( open class CheckBoxLabelInputPanel<out S : Screen> @JvmOverloads constructor(
screen: S, screen: S,
parent: EditablePanel<*>?, parent: EditablePanel<*>?,
widget: BooleanPlayerInputWidget, widget: NetworkedBooleanInput,
text: Component, text: Component,
x: Float = 0f, x: Float = 0f,
y: Float = 0f, y: Float = 0f,

View File

@ -15,7 +15,7 @@ import ru.dbotthepony.mc.otm.core.ifPresentK
import ru.dbotthepony.mc.otm.item.PortableCondensationDriveItem import ru.dbotthepony.mc.otm.item.PortableCondensationDriveItem
import ru.dbotthepony.mc.otm.menu.data.INetworkedItemViewProvider import ru.dbotthepony.mc.otm.menu.data.INetworkedItemViewProvider
import ru.dbotthepony.mc.otm.menu.data.NetworkedItemView import ru.dbotthepony.mc.otm.menu.data.NetworkedItemView
import ru.dbotthepony.mc.otm.menu.widget.BooleanPlayerInputWidget import ru.dbotthepony.mc.otm.menu.widget.NetworkedBooleanInput
import ru.dbotthepony.mc.otm.registry.MMenus import ru.dbotthepony.mc.otm.registry.MMenus
import ru.dbotthepony.mc.otm.storage.ITEM_STORAGE import ru.dbotthepony.mc.otm.storage.ITEM_STORAGE
import ru.dbotthepony.mc.otm.storage.ItemStackWrapper import ru.dbotthepony.mc.otm.storage.ItemStackWrapper
@ -68,15 +68,15 @@ class DriveViewerMenu @JvmOverloads constructor(
val driveFilterSlots = addFilterSlots(driveFilter) val driveFilterSlots = addFilterSlots(driveFilter)
val isWhitelist = BooleanPlayerInputWidget(this) val isWhitelist = NetworkedBooleanInput(this)
val matchTag = BooleanPlayerInputWidget(this) val matchTag = NetworkedBooleanInput(this)
val matchNBT = BooleanPlayerInputWidget(this) val matchNBT = NetworkedBooleanInput(this)
init { init {
if (tile == null) { if (tile == null) {
isWhitelist.asClient() isWhitelist.isClient = true
matchTag.asClient() matchTag.isClient = true
matchNBT.asClient() matchNBT.isClient = true
} }
} }
@ -109,24 +109,24 @@ class DriveViewerMenu @JvmOverloads constructor(
driveFilter.copyFrom(filter) driveFilter.copyFrom(filter)
driveFilter.isLocked = false driveFilter.isLocked = false
isWhitelist.withProperty(driveFilter::isWhitelist) isWhitelist.with(driveFilter::isWhitelist)
matchTag.withProperty(driveFilter::matchTag) matchTag.with(driveFilter::matchTag)
matchNBT.withProperty(driveFilter::matchNBT) matchNBT.with(driveFilter::matchNBT)
} else { } else {
driveFilter.clear() driveFilter.clear()
driveFilter.isLocked = true driveFilter.isLocked = true
isWhitelist.withoutAnything() isWhitelist.clear()
matchTag.withoutAnything() matchTag.clear()
matchNBT.withoutAnything() matchNBT.clear()
} }
} else { } else {
driveFilter.clear() driveFilter.clear()
driveFilter.isLocked = true driveFilter.isLocked = true
isWhitelist.withoutAnything() isWhitelist.clear()
matchTag.withoutAnything() matchTag.clear()
matchNBT.withoutAnything() matchNBT.clear()
} }
} }
@ -170,4 +170,4 @@ class DriveViewerMenu @JvmOverloads constructor(
slot.setChanged() slot.setChanged()
return copy return copy
} }
} }

View File

@ -8,8 +8,6 @@ import net.minecraft.world.level.block.Block
import ru.dbotthepony.mc.otm.block.tech.EnergyCounterBlock import ru.dbotthepony.mc.otm.block.tech.EnergyCounterBlock
import ru.dbotthepony.mc.otm.block.entity.tech.EnergyCounterBlockEntity import ru.dbotthepony.mc.otm.block.entity.tech.EnergyCounterBlockEntity
import ru.dbotthepony.mc.otm.core.math.Decimal import ru.dbotthepony.mc.otm.core.math.Decimal
import ru.dbotthepony.mc.otm.menu.widget.NumberPlayerInputWidget
import ru.dbotthepony.mc.otm.menu.widget.OneWayPlayerInputWidget
import ru.dbotthepony.mc.otm.registry.MMenus import ru.dbotthepony.mc.otm.registry.MMenus
import java.math.BigDecimal import java.math.BigDecimal
@ -22,36 +20,28 @@ class EnergyCounterMenu @JvmOverloads constructor(
var average by mSynchronizer.fraction() var average by mSynchronizer.fraction()
var last20Ticks by mSynchronizer.fraction() var last20Ticks by mSynchronizer.fraction()
var lastTick by mSynchronizer.fraction() var lastTick by mSynchronizer.fraction()
var maxIO by mSynchronizer.bigDecimal()
val switchDirection = oneWayInput {
if (tile is EnergyCounterBlockEntity)
tile.level?.setBlock(tile.blockPos, tile.blockState.setValue(EnergyCounterBlock.INPUT_DIRECTION, tile.blockState.getValue(EnergyCounterBlock.INPUT_DIRECTION).opposite), Block.UPDATE_ALL)
}
val switchDirection: OneWayPlayerInputWidget
var inputDirection by mSynchronizer.enum(Direction::class.java) var inputDirection by mSynchronizer.enum(Direction::class.java)
val maxIO = NumberPlayerInputWidget(this) val maxIOInput = bigDecimalInput {
if (tile is EnergyCounterBlockEntity) {
// TODO: Graph and proper networking for it if (it.signum() < 0) {
private var ticksPassed = 0 tile.ioLimit = null
} else {
init { tile.ioLimit = Decimal(it)
if (tile == null) {
switchDirection = OneWayPlayerInputWidget(this)
maxIO.asClient()
} else {
switchDirection = OneWayPlayerInputWidget(this) {
tile.level?.setBlock(tile.blockPos, tile.blockState.setValue(EnergyCounterBlock.INPUT_DIRECTION, tile.blockState.getValue(EnergyCounterBlock.INPUT_DIRECTION).opposite), Block.UPDATE_ALL)
}
maxIO.withSupplier {
return@withSupplier if (tile.ioLimit == null) MINUS_ONE else tile.ioLimit!!.toBigDecmial()
}.withConsumer {
if (it.signum() < 0) {
tile.ioLimit = null
} else {
tile.ioLimit = Decimal(it)
}
} }
} }
} }
// TODO: Graph and proper networking for it
private var ticksPassed = 0
override fun broadcastChanges() { override fun broadcastChanges() {
if (tile is EnergyCounterBlockEntity) { if (tile is EnergyCounterBlockEntity) {
passed = tile.passed passed = tile.passed
@ -64,6 +54,8 @@ class EnergyCounterMenu @JvmOverloads constructor(
ticksPassed = (ticksPassed + 1) % 20 ticksPassed = (ticksPassed + 1) % 20
inputDirection = tile.blockState.getValue(EnergyCounterBlock.INPUT_DIRECTION) inputDirection = tile.blockState.getValue(EnergyCounterBlock.INPUT_DIRECTION)
maxIO = tile.ioLimit?.toBigDecmial() ?: -BigDecimal.ONE
} }
super.broadcastChanges() super.broadcastChanges()

View File

@ -8,7 +8,7 @@ import ru.dbotthepony.mc.otm.block.entity.matter.MatterBottlerBlockEntity
import ru.dbotthepony.mc.otm.capability.MatteryCapability import ru.dbotthepony.mc.otm.capability.MatteryCapability
import ru.dbotthepony.mc.otm.capability.matter.canExtractMatter import ru.dbotthepony.mc.otm.capability.matter.canExtractMatter
import ru.dbotthepony.mc.otm.capability.matter.canReceiveMatter import ru.dbotthepony.mc.otm.capability.matter.canReceiveMatter
import ru.dbotthepony.mc.otm.menu.widget.BooleanPlayerInputWidget import ru.dbotthepony.mc.otm.menu.widget.NetworkedBooleanInput
import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.LevelGaugeWidget
import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget import ru.dbotthepony.mc.otm.menu.widget.ProgressGaugeWidget
import ru.dbotthepony.mc.otm.core.orNull import ru.dbotthepony.mc.otm.core.orNull
@ -21,7 +21,7 @@ class MatterBottlerMenu @JvmOverloads constructor(
) : MatteryPoweredMenu( ) : MatteryPoweredMenu(
MMenus.MATTER_BOTTLER, p_38852_, inventory, tile MMenus.MATTER_BOTTLER, p_38852_, inventory, tile
) { ) {
val workFlow: BooleanPlayerInputWidget val workFlow: NetworkedBooleanInput
val progressWidget: ProgressGaugeWidget val progressWidget: ProgressGaugeWidget
val matterWidget: LevelGaugeWidget val matterWidget: LevelGaugeWidget
@ -34,11 +34,11 @@ class MatterBottlerMenu @JvmOverloads constructor(
if (tile == null) { if (tile == null) {
progressWidget = ProgressGaugeWidget(this) progressWidget = ProgressGaugeWidget(this)
matterWidget = LevelGaugeWidget(this) matterWidget = LevelGaugeWidget(this)
workFlow = BooleanPlayerInputWidget(this).asClient() workFlow = NetworkedBooleanInput(this).asClient()
} else { } else {
progressWidget = ProgressGaugeWidget(this) { tile.getWorkProgress() } progressWidget = ProgressGaugeWidget(this) { tile.getWorkProgress() }
matterWidget = LevelGaugeWidget(this, tile.matter) matterWidget = LevelGaugeWidget(this, tile.matter)
workFlow = BooleanPlayerInputWidget(this, tile::isBottling) workFlow = NetworkedBooleanInput(this, tile::isBottling)
} }
storageSlots = ImmutableList(6) { index -> storageSlots = ImmutableList(6) { index ->
@ -58,9 +58,4 @@ class MatterBottlerMenu @JvmOverloads constructor(
storageSlots.forEach(this::addSlot) storageSlots.forEach(this::addSlot)
addInventorySlots() addInventorySlots()
} }
override fun broadcastChanges() {
super.broadcastChanges()
workFlow.value = (tile as MatterBottlerBlockEntity).isBottling
}
} }

View File

@ -22,7 +22,10 @@ import ru.dbotthepony.mc.otm.compat.cos.cosmeticArmorSlots
import ru.dbotthepony.mc.otm.compat.curios.isCurioSlot import ru.dbotthepony.mc.otm.compat.curios.isCurioSlot
import ru.dbotthepony.mc.otm.container.ItemFilter import ru.dbotthepony.mc.otm.container.ItemFilter
import ru.dbotthepony.mc.otm.container.ItemFilterNetworkSlot import ru.dbotthepony.mc.otm.container.ItemFilterNetworkSlot
import ru.dbotthepony.mc.otm.core.util.BigDecimalValueCodec
import ru.dbotthepony.mc.otm.core.util.BooleanValueCodec
import ru.dbotthepony.mc.otm.core.util.IStreamCodec import ru.dbotthepony.mc.otm.core.util.IStreamCodec
import ru.dbotthepony.mc.otm.core.util.NullValueCodec
import ru.dbotthepony.mc.otm.menu.widget.AbstractWidget import ru.dbotthepony.mc.otm.menu.widget.AbstractWidget
import ru.dbotthepony.mc.otm.network.FieldSynchronizer import ru.dbotthepony.mc.otm.network.FieldSynchronizer
import ru.dbotthepony.mc.otm.network.MatteryPacket import ru.dbotthepony.mc.otm.network.MatteryPacket
@ -33,6 +36,7 @@ import ru.dbotthepony.mc.otm.network.packetHandled
import ru.dbotthepony.mc.otm.network.sender import ru.dbotthepony.mc.otm.network.sender
import java.io.DataInputStream import java.io.DataInputStream
import java.io.DataOutputStream import java.io.DataOutputStream
import java.math.BigDecimal
import java.util.* import java.util.*
import java.util.function.Supplier import java.util.function.Supplier
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
@ -43,6 +47,9 @@ abstract class MatteryMenu @JvmOverloads protected constructor(
val inventory: Inventory, val inventory: Inventory,
val tile: BlockEntity? = null val tile: BlockEntity? = null
) : AbstractContainerMenu(menuType, containerId) { ) : AbstractContainerMenu(menuType, containerId) {
/**
* Server->Client field synchronizer
*/
val mSynchronizer = FieldSynchronizer() val mSynchronizer = FieldSynchronizer()
val ply: Player get() = inventory.player val ply: Player get() = inventory.player
@ -80,8 +87,12 @@ abstract class MatteryMenu @JvmOverloads protected constructor(
} }
} }
inner class PlayerInput<V>(val codec: IStreamCodec<V>, val allowSpectators: Boolean = false, val handler: (V) -> Unit) { /**
* Client->Server handler
*/
inner class PlayerInput<V>(val codec: IStreamCodec<V>, allowSpectators: Boolean = false, val handler: (V) -> Unit) {
val id = playerInputs.size val id = playerInputs.size
var allowSpectators by mSynchronizer.bool(allowSpectators)
init { init {
playerInputs.add(this) playerInputs.add(this)
@ -93,11 +104,26 @@ abstract class MatteryMenu @JvmOverloads protected constructor(
MenuNetworkChannel.sendToServer(PlayerInputPacket(containerId, id, stream.array.copyOfRange(0, stream.length))) MenuNetworkChannel.sendToServer(PlayerInputPacket(containerId, id, stream.array.copyOfRange(0, stream.length)))
} }
fun checkedInput(value: V, player: Player?) {
if (allowSpectators || player?.isSpectator == false) {
return input(value)
}
}
internal fun invoke(value: Any?) { internal fun invoke(value: Any?) {
handler.invoke(value as V) handler.invoke(value as V)
} }
} }
fun oneWayInput(allowSpectators: Boolean = false, handler: () -> Unit): PlayerInput<Nothing?> {
return PlayerInput(NullValueCodec, allowSpectators) {
handler.invoke()
}
}
fun bigDecimalInput(allowSpectators: Boolean = false, handler: (BigDecimal) -> Unit) = PlayerInput(BigDecimalValueCodec, allowSpectators, handler)
fun booleanInput(allowSpectators: Boolean = false, handler: (Boolean) -> Unit) = PlayerInput(BooleanValueCodec, allowSpectators, handler)
/** /**
* inventory + exosuit + hotbar (in this order) * inventory + exosuit + hotbar (in this order)
*/ */

View File

@ -4,7 +4,7 @@ import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.inventory.Slot import net.minecraft.world.inventory.Slot
import ru.dbotthepony.mc.otm.block.entity.storage.StorageBusBlockEntity import ru.dbotthepony.mc.otm.block.entity.storage.StorageBusBlockEntity
import ru.dbotthepony.mc.otm.container.ItemFilterNetworkSlot import ru.dbotthepony.mc.otm.container.ItemFilterNetworkSlot
import ru.dbotthepony.mc.otm.menu.widget.BooleanPlayerInputWidget import ru.dbotthepony.mc.otm.menu.widget.NetworkedBooleanInput
import ru.dbotthepony.mc.otm.registry.MMenus import ru.dbotthepony.mc.otm.registry.MMenus
class StorageBusMenu @JvmOverloads constructor( class StorageBusMenu @JvmOverloads constructor(
@ -15,15 +15,15 @@ class StorageBusMenu @JvmOverloads constructor(
MMenus.STORAGE_BUS, p_38852_, inventory, tile MMenus.STORAGE_BUS, p_38852_, inventory, tile
) { ) {
val busFilterSlots: List<ItemFilterNetworkSlot> val busFilterSlots: List<ItemFilterNetworkSlot>
val busFilterState: BooleanPlayerInputWidget val busFilterState: NetworkedBooleanInput
init { init {
if (tile != null) { if (tile != null) {
busFilterSlots = addFilterSlots(tile.filter) busFilterSlots = addFilterSlots(tile.filter)
busFilterState = BooleanPlayerInputWidget(this, tile.filter::isWhitelist) busFilterState = NetworkedBooleanInput(this, tile.filter::isWhitelist)
} else { } else {
busFilterSlots = addFilterSlots(StorageBusBlockEntity.MAX_FILTERS) busFilterSlots = addFilterSlots(StorageBusBlockEntity.MAX_FILTERS)
busFilterState = BooleanPlayerInputWidget(this).asClient() busFilterState = NetworkedBooleanInput(this).asClient()
} }
addInventorySlots() addInventorySlots()

View File

@ -4,7 +4,7 @@ import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.inventory.Slot import net.minecraft.world.inventory.Slot
import ru.dbotthepony.mc.otm.block.entity.storage.StorageExporterBlockEntity import ru.dbotthepony.mc.otm.block.entity.storage.StorageExporterBlockEntity
import ru.dbotthepony.mc.otm.container.ItemFilterNetworkSlot import ru.dbotthepony.mc.otm.container.ItemFilterNetworkSlot
import ru.dbotthepony.mc.otm.menu.widget.BooleanPlayerInputWidget import ru.dbotthepony.mc.otm.menu.widget.NetworkedBooleanInput
import ru.dbotthepony.mc.otm.registry.MMenus import ru.dbotthepony.mc.otm.registry.MMenus
class StorageExporterMenu @JvmOverloads constructor( class StorageExporterMenu @JvmOverloads constructor(
@ -15,15 +15,15 @@ class StorageExporterMenu @JvmOverloads constructor(
MMenus.STORAGE_EXPORTER, p_38852_, inventory, tile MMenus.STORAGE_EXPORTER, p_38852_, inventory, tile
) { ) {
val busFilterSlots: List<ItemFilterNetworkSlot> val busFilterSlots: List<ItemFilterNetworkSlot>
val busFilterState: BooleanPlayerInputWidget val busFilterState: NetworkedBooleanInput
init { init {
if (tile != null) { if (tile != null) {
busFilterSlots = addFilterSlots(tile.filter) busFilterSlots = addFilterSlots(tile.filter)
busFilterState = BooleanPlayerInputWidget(this, tile.filter::isWhitelist) busFilterState = NetworkedBooleanInput(this, tile.filter::isWhitelist)
} else { } else {
busFilterSlots = addFilterSlots(StorageExporterBlockEntity.MAX_FILTERS) busFilterSlots = addFilterSlots(StorageExporterBlockEntity.MAX_FILTERS)
busFilterState = BooleanPlayerInputWidget(this).asClient() busFilterState = NetworkedBooleanInput(this).asClient()
} }
addInventorySlots() addInventorySlots()

View File

@ -4,7 +4,7 @@ import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.inventory.Slot import net.minecraft.world.inventory.Slot
import ru.dbotthepony.mc.otm.block.entity.storage.StorageImporterBlockEntity import ru.dbotthepony.mc.otm.block.entity.storage.StorageImporterBlockEntity
import ru.dbotthepony.mc.otm.container.ItemFilterNetworkSlot import ru.dbotthepony.mc.otm.container.ItemFilterNetworkSlot
import ru.dbotthepony.mc.otm.menu.widget.BooleanPlayerInputWidget import ru.dbotthepony.mc.otm.menu.widget.NetworkedBooleanInput
import ru.dbotthepony.mc.otm.registry.MMenus import ru.dbotthepony.mc.otm.registry.MMenus
class StorageImporterMenu @JvmOverloads constructor( class StorageImporterMenu @JvmOverloads constructor(
@ -15,15 +15,15 @@ class StorageImporterMenu @JvmOverloads constructor(
MMenus.STORAGE_IMPORTER, p_38852_, inventory, tile MMenus.STORAGE_IMPORTER, p_38852_, inventory, tile
) { ) {
val busFilterSlots: List<ItemFilterNetworkSlot> val busFilterSlots: List<ItemFilterNetworkSlot>
val busFilterState: BooleanPlayerInputWidget val busFilterState: NetworkedBooleanInput
init { init {
if (tile != null) { if (tile != null) {
busFilterSlots = addFilterSlots(tile.filter) busFilterSlots = addFilterSlots(tile.filter)
busFilterState = BooleanPlayerInputWidget(this, tile.filter::isWhitelist) busFilterState = NetworkedBooleanInput(this, tile.filter::isWhitelist)
} else { } else {
busFilterSlots = addFilterSlots(StorageImporterBlockEntity.MAX_FILTERS) busFilterSlots = addFilterSlots(StorageImporterBlockEntity.MAX_FILTERS)
busFilterState = BooleanPlayerInputWidget(this).asClient() busFilterState = NetworkedBooleanInput(this).asClient()
} }
addInventorySlots() addInventorySlots()

View File

@ -1,101 +0,0 @@
package ru.dbotthepony.mc.otm.menu.widget
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.world.entity.player.Player
import net.minecraftforge.network.NetworkEvent
import ru.dbotthepony.mc.otm.menu.MatteryMenu
import ru.dbotthepony.mc.otm.network.MatteryPacket
import ru.dbotthepony.mc.otm.network.MenuNetworkChannel
import ru.dbotthepony.mc.otm.network.sender
import java.util.function.Supplier
import kotlin.reflect.KMutableProperty0
class BooleanPlayerInputPacket(val id: Int, val value: Boolean) : MatteryPacket {
override fun play(context: Supplier<NetworkEvent.Context>) {
context.get().packetHandled = true
context.get().enqueueWork {
((context.get().sender?.containerMenu as? MatteryMenu)?.getWidget(id) as? BooleanPlayerInputWidget)?.userInput(value, context.sender!!)
}
}
override fun write(buff: FriendlyByteBuf) {
buff.writeInt(id)
buff.writeBoolean(value)
}
companion object {
fun read(buff: FriendlyByteBuf): BooleanPlayerInputPacket {
return BooleanPlayerInputPacket(buff.readInt(), buff.readBoolean())
}
}
}
class BooleanPlayerInputWidget(menu: MatteryMenu) : AbstractWidget(menu) {
var value by menu.mSynchronizer.bool()
var ignoreSpectators by menu.mSynchronizer.bool(true)
constructor(menu: MatteryMenu, state: KMutableProperty0<Boolean>) : this(menu) {
withClicker { state.set(it) }
withSupplier { state.get() }
}
var supplier: (() -> Boolean)? = null
var clicker: ((Boolean) -> Unit)? = null
fun withSupplier(func: () -> Boolean): BooleanPlayerInputWidget {
supplier = func
return this
}
fun withClicker(func: (Boolean) -> Unit): BooleanPlayerInputWidget {
clicker = func
return this
}
fun withProperty(state: KMutableProperty0<Boolean>): BooleanPlayerInputWidget {
withClicker { state.set(it) }
withSupplier { state.get() }
return this
}
fun withoutAnything(): BooleanPlayerInputWidget {
supplier = null
clicker = null
return this
}
fun asClient(): BooleanPlayerInputWidget {
supplier = null
clicker = {
MenuNetworkChannel.sendToServer(BooleanPlayerInputPacket(slotID, it))
}
return this
}
fun userInput(newValue: Boolean, ply: Player? = null) {
if (ply?.isSpectator == true && ignoreSpectators) {
return
}
val clicker = clicker
if (clicker != null) {
clicker.invoke(newValue)
updateServer()
}
}
fun switchValue(ply: Player? = null) {
userInput(!value, ply)
}
override fun updateServer() {
val supplier = supplier
if (supplier != null) {
value = supplier.invoke()
}
}
}

View File

@ -0,0 +1,60 @@
package ru.dbotthepony.mc.otm.menu.widget
import net.minecraft.world.entity.player.Player
import ru.dbotthepony.mc.otm.menu.MatteryMenu
import kotlin.reflect.KMutableProperty0
class NetworkedBooleanInput(menu: MatteryMenu) {
val input = menu.booleanInput { consumer?.invoke(it) }
val value by menu.mSynchronizer.bool(getter = { supplier?.invoke() ?: false })
constructor(menu: MatteryMenu, state: KMutableProperty0<Boolean>) : this(menu) {
with(state)
}
var isClient = false
fun asClient(): NetworkedBooleanInput {
isClient = true
supplier = null
consumer = null
return this
}
var supplier: (() -> Boolean)? = null
var consumer: ((Boolean) -> Unit)? = null
fun withSupplier(func: () -> Boolean): NetworkedBooleanInput {
supplier = func
return this
}
fun withConsumer(func: (Boolean) -> Unit): NetworkedBooleanInput {
consumer = func
return this
}
fun with(state: KMutableProperty0<Boolean>): NetworkedBooleanInput {
withConsumer { state.set(it) }
withSupplier { state.get() }
return this
}
fun clear(): NetworkedBooleanInput {
supplier = null
consumer = null
return this
}
fun userInput(newValue: Boolean, ply: Player? = null) {
if (isClient) {
input.checkedInput(newValue, ply)
} else {
consumer?.invoke(newValue)
}
}
fun switchValue(ply: Player? = null) {
userInput(!value, ply)
}
}

View File

@ -1,92 +0,0 @@
package ru.dbotthepony.mc.otm.menu.widget
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.world.entity.player.Player
import net.minecraftforge.network.NetworkEvent
import ru.dbotthepony.mc.otm.menu.MatteryMenu
import ru.dbotthepony.mc.otm.network.*
import java.math.BigDecimal
import java.util.function.Supplier
class NumberPlayerInputPacket(val id: Int, val value: BigDecimal) : MatteryPacket {
override fun play(context: Supplier<NetworkEvent.Context>) {
context.get().packetHandled = true
context.get().enqueueWork {
((context.get().sender?.containerMenu as? MatteryMenu)?.getWidget(id) as? NumberPlayerInputWidget)?.userInput(value, context.sender!!)
}
}
override fun write(buff: FriendlyByteBuf) {
buff.writeInt(id)
buff.writeDecimal(value)
}
companion object {
fun read(buff: FriendlyByteBuf): NumberPlayerInputPacket {
return NumberPlayerInputPacket(buff.readInt(), buff.readDecimal())
}
}
}
class NumberPlayerInputWidget(menu: MatteryMenu) : AbstractWidget(menu) {
var value by menu.mSynchronizer.bigDecimal()
var ignoreSpectators by menu.mSynchronizer.bool(true)
var supplier: (() -> BigDecimal)? = null
var consumer: ((BigDecimal) -> Unit)? = null
var minValue: BigDecimal? = null
var maxValue: BigDecimal? = null
fun withSupplier(func: () -> BigDecimal): NumberPlayerInputWidget {
supplier = func
return this
}
fun withConsumer(func: (BigDecimal) -> Unit): NumberPlayerInputWidget {
consumer = func
return this
}
fun asClient(): NumberPlayerInputWidget {
supplier = null
consumer = {
MenuNetworkChannel.sendToServer(NumberPlayerInputPacket(slotID, it))
}
return this
}
fun userInput(newValue: BigDecimal, ply: Player? = null) {
if (ply?.isSpectator == true && ignoreSpectators) {
return
}
val consumer = consumer
if (consumer != null) {
@Suppress("name_shadowing")
var newValue = newValue
if (minValue != null) {
newValue = newValue.max(minValue!!)
}
if (maxValue != null) {
newValue = newValue.min(maxValue!!)
}
consumer.invoke(newValue)
updateServer()
}
}
override fun updateServer() {
val supplier = supplier
if (supplier != null) {
value = supplier.invoke()
}
}
}

View File

@ -1,53 +0,0 @@
package ru.dbotthepony.mc.otm.menu.widget
import net.minecraft.network.FriendlyByteBuf
import net.minecraft.world.entity.player.Player
import net.minecraftforge.network.NetworkEvent
import ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.menu.MatteryMenu
import ru.dbotthepony.mc.otm.network.MatteryPacket
import ru.dbotthepony.mc.otm.network.MenuNetworkChannel
import ru.dbotthepony.mc.otm.network.sender
import ru.dbotthepony.mc.otm.runIfClient
import java.util.function.Supplier
class OneWayPlayerInputPacket(val id: Int) : MatteryPacket {
override fun play(context: Supplier<NetworkEvent.Context>) {
context.get().packetHandled = true
context.get().enqueueWork {
((context.get().sender?.containerMenu as? MatteryMenu)?.getWidget(id) as? OneWayPlayerInputWidget)?.userInput(context.sender!!)
}
}
override fun write(buff: FriendlyByteBuf) {
buff.writeInt(id)
}
companion object {
fun read(buff: FriendlyByteBuf): OneWayPlayerInputPacket {
return OneWayPlayerInputPacket(buff.readInt())
}
}
}
class OneWayPlayerInputWidget(menu: MatteryMenu, clicker: (() -> Unit)? = null) : AbstractWidget(menu) {
val clicker: () -> Unit
var ignoreSpectators by menu.mSynchronizer.bool(true)
init {
if (clicker != null) {
this.clicker = clicker
} else {
this.clicker = { MenuNetworkChannel.sendToServer(OneWayPlayerInputPacket(slotID)) }
}
}
fun userInput(ply: Player? = null) {
if (ply?.isSpectator != true || !ignoreSpectators) {
clicker.invoke()
}
}
override fun updateServer() {}
}

View File

@ -19,9 +19,6 @@ import ru.dbotthepony.mc.otm.menu.data.ItemViewInteractPacket
import ru.dbotthepony.mc.otm.menu.data.StackAddPacket import ru.dbotthepony.mc.otm.menu.data.StackAddPacket
import ru.dbotthepony.mc.otm.menu.data.StackChangePacket import ru.dbotthepony.mc.otm.menu.data.StackChangePacket
import ru.dbotthepony.mc.otm.menu.data.StackRemovePacket import ru.dbotthepony.mc.otm.menu.data.StackRemovePacket
import ru.dbotthepony.mc.otm.menu.widget.BooleanPlayerInputPacket
import ru.dbotthepony.mc.otm.menu.widget.NumberPlayerInputPacket
import ru.dbotthepony.mc.otm.menu.widget.OneWayPlayerInputPacket
import java.io.ByteArrayInputStream import java.io.ByteArrayInputStream
import java.util.function.Supplier import java.util.function.Supplier
@ -79,17 +76,12 @@ object MenuNetworkChannel : MatteryNetworkChannel(
add(StackChangePacket::class.java, StackChangePacket.Companion::read, NetworkDirection.PLAY_TO_CLIENT) add(StackChangePacket::class.java, StackChangePacket.Companion::read, NetworkDirection.PLAY_TO_CLIENT)
add(StackRemovePacket::class.java, StackRemovePacket.Companion::read, NetworkDirection.PLAY_TO_CLIENT) add(StackRemovePacket::class.java, StackRemovePacket.Companion::read, NetworkDirection.PLAY_TO_CLIENT)
// container data // Menu data
// Server->Client
add(MenuFieldPacket::class.java, MenuFieldPacket.Companion::read, NetworkDirection.PLAY_TO_CLIENT) add(MenuFieldPacket::class.java, MenuFieldPacket.Companion::read, NetworkDirection.PLAY_TO_CLIENT)
// Client->Server
// Player input in menus
add(NumberPlayerInputPacket::class.java, NumberPlayerInputPacket.Companion::read, NetworkDirection.PLAY_TO_SERVER)
add(OneWayPlayerInputPacket::class.java, OneWayPlayerInputPacket.Companion::read, NetworkDirection.PLAY_TO_SERVER)
add(BooleanPlayerInputPacket::class.java, BooleanPlayerInputPacket.Companion::read, NetworkDirection.PLAY_TO_SERVER)
add(MatteryMenu.PlayerInputPacket::class.java, MatteryMenu::PlayerInputPacket, NetworkDirection.PLAY_TO_SERVER) add(MatteryMenu.PlayerInputPacket::class.java, MatteryMenu::PlayerInputPacket, NetworkDirection.PLAY_TO_SERVER)
// menu specific
// Item monitor // Item monitor
add(ItemMonitorPlayerSettings::class.java, ItemMonitorPlayerSettings.Companion::read) add(ItemMonitorPlayerSettings::class.java, ItemMonitorPlayerSettings.Companion::read)