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"))
button.dock = Dock.TOP
button.setDockMargin(4f, 0f, 4f, 0f)
button.bind { menu.switchDirection.userInput(minecraft?.player) }
button.bind { menu.switchDirection.input(null) }
}
val infoPanels = frame.fetchChildren()
@ -91,7 +91,7 @@ class EnergyCounterScreen(menu: EnergyCounterMenu, inventory: Inventory, title:
label.dock = Dock.TOP
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.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 ru.dbotthepony.mc.otm.client.minecraft
import ru.dbotthepony.mc.otm.core.TextComponent
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
import ru.dbotthepony.mc.otm.menu.widget.NumberPlayerInputWidget
import ru.dbotthepony.mc.otm.menu.MatteryMenu
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,
parent: EditablePanel<*>?,
val inputWidget: NumberPlayerInputWidget,
val networkValue: () -> BigDecimal,
val callback: (BigDecimal) -> Unit,
val isAvailable: BooleanSupplier = BooleanSupplier { true },
x: Float = 0f,
y: Float = 0f,
width: Float = 0f,
height: Float = 20f,
defaultText: Component = TextComponent("")
) : 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 inputStr = ""
override fun mouseClickedInner(x: Double, y: Double, button: Int): Boolean {
if (inputWidget.ignoreSpectators && minecraft.player?.isSpectator == true) {
if (!isAvailable.asBoolean) {
return true
}
@ -33,7 +58,7 @@ open class NumberInputPanel<out S : Screen> @JvmOverloads constructor(
super.tick()
if (isFocused) {
if (inputWidget.ignoreSpectators && minecraft.player?.isSpectator == true) {
if (!isAvailable.asBoolean) {
killFocus()
return
}
@ -42,14 +67,14 @@ open class NumberInputPanel<out S : Screen> @JvmOverloads constructor(
}
if (nextUpdateFromServer < System.currentTimeMillis()) {
getOrCreateWidget().value = inputWidget.value.toPlainString()
getOrCreateWidget().value = networkValue.invoke().toPlainString()
inputStr = getOrCreateWidget().value
} else if (!inputWidget.ignoreSpectators || minecraft.player?.isSpectator != true) {
} else if (isAvailable.asBoolean) {
if (inputStr != getOrCreateWidget().value) {
inputStr = getOrCreateWidget().value
try {
inputWidget.userInput(BigDecimal(inputStr), minecraft.player)
callback.invoke(BigDecimal(inputStr))
} 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 ru.dbotthepony.mc.otm.client.minecraft
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(
screen: S,
parent: EditablePanel<*>?,
val widget: BooleanPlayerInputWidget,
val widget: NetworkedBooleanInput,
x: Float = 0f,
y: Float = 0f,
width: Float = REGULAR_DIMENSIONS + 120f,
@ -19,7 +19,7 @@ open class CheckBoxInputPanel<out S : Screen> @JvmOverloads constructor(
set(value) {}
override var isDisabled: Boolean
get() = !widget.ignoreSpectators || minecraft.player?.isSpectator == true
get() = widget.input.allowSpectators || minecraft.player?.isSpectator == true
set(value) {}
override fun onClick() {

View File

@ -4,12 +4,12 @@ import net.minecraft.client.gui.screens.Screen
import net.minecraft.network.chat.Component
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
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(
screen: S,
parent: EditablePanel<*>?,
widget: BooleanPlayerInputWidget,
widget: NetworkedBooleanInput,
text: Component,
x: 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.menu.data.INetworkedItemViewProvider
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.storage.ITEM_STORAGE
import ru.dbotthepony.mc.otm.storage.ItemStackWrapper
@ -68,15 +68,15 @@ class DriveViewerMenu @JvmOverloads constructor(
val driveFilterSlots = addFilterSlots(driveFilter)
val isWhitelist = BooleanPlayerInputWidget(this)
val matchTag = BooleanPlayerInputWidget(this)
val matchNBT = BooleanPlayerInputWidget(this)
val isWhitelist = NetworkedBooleanInput(this)
val matchTag = NetworkedBooleanInput(this)
val matchNBT = NetworkedBooleanInput(this)
init {
if (tile == null) {
isWhitelist.asClient()
matchTag.asClient()
matchNBT.asClient()
isWhitelist.isClient = true
matchTag.isClient = true
matchNBT.isClient = true
}
}
@ -109,24 +109,24 @@ class DriveViewerMenu @JvmOverloads constructor(
driveFilter.copyFrom(filter)
driveFilter.isLocked = false
isWhitelist.withProperty(driveFilter::isWhitelist)
matchTag.withProperty(driveFilter::matchTag)
matchNBT.withProperty(driveFilter::matchNBT)
isWhitelist.with(driveFilter::isWhitelist)
matchTag.with(driveFilter::matchTag)
matchNBT.with(driveFilter::matchNBT)
} else {
driveFilter.clear()
driveFilter.isLocked = true
isWhitelist.withoutAnything()
matchTag.withoutAnything()
matchNBT.withoutAnything()
isWhitelist.clear()
matchTag.clear()
matchNBT.clear()
}
} else {
driveFilter.clear()
driveFilter.isLocked = true
isWhitelist.withoutAnything()
matchTag.withoutAnything()
matchNBT.withoutAnything()
isWhitelist.clear()
matchTag.clear()
matchNBT.clear()
}
}
@ -170,4 +170,4 @@ class DriveViewerMenu @JvmOverloads constructor(
slot.setChanged()
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.entity.tech.EnergyCounterBlockEntity
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 java.math.BigDecimal
@ -22,36 +20,28 @@ class EnergyCounterMenu @JvmOverloads constructor(
var average by mSynchronizer.fraction()
var last20Ticks 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)
val maxIO = NumberPlayerInputWidget(this)
// TODO: Graph and proper networking for it
private var ticksPassed = 0
init {
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)
}
val maxIOInput = bigDecimalInput {
if (tile is EnergyCounterBlockEntity) {
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() {
if (tile is EnergyCounterBlockEntity) {
passed = tile.passed
@ -64,6 +54,8 @@ class EnergyCounterMenu @JvmOverloads constructor(
ticksPassed = (ticksPassed + 1) % 20
inputDirection = tile.blockState.getValue(EnergyCounterBlock.INPUT_DIRECTION)
maxIO = tile.ioLimit?.toBigDecmial() ?: -BigDecimal.ONE
}
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.matter.canExtractMatter
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.ProgressGaugeWidget
import ru.dbotthepony.mc.otm.core.orNull
@ -21,7 +21,7 @@ class MatterBottlerMenu @JvmOverloads constructor(
) : MatteryPoweredMenu(
MMenus.MATTER_BOTTLER, p_38852_, inventory, tile
) {
val workFlow: BooleanPlayerInputWidget
val workFlow: NetworkedBooleanInput
val progressWidget: ProgressGaugeWidget
val matterWidget: LevelGaugeWidget
@ -34,11 +34,11 @@ class MatterBottlerMenu @JvmOverloads constructor(
if (tile == null) {
progressWidget = ProgressGaugeWidget(this)
matterWidget = LevelGaugeWidget(this)
workFlow = BooleanPlayerInputWidget(this).asClient()
workFlow = NetworkedBooleanInput(this).asClient()
} else {
progressWidget = ProgressGaugeWidget(this) { tile.getWorkProgress() }
matterWidget = LevelGaugeWidget(this, tile.matter)
workFlow = BooleanPlayerInputWidget(this, tile::isBottling)
workFlow = NetworkedBooleanInput(this, tile::isBottling)
}
storageSlots = ImmutableList(6) { index ->
@ -58,9 +58,4 @@ class MatterBottlerMenu @JvmOverloads constructor(
storageSlots.forEach(this::addSlot)
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.container.ItemFilter
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.NullValueCodec
import ru.dbotthepony.mc.otm.menu.widget.AbstractWidget
import ru.dbotthepony.mc.otm.network.FieldSynchronizer
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 java.io.DataInputStream
import java.io.DataOutputStream
import java.math.BigDecimal
import java.util.*
import java.util.function.Supplier
import kotlin.collections.ArrayList
@ -43,6 +47,9 @@ abstract class MatteryMenu @JvmOverloads protected constructor(
val inventory: Inventory,
val tile: BlockEntity? = null
) : AbstractContainerMenu(menuType, containerId) {
/**
* Server->Client field synchronizer
*/
val mSynchronizer = FieldSynchronizer()
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
var allowSpectators by mSynchronizer.bool(allowSpectators)
init {
playerInputs.add(this)
@ -93,11 +104,26 @@ abstract class MatteryMenu @JvmOverloads protected constructor(
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?) {
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)
*/

View File

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

View File

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

View File

@ -4,7 +4,7 @@ import net.minecraft.world.entity.player.Inventory
import net.minecraft.world.inventory.Slot
import ru.dbotthepony.mc.otm.block.entity.storage.StorageImporterBlockEntity
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
class StorageImporterMenu @JvmOverloads constructor(
@ -15,15 +15,15 @@ class StorageImporterMenu @JvmOverloads constructor(
MMenus.STORAGE_IMPORTER, p_38852_, inventory, tile
) {
val busFilterSlots: List<ItemFilterNetworkSlot>
val busFilterState: BooleanPlayerInputWidget
val busFilterState: NetworkedBooleanInput
init {
if (tile != null) {
busFilterSlots = addFilterSlots(tile.filter)
busFilterState = BooleanPlayerInputWidget(this, tile.filter::isWhitelist)
busFilterState = NetworkedBooleanInput(this, tile.filter::isWhitelist)
} else {
busFilterSlots = addFilterSlots(StorageImporterBlockEntity.MAX_FILTERS)
busFilterState = BooleanPlayerInputWidget(this).asClient()
busFilterState = NetworkedBooleanInput(this).asClient()
}
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.StackChangePacket
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.util.function.Supplier
@ -79,17 +76,12 @@ object MenuNetworkChannel : MatteryNetworkChannel(
add(StackChangePacket::class.java, StackChangePacket.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)
// 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)
// Client->Server
add(MatteryMenu.PlayerInputPacket::class.java, MatteryMenu::PlayerInputPacket, NetworkDirection.PLAY_TO_SERVER)
// menu specific
// Item monitor
add(ItemMonitorPlayerSettings::class.java, ItemMonitorPlayerSettings.Companion::read)