Holo sign lock, more streamlined player input API
This commit is contained in:
parent
e505bce76d
commit
19d8eca2e5
@ -20,6 +20,8 @@ class HoloSignBlockEntity(blockPos: BlockPos, blockState: BlockState) : Synchron
|
||||
access.write(value)
|
||||
})
|
||||
|
||||
var locked = false
|
||||
|
||||
override fun createMenu(p_39954_: Int, p_39955_: Inventory, p_39956_: Player): AbstractContainerMenu {
|
||||
return HoloSignMenu(p_39954_, p_39955_, this)
|
||||
}
|
||||
@ -35,12 +37,35 @@ class HoloSignBlockEntity(blockPos: BlockPos, blockState: BlockState) : Synchron
|
||||
|
||||
override fun load(p_155245_: CompoundTag) {
|
||||
super.load(p_155245_)
|
||||
text = p_155245_.getString(TEXT_KEY)
|
||||
locked = p_155245_.getBoolean(LOCKED_KEY)
|
||||
|
||||
if (locked) {
|
||||
text = p_155245_.getString(TEXT_KEY)
|
||||
} else {
|
||||
text = truncate(p_155245_.getString(TEXT_KEY))
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TEXT_KEY = "SignText"
|
||||
const val LOCKED_KEY = "Locked"
|
||||
const val DEFAULT_MAX_NEWLINES = 8
|
||||
const val DEFAULT_MAX_LINE_LENGTH = 15
|
||||
private val NEWLINES = Regex("\r?\n")
|
||||
|
||||
fun truncate(input: String): String {
|
||||
val lines = input.split(NEWLINES)
|
||||
val result = ArrayList<String>(lines.size.coerceAtMost(DEFAULT_MAX_NEWLINES))
|
||||
|
||||
for (i in 0 until lines.size.coerceAtMost(DEFAULT_MAX_NEWLINES)) {
|
||||
if (lines[i].length > DEFAULT_MAX_LINE_LENGTH) {
|
||||
result.add(lines[i].substring(0, DEFAULT_MAX_LINE_LENGTH))
|
||||
} else {
|
||||
result.add(lines[i])
|
||||
}
|
||||
}
|
||||
|
||||
return result.joinToString("\n")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,9 @@ import net.minecraft.world.entity.player.Inventory
|
||||
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.FramePanel
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.button.CheckBoxLabelInputPanel
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.input.NetworkedStringInputPanel
|
||||
import ru.dbotthepony.mc.otm.core.TranslatableComponent
|
||||
import ru.dbotthepony.mc.otm.menu.decorative.HoloSignMenu
|
||||
|
||||
class HoloSignScreen(menu: HoloSignMenu, inventory: Inventory, title: Component) : MatteryScreen<HoloSignMenu>(menu, title) {
|
||||
@ -16,6 +18,9 @@ class HoloSignScreen(menu: HoloSignMenu, inventory: Inventory, title: Component)
|
||||
input.dock = Dock.FILL
|
||||
input.multiLine = true
|
||||
|
||||
val lock = CheckBoxLabelInputPanel(this, frame, menu.locked, TranslatableComponent("otm.gui.lock_holo_screen"))
|
||||
lock.dock = Dock.BOTTOM
|
||||
|
||||
return frame
|
||||
}
|
||||
}
|
||||
|
@ -3,12 +3,13 @@ package ru.dbotthepony.mc.otm.client.screen.panels.button
|
||||
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.input.BooleanInputWithFeedback
|
||||
import ru.dbotthepony.mc.otm.core.value
|
||||
import ru.dbotthepony.mc.otm.menu.input.IPlayerInputWithFeedback
|
||||
|
||||
open class CheckBoxInputPanel<out S : Screen> @JvmOverloads constructor(
|
||||
screen: S,
|
||||
parent: EditablePanel<*>?,
|
||||
val widget: BooleanInputWithFeedback,
|
||||
val widget: IPlayerInputWithFeedback<Boolean>,
|
||||
x: Float = 0f,
|
||||
y: Float = 0f,
|
||||
width: Float = REGULAR_DIMENSIONS + 120f,
|
||||
@ -19,10 +20,10 @@ open class CheckBoxInputPanel<out S : Screen> @JvmOverloads constructor(
|
||||
set(value) {}
|
||||
|
||||
override var isDisabled: Boolean
|
||||
get() = widget.input.allowSpectators || minecraft.player?.isSpectator == true
|
||||
get() = !widget.test(minecraft.player)
|
||||
set(value) {}
|
||||
|
||||
override fun onClick() {
|
||||
widget.input(!checked)
|
||||
widget.accept(!checked)
|
||||
}
|
||||
}
|
||||
|
@ -5,11 +5,12 @@ 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.input.BooleanInputWithFeedback
|
||||
import ru.dbotthepony.mc.otm.menu.input.IPlayerInputWithFeedback
|
||||
|
||||
open class CheckBoxLabelInputPanel<out S : Screen> @JvmOverloads constructor(
|
||||
screen: S,
|
||||
parent: EditablePanel<*>?,
|
||||
widget: BooleanInputWithFeedback,
|
||||
widget: IPlayerInputWithFeedback<Boolean>,
|
||||
text: Component,
|
||||
x: Float = 0f,
|
||||
y: Float = 0f,
|
||||
@ -17,14 +18,6 @@ open class CheckBoxLabelInputPanel<out S : Screen> @JvmOverloads constructor(
|
||||
height: Float = CheckBoxPanel.REGULAR_DIMENSIONS
|
||||
) : EditablePanel<S>(screen, parent, x, y, width, height) {
|
||||
val widget get() = checkbox.widget
|
||||
val checkbox = CheckBoxInputPanel(
|
||||
screen,
|
||||
this,
|
||||
widget,
|
||||
0f,
|
||||
0f,
|
||||
CheckBoxPanel.REGULAR_DIMENSIONS,
|
||||
CheckBoxPanel.REGULAR_DIMENSIONS
|
||||
)
|
||||
val checkbox = CheckBoxInputPanel(screen = screen, parent = this, widget = widget, x = 0f, y = 0f, width = CheckBoxPanel.REGULAR_DIMENSIONS, height = CheckBoxPanel.REGULAR_DIMENSIONS)
|
||||
val label = Label(screen, this, CheckBoxPanel.REGULAR_DIMENSIONS + 4f, 4f, text = text)
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package ru.dbotthepony.mc.otm.client.screen.panels.input
|
||||
|
||||
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.input.AbstractPlayerInputWithFeedback
|
||||
import ru.dbotthepony.mc.otm.milliTime
|
||||
@ -15,13 +16,13 @@ open class NetworkedStringInputPanel<out S : Screen>(
|
||||
height: Float = 11f,
|
||||
) : TextInputPanel<S>(screen, parent, x, y, width, height) {
|
||||
override var isActive: Boolean
|
||||
get() = backend.check()
|
||||
get() = backend.test(minecraft.player)
|
||||
set(value) {}
|
||||
|
||||
override fun onFocusChanged(new: Boolean, old: Boolean) {
|
||||
super.onFocusChanged(new, old)
|
||||
|
||||
if (new && !backend.check()) {
|
||||
if (new && !backend.test(minecraft.player)) {
|
||||
killFocus()
|
||||
}
|
||||
}
|
||||
@ -30,7 +31,7 @@ open class NetworkedStringInputPanel<out S : Screen>(
|
||||
|
||||
override fun onTextChanged(old: String, new: String) {
|
||||
lastChanges = milliTime + 1000L
|
||||
backend.input(new)
|
||||
backend.accept(new)
|
||||
}
|
||||
|
||||
override fun tick() {
|
||||
|
@ -19,6 +19,14 @@ interface GetterSetter<V> : Supplier<V>, Consumer<V>, ReadWriteProperty<Any?, V>
|
||||
return get()
|
||||
}
|
||||
|
||||
operator fun invoke(): V {
|
||||
return get()
|
||||
}
|
||||
|
||||
operator fun invoke(value: V) {
|
||||
accept(value)
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun <V> of(getter: Supplier<V>, setter: Consumer<V>): GetterSetter<V> {
|
||||
return object : GetterSetter<V> {
|
||||
|
@ -39,6 +39,7 @@ import java.io.DataInputStream
|
||||
import java.io.DataOutputStream
|
||||
import java.math.BigDecimal
|
||||
import java.util.*
|
||||
import java.util.function.Predicate
|
||||
import java.util.function.Supplier
|
||||
import kotlin.collections.ArrayList
|
||||
|
||||
@ -82,7 +83,7 @@ abstract class MatteryMenu @JvmOverloads protected constructor(
|
||||
val menu = context.sender?.containerMenu as? MatteryMenu ?: return@enqueueWork
|
||||
if (menu.containerId != containerId) return@enqueueWork
|
||||
val input = menu.playerInputs.getOrNull(inputId) ?: return@enqueueWork
|
||||
if (!input.allowSpectators && context.sender!!.isSpectator) return@enqueueWork
|
||||
if (!input.test(context.sender)) return@enqueueWork
|
||||
input.invoke(input.codec.read(DataInputStream(FastByteArrayInputStream(payload))))
|
||||
}
|
||||
}
|
||||
@ -91,7 +92,7 @@ abstract class MatteryMenu @JvmOverloads protected constructor(
|
||||
/**
|
||||
* Client->Server handler
|
||||
*/
|
||||
inner class PlayerInput<V>(val codec: IStreamCodec<V>, allowSpectators: Boolean = false, val handler: (V) -> Unit) {
|
||||
inner class PlayerInput<V>(val codec: IStreamCodec<V>, allowSpectators: Boolean = false, val handler: (V) -> Unit) : Predicate<Player?> {
|
||||
val id = playerInputs.size
|
||||
var allowSpectators by mSynchronizer.bool(allowSpectators)
|
||||
|
||||
@ -99,6 +100,22 @@ abstract class MatteryMenu @JvmOverloads protected constructor(
|
||||
playerInputs.add(this)
|
||||
}
|
||||
|
||||
private val filters = ArrayList<Predicate<Player>>()
|
||||
|
||||
init {
|
||||
filters.add { allowSpectators || !it.isSpectator }
|
||||
}
|
||||
|
||||
fun filter(predicate: Predicate<Player>): PlayerInput<V> {
|
||||
filters.add(predicate)
|
||||
return this
|
||||
}
|
||||
|
||||
override fun test(player: Player?): Boolean {
|
||||
if (player == null) return false
|
||||
return filters.all { it.test(player) }
|
||||
}
|
||||
|
||||
fun input(value: V) {
|
||||
val stream = FastByteArrayOutputStream()
|
||||
codec.write(DataOutputStream(stream), value)
|
||||
|
@ -4,6 +4,7 @@ import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.inventory.Slot
|
||||
import ru.dbotthepony.mc.otm.block.entity.decorative.HoloSignBlockEntity
|
||||
import ru.dbotthepony.mc.otm.menu.MatteryMenu
|
||||
import ru.dbotthepony.mc.otm.menu.input.BooleanInputWithFeedback
|
||||
import ru.dbotthepony.mc.otm.menu.input.StringInputWithFeedback
|
||||
import ru.dbotthepony.mc.otm.registry.MMenus
|
||||
|
||||
@ -12,28 +13,18 @@ class HoloSignMenu @JvmOverloads constructor(
|
||||
inventory: Inventory,
|
||||
tile: HoloSignBlockEntity? = null
|
||||
) : MatteryMenu(MMenus.HOLO_SIGN, containerId, inventory, tile) {
|
||||
val text = if (tile != null)
|
||||
StringInputWithFeedback(this).withConsumer {
|
||||
val lines = it.split(NEWLINES)
|
||||
val result = ArrayList<String>(lines.size.coerceAtMost(HoloSignBlockEntity.DEFAULT_MAX_NEWLINES))
|
||||
val text = StringInputWithFeedback(this)
|
||||
val locked = BooleanInputWithFeedback(this)
|
||||
|
||||
for (i in 0 until lines.size.coerceAtMost(HoloSignBlockEntity.DEFAULT_MAX_NEWLINES)) {
|
||||
if (lines[i].length > HoloSignBlockEntity.DEFAULT_MAX_LINE_LENGTH) {
|
||||
result.add(lines[i].substring(0, HoloSignBlockEntity.DEFAULT_MAX_LINE_LENGTH))
|
||||
} else {
|
||||
result.add(lines[i])
|
||||
}
|
||||
}
|
||||
init {
|
||||
locked.filter { it.isCreative }
|
||||
|
||||
tile.text = result.joinToString("\n")
|
||||
}.withSupplier(tile::text)
|
||||
else
|
||||
StringInputWithFeedback(this)
|
||||
if (tile != null) {
|
||||
text.withConsumer { if (tile.locked) tile.text = it else tile.text = HoloSignBlockEntity.truncate(it) }.withSupplier(tile::text)
|
||||
locked.with(tile::locked)
|
||||
}
|
||||
}
|
||||
|
||||
override val storageSlots: Collection<Slot>
|
||||
get() = listOf()
|
||||
|
||||
companion object {
|
||||
private val NEWLINES = Regex("\r?\n")
|
||||
}
|
||||
}
|
||||
|
@ -4,12 +4,17 @@ import net.minecraft.world.entity.player.Player
|
||||
import ru.dbotthepony.mc.otm.client.minecraft
|
||||
import ru.dbotthepony.mc.otm.core.GetterSetter
|
||||
import ru.dbotthepony.mc.otm.menu.MatteryMenu
|
||||
import java.util.function.Consumer
|
||||
import java.util.function.Predicate
|
||||
import java.util.function.Supplier
|
||||
import kotlin.reflect.KMutableProperty0
|
||||
|
||||
interface IPlayerInputWithFeedback<V> : GetterSetter<V>, Predicate<Player?>
|
||||
|
||||
/**
|
||||
* Getting and setting values should ONLY be done clientside
|
||||
*/
|
||||
abstract class AbstractPlayerInputWithFeedback<V> : GetterSetter<V> {
|
||||
abstract class AbstractPlayerInputWithFeedback<V> : IPlayerInputWithFeedback<V> {
|
||||
abstract val input: MatteryMenu.PlayerInput<V>
|
||||
abstract val value: V
|
||||
|
||||
@ -21,6 +26,9 @@ abstract class AbstractPlayerInputWithFeedback<V> : GetterSetter<V> {
|
||||
input.checkedInput(t, minecraft.player as Player?)
|
||||
}
|
||||
|
||||
override fun test(player: Player?) = input.test(player)
|
||||
fun filter(filter: Predicate<Player>) = input.filter(filter)
|
||||
|
||||
var supplier: (() -> V)? = null
|
||||
var consumer: ((V) -> Unit)? = null
|
||||
|
||||
@ -29,11 +37,21 @@ abstract class AbstractPlayerInputWithFeedback<V> : GetterSetter<V> {
|
||||
return this
|
||||
}
|
||||
|
||||
fun withSupplier(func: Supplier<V>): AbstractPlayerInputWithFeedback<V> {
|
||||
supplier = func::get
|
||||
return this
|
||||
}
|
||||
|
||||
fun withConsumer(func: (V) -> Unit): AbstractPlayerInputWithFeedback<V> {
|
||||
consumer = func
|
||||
return this
|
||||
}
|
||||
|
||||
fun withConsumer(func: Consumer<V>): AbstractPlayerInputWithFeedback<V> {
|
||||
consumer = func::accept
|
||||
return this
|
||||
}
|
||||
|
||||
fun with(state: KMutableProperty0<V>): AbstractPlayerInputWithFeedback<V> {
|
||||
withConsumer { state.set(it) }
|
||||
withSupplier { state.get() }
|
||||
@ -41,8 +59,8 @@ abstract class AbstractPlayerInputWithFeedback<V> : GetterSetter<V> {
|
||||
}
|
||||
|
||||
fun with(state: GetterSetter<V>): AbstractPlayerInputWithFeedback<V> {
|
||||
withConsumer(state::accept)
|
||||
withSupplier(state::get)
|
||||
withConsumer(state)
|
||||
withSupplier(state)
|
||||
return this
|
||||
}
|
||||
|
||||
@ -51,18 +69,4 @@ abstract class AbstractPlayerInputWithFeedback<V> : GetterSetter<V> {
|
||||
consumer = null
|
||||
return this
|
||||
}
|
||||
|
||||
/**
|
||||
* shortcut to checked input of [input]
|
||||
*/
|
||||
fun input(newValue: V) {
|
||||
input.checkedInput(newValue, minecraft.player as Player?)
|
||||
}
|
||||
|
||||
/**
|
||||
* checks if local (client) player can modify this input
|
||||
*/
|
||||
fun check(): Boolean {
|
||||
return input.allowSpectators || (minecraft.player as Player?)?.isSpectator == false
|
||||
}
|
||||
}
|
||||
|
@ -17,6 +17,6 @@ class BooleanInputWithFeedback(menu: MatteryMenu) : AbstractPlayerInputWithFeedb
|
||||
}
|
||||
|
||||
fun switchValue() {
|
||||
input(!value)
|
||||
accept(!value)
|
||||
}
|
||||
}
|
||||
|
@ -99,6 +99,10 @@ sealed interface IMutableField<V> : IField<V>, GetterSetter<V> {
|
||||
override fun accept(t: V) {
|
||||
value = t
|
||||
}
|
||||
|
||||
override fun invoke(): V {
|
||||
return this.value
|
||||
}
|
||||
}
|
||||
|
||||
data class MapChangeset<out K, out V>(
|
||||
|
Loading…
Reference in New Issue
Block a user