Redstone control button, sanitize EnumRectangleButtonPanel, EnumInputWithFeedback
This commit is contained in:
parent
862eba0234
commit
7d5b63f38e
@ -22,9 +22,6 @@ data class MatteryAtlas(
|
||||
winding: UVWindingOrder = this.winding,
|
||||
) = MatterySprite(texture, x = x, y = y, width = width, height = height, atlasHeight = this.height, atlasWidth = this.width, winding = winding)
|
||||
|
||||
@Deprecated("Construct grid directly instead")
|
||||
fun grid(rows: Int, columns: Int) = GridAtlas(texture, this.width / rows, this.height / columns, rows = rows, columns = columns)
|
||||
|
||||
@Deprecated("Construct grid directly instead")
|
||||
fun grid(width: Float, height: Float, rows: Int, columns: Int) = GridAtlas(texture, width, height, rows, columns)
|
||||
}
|
||||
|
@ -13,4 +13,5 @@ object WidgetLocation {
|
||||
val PROGRESS_ARROWS = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/progress_arrows.png"), 22f, 31f)
|
||||
val HORIZONTAL_GAUGES = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/horizontal_gauges.png"), 96f, 54f)
|
||||
val VERTICAL_GAUGES = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/vertical_gauges.png"), 90f, 48f)
|
||||
val REDSTONE_CONTROLS = MatteryAtlas(ResourceLocation(OverdriveThatMatters.MOD_ID, "textures/gui/widgets/redstone.png"), 54f, 18f)
|
||||
}
|
||||
|
@ -46,4 +46,10 @@ object Widgets18 {
|
||||
val BUTTON_DISABLED_STRETCHABLE = makeButton(GRID)
|
||||
val BUTTON_DISABLED = GRID.next()
|
||||
val COOLDOWN = GRID.next()
|
||||
|
||||
private val redstoneGrid = WidgetLocation.REDSTONE_CONTROLS.grid(rows = 1, columns = 3)
|
||||
|
||||
val REDSTONE_IGNORED = redstoneGrid.next()
|
||||
val REDSTONE_LOW = redstoneGrid.next()
|
||||
val REDSTONE_HIGH = redstoneGrid.next()
|
||||
}
|
||||
|
@ -11,6 +11,7 @@ import net.minecraft.client.renderer.entity.ItemRenderer
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.inventory.Slot
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraftforge.client.event.ContainerScreenEvent.Render.Background
|
||||
import net.minecraftforge.client.event.ContainerScreenEvent.Render.Foreground
|
||||
import net.minecraftforge.common.MinecraftForge
|
||||
@ -62,6 +63,40 @@ abstract class MatteryScreen<T : MatteryMenu>(menu: T, inventory: Inventory, tit
|
||||
val quickCraftingType get() = quickCraftingType
|
||||
val isQuickCrafting get() = isQuickCrafting
|
||||
|
||||
fun renderItemStack(absoluteX: Float, absoluteY: Float, itemstack: ItemStack, countOverride: String? = null) {
|
||||
if (!itemstack.isEmpty) {
|
||||
RenderSystem.enableDepthTest()
|
||||
|
||||
val systemPoseStack = RenderSystem.getModelViewStack()
|
||||
|
||||
systemPoseStack.pushPose()
|
||||
systemPoseStack.translate(absoluteX + 1f, absoluteY + 1f, 0f)
|
||||
RenderSystem.applyModelViewMatrix()
|
||||
RenderSystem.depthFunc(GL11.GL_LESS)
|
||||
|
||||
// Thanks Mojang
|
||||
// Very cool
|
||||
// (for int x, int y, which are then cast into doubles anyway)
|
||||
itemRenderer.blitOffset = 1f // Z pos
|
||||
|
||||
itemRenderer.renderAndDecorateItem(
|
||||
requireNotNull(ru.dbotthepony.mc.otm.client.minecraft.player) { "yo, dude, what the fuck" },
|
||||
itemstack,
|
||||
0,
|
||||
0,
|
||||
(absoluteX + absoluteY * 1000f).toInt()
|
||||
)
|
||||
|
||||
RenderSystem.depthFunc(GL11.GL_ALWAYS)
|
||||
itemRenderer.renderGuiItemDecorations(font, itemstack, 0, 0, countOverride)
|
||||
itemRenderer.blitOffset = 0f
|
||||
|
||||
// too big accumulations can lead to Z near clipping issues
|
||||
systemPoseStack.popPose()
|
||||
RenderSystem.applyModelViewMatrix()
|
||||
}
|
||||
}
|
||||
|
||||
init {
|
||||
for (slot in menu.slots) {
|
||||
slot.x = Int.MAX_VALUE
|
||||
|
@ -7,6 +7,7 @@ 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.FramePanel
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.button.CheckBoxLabelInputPanel
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.button.makeDeviceControls
|
||||
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
|
||||
@ -24,6 +25,8 @@ class HoloSignScreen(menu: HoloSignMenu, inventory: Inventory, title: Component)
|
||||
lock.dockMargin = DockProperty(2f, 2f, 2f, 2f)
|
||||
lock.tooltip = TranslatableComponent("otm.gui.lock_holo_screen.tip")
|
||||
|
||||
makeDeviceControls(this, frame, redstone = menu.redstone)
|
||||
|
||||
return frame
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,59 @@
|
||||
package ru.dbotthepony.mc.otm.client.screen.panels.button
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraft.world.item.Items
|
||||
import ru.dbotthepony.mc.otm.block.entity.RedstoneSetting
|
||||
import ru.dbotthepony.mc.otm.client.minecraft
|
||||
import ru.dbotthepony.mc.otm.client.render.Widgets18
|
||||
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.FramePanel
|
||||
import ru.dbotthepony.mc.otm.menu.input.IPlayerInputWithFeedback
|
||||
|
||||
fun <S : MatteryScreen<*>> makeRedstoneSettingButton(
|
||||
screen: S,
|
||||
parent: EditablePanel<*>?,
|
||||
x: Float = 0f,
|
||||
y: Float = 0f,
|
||||
control: IPlayerInputWithFeedback<RedstoneSetting>
|
||||
): LargeEnumRectangleButtonPanel<S, RedstoneSetting> {
|
||||
return object : LargeEnumRectangleButtonPanel<S, RedstoneSetting>(
|
||||
screen, parent, x = x, y = y,
|
||||
defaultValue = RedstoneSetting.LOW, enum = RedstoneSetting::class.java,
|
||||
prop = control,
|
||||
) {
|
||||
override var isDisabled: Boolean
|
||||
get() = !control.test(minecraft.player)
|
||||
set(value) {}
|
||||
|
||||
init {
|
||||
add(RedstoneSetting.IGNORED, tooltip = RedstoneSetting.IGNORED.description, skinElement = Widgets18.REDSTONE_IGNORED)
|
||||
add(RedstoneSetting.LOW, tooltip = RedstoneSetting.LOW.description, skinElement = Widgets18.REDSTONE_LOW)
|
||||
add(RedstoneSetting.HIGH, tooltip = RedstoneSetting.HIGH.description, skinElement = Widgets18.REDSTONE_HIGH)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun <S : MatteryScreen<*>> makeDeviceControls(
|
||||
screen: S,
|
||||
parent: FramePanel<S>,
|
||||
redstone: IPlayerInputWithFeedback<RedstoneSetting>? = null
|
||||
): EditablePanel<S> {
|
||||
val panel = object : EditablePanel<S>(screen, parent, width = LargeEnumRectangleButtonPanel.SIZE, height = 0f) {
|
||||
override fun tick() {
|
||||
super.tick()
|
||||
x = parent.width + 3f
|
||||
y = 0f
|
||||
}
|
||||
}
|
||||
|
||||
var y = 0f
|
||||
|
||||
if (redstone != null) {
|
||||
y += makeRedstoneSettingButton(screen, panel, y = y, control = redstone).height + 2f
|
||||
}
|
||||
|
||||
panel.height = (y - 2f).coerceAtLeast(0f)
|
||||
return panel
|
||||
}
|
@ -12,6 +12,7 @@ import ru.dbotthepony.mc.otm.core.GetterSetter
|
||||
import ru.dbotthepony.mc.otm.core.TextComponent
|
||||
import ru.dbotthepony.mc.otm.core.next
|
||||
import ru.dbotthepony.mc.otm.core.prev
|
||||
import ru.dbotthepony.mc.otm.core.util.EnumValueCodec
|
||||
import ru.dbotthepony.mc.otm.core.value
|
||||
import java.util.*
|
||||
import kotlin.collections.ArrayList
|
||||
@ -23,31 +24,25 @@ abstract class EnumRectangleButtonPanel<out S : Screen, T : Enum<T>>(
|
||||
y: Float = 0f,
|
||||
width: Float,
|
||||
height: Float,
|
||||
val enum: Class<T>,
|
||||
enum: Class<T>,
|
||||
val prop: GetterSetter<T>,
|
||||
val defaultValue: T,
|
||||
val onChange: ((newValue: T) -> Unit)? = null,
|
||||
) : RectangleButtonPanel<S>(screen, parent, x, y, width, height, null) {
|
||||
private var building = true
|
||||
val enum = EnumValueCodec.searchClass(enum)
|
||||
private var isBuilding = true
|
||||
|
||||
protected val enumMapping = EnumMap<T, Pair<AbstractMatterySprite, UVWindingOrder>>(enum)
|
||||
protected val tooltipMapping = EnumMap<T, Component>(enum)
|
||||
data class Entry<T : Enum<T>>(
|
||||
val key: T,
|
||||
val skinElement: AbstractMatterySprite?,
|
||||
val winding: UVWindingOrder = UVWindingOrder.NORMAL,
|
||||
val tooltip: Component? = null
|
||||
)
|
||||
|
||||
fun addTooltip(value: T, component: Component): EnumRectangleButtonPanel<S, T> {
|
||||
check(tooltipMapping.put(value, component) == null) { "Already has mapping for $value" }
|
||||
return this
|
||||
}
|
||||
|
||||
var mainTooltip: Component? = null
|
||||
set(value) {
|
||||
if (field != null) {
|
||||
throw UnsupportedOperationException("Write once only")
|
||||
}
|
||||
|
||||
field = value
|
||||
}
|
||||
protected val enumMapping = EnumMap<T, Entry<T>>(enum)
|
||||
|
||||
fun isFullyDefined(): Boolean {
|
||||
if (!isBuilding) return true
|
||||
|
||||
for (value in enum.enumConstants) {
|
||||
if (enumMapping[value] == null) {
|
||||
return false
|
||||
@ -69,77 +64,54 @@ abstract class EnumRectangleButtonPanel<out S : Screen, T : Enum<T>>(
|
||||
return missing
|
||||
}
|
||||
|
||||
fun add(value: T, skinElement: AbstractMatterySprite, winding: UVWindingOrder = UVWindingOrder.NORMAL): EnumRectangleButtonPanel<S, T> {
|
||||
return add(value, skinElement to winding)
|
||||
}
|
||||
|
||||
fun add(value: T, skinElement: AbstractMatterySprite, component: Component, winding: UVWindingOrder = UVWindingOrder.NORMAL): EnumRectangleButtonPanel<S, T> {
|
||||
return add(value, component, skinElement to winding)
|
||||
}
|
||||
|
||||
fun add(value: T, component: Component, skinElement: AbstractMatterySprite, winding: UVWindingOrder = UVWindingOrder.NORMAL): EnumRectangleButtonPanel<S, T> {
|
||||
return add(value, component, skinElement to winding)
|
||||
}
|
||||
|
||||
fun add(value: T, pair: Pair<AbstractMatterySprite, UVWindingOrder>): EnumRectangleButtonPanel<S, T> {
|
||||
check(building) { "Not building" }
|
||||
check(enumMapping.put(value, pair) == null) { "Already has mapping for $value" }
|
||||
|
||||
if (enumMapping.size == enum.enumConstants.size) {
|
||||
finish()
|
||||
fun add(key: T, skinElement: AbstractMatterySprite? = null, tooltip: Component? = null, winding: UVWindingOrder = UVWindingOrder.NORMAL): EnumRectangleButtonPanel<S, T> {
|
||||
return add(Entry(key = key, skinElement = skinElement, winding = winding, tooltip = tooltip))
|
||||
}
|
||||
|
||||
fun add(entry: Entry<T>): EnumRectangleButtonPanel<S, T> {
|
||||
check(isBuilding) { "Not building" }
|
||||
check(enumMapping.put(entry.key, entry) == null) { "Already has mapping for ${entry.key}" }
|
||||
if (enumMapping.size == enum.enumConstants.size) finish()
|
||||
return this
|
||||
}
|
||||
|
||||
fun add(value: T, component: Component, pair: Pair<AbstractMatterySprite, UVWindingOrder>): EnumRectangleButtonPanel<S, T> {
|
||||
addTooltip(value, component)
|
||||
return add(value, pair)
|
||||
}
|
||||
|
||||
fun finish(): EnumRectangleButtonPanel<S, T> {
|
||||
check(building) { "Not building" }
|
||||
check(isFullyDefined()) {
|
||||
"Not all enums having their mapping defined, missing are: ${missingValues.joinToString(", ")}"
|
||||
}
|
||||
|
||||
building = false
|
||||
check(isBuilding) { "Not building" }
|
||||
check(isFullyDefined()) { "Not all enums having their mapping defined, missing are: ${missingValues.joinToString(", ")}" }
|
||||
isBuilding = false
|
||||
return this
|
||||
}
|
||||
|
||||
override fun innerRender(stack: PoseStack, mouseX: Float, mouseY: Float, partialTick: Float) {
|
||||
check(!building) { "Still building this button!" }
|
||||
check(!isBuilding) { "Still building this button!" }
|
||||
super.innerRender(stack, mouseX, mouseY, partialTick)
|
||||
val pair = checkNotNull(enumMapping[prop.get()]) { "HOW" }
|
||||
pair.first.render(stack, 0f, 0f, width, height, pair.second)
|
||||
val entry = checkNotNull(enumMapping[prop.get()]) { "HOW" }
|
||||
entry.skinElement?.render(stack, 0f, 0f, width, height, entry.winding)
|
||||
}
|
||||
|
||||
override fun mouseClickedInner(x: Double, y: Double, button: Int): Boolean {
|
||||
check(!building) { "Still building this button!" }
|
||||
check(!isBuilding) { "Still building this button!" }
|
||||
return super.mouseClickedInner(x, y, button)
|
||||
}
|
||||
|
||||
override fun mouseReleasedInner(x: Double, y: Double, button: Int): Boolean {
|
||||
check(!building) { "Still building this button!" }
|
||||
check(!isBuilding) { "Still building this button!" }
|
||||
return super.mouseReleasedInner(x, y, button)
|
||||
}
|
||||
|
||||
override fun onClick(clickButton: Int) {
|
||||
when (clickButton) {
|
||||
InputConstants.MOUSE_BUTTON_LEFT -> {
|
||||
prop.value = prop.value.next(enum.enumConstants)
|
||||
onChange?.invoke(prop.get())
|
||||
}
|
||||
|
||||
InputConstants.MOUSE_BUTTON_RIGHT -> {
|
||||
prop.value = prop.value.prev(enum.enumConstants)
|
||||
onChange?.invoke(prop.get())
|
||||
override fun test(value: Int): Boolean {
|
||||
return value == InputConstants.MOUSE_BUTTON_LEFT ||
|
||||
value == InputConstants.MOUSE_BUTTON_RIGHT ||
|
||||
value == InputConstants.MOUSE_BUTTON_MIDDLE
|
||||
}
|
||||
|
||||
override fun onClick(mouseButton: Int) {
|
||||
when (mouseButton) {
|
||||
InputConstants.MOUSE_BUTTON_LEFT -> prop.value = prop.value.next(enum.enumConstants)
|
||||
InputConstants.MOUSE_BUTTON_RIGHT -> prop.value = prop.value.prev(enum.enumConstants)
|
||||
InputConstants.MOUSE_BUTTON_MIDDLE -> {
|
||||
if (prop.get() != defaultValue) {
|
||||
if (prop.value != defaultValue) {
|
||||
prop.value = defaultValue
|
||||
onChange?.invoke(prop.get())
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -150,33 +122,27 @@ abstract class EnumRectangleButtonPanel<out S : Screen, T : Enum<T>>(
|
||||
return super.innerRenderTooltips(stack, mouseX, mouseY, partialTick)
|
||||
}
|
||||
|
||||
if (mainTooltip == null && tooltipMapping.size == 0) {
|
||||
if (tooltip == null && tooltipList == null && enumMapping.values.none { it.tooltip != null }) {
|
||||
return super.innerRenderTooltips(stack, mouseX, mouseY, partialTick)
|
||||
}
|
||||
|
||||
val listing = ArrayList<Component>()
|
||||
|
||||
if (mainTooltip != null) {
|
||||
listing.add(mainTooltip!!)
|
||||
if (tooltipList != null) {
|
||||
listing.addAll(tooltipList!!)
|
||||
listing.add(SPACE)
|
||||
} else if (tooltip != null) {
|
||||
listing.add(tooltip!!)
|
||||
listing.add(SPACE)
|
||||
}
|
||||
|
||||
for ((key, value) in tooltipMapping) {
|
||||
if (key == prop.get()) {
|
||||
listing.add(value.copy().withStyle(ChatFormatting.WHITE))
|
||||
} else {
|
||||
listing.add(value.copy().withStyle(ChatFormatting.GRAY))
|
||||
for (entry in enumMapping.values) {
|
||||
if (entry.tooltip != null) {
|
||||
listing.add(entry.tooltip.copy().withStyle(if (entry.key == prop.get()) ChatFormatting.WHITE else ChatFormatting.GRAY))
|
||||
}
|
||||
}
|
||||
|
||||
screen.renderComponentTooltip(
|
||||
stack,
|
||||
listing,
|
||||
mouseX.toInt(),
|
||||
mouseY.toInt(),
|
||||
font
|
||||
)
|
||||
|
||||
screen.renderComponentTooltip(stack, listing, mouseX.toInt(), mouseY.toInt(), font)
|
||||
return true
|
||||
}
|
||||
|
||||
|
@ -15,8 +15,7 @@ open class LargeEnumRectangleButtonPanel<out S : Screen, T : Enum<T>>(
|
||||
enum: Class<T>,
|
||||
prop: GetterSetter<T>,
|
||||
defaultValue: T,
|
||||
onChange: ((newValue: T) -> Unit)? = null,
|
||||
) : EnumRectangleButtonPanel<S, T>(screen, parent, x, y, width, height, enum, prop, defaultValue, onChange) {
|
||||
) : EnumRectangleButtonPanel<S, T>(screen, parent, x, y, width, height, enum, prop, defaultValue) {
|
||||
final override val IDLE = Widgets18.BUTTON_IDLE
|
||||
final override val HOVERED = Widgets18.BUTTON_HOVERED
|
||||
final override val PRESSED = Widgets18.BUTTON_PRESSED
|
||||
|
@ -15,8 +15,7 @@ open class SmallEnumRectangleButtonPanel<out S : Screen, T : Enum<T>>(
|
||||
enum: Class<T>,
|
||||
prop: GetterSetter<T>,
|
||||
defaultValue: T,
|
||||
onChange: ((newValue: T) -> Unit)? = null,
|
||||
) : EnumRectangleButtonPanel<S, T>(screen, parent, x, y, width, height, enum, prop, defaultValue, onChange) {
|
||||
) : EnumRectangleButtonPanel<S, T>(screen, parent, x, y, width, height, enum, prop, defaultValue) {
|
||||
final override val IDLE = Widgets8.BUTTON_IDLE
|
||||
final override val HOVERED = Widgets8.BUTTON_HOVERED
|
||||
final override val PRESSED = Widgets8.BUTTON_PRESSED
|
||||
|
@ -6,8 +6,6 @@ import net.minecraft.client.renderer.GameRenderer
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.world.item.ItemStack
|
||||
import net.minecraftforge.client.extensions.common.IClientItemExtensions
|
||||
import org.lwjgl.opengl.GL11
|
||||
import ru.dbotthepony.mc.otm.client.minecraft
|
||||
import ru.dbotthepony.mc.otm.client.render.*
|
||||
import ru.dbotthepony.mc.otm.client.screen.MatteryScreen
|
||||
import ru.dbotthepony.mc.otm.client.screen.panels.EditablePanel
|
||||
@ -27,40 +25,11 @@ abstract class AbstractSlotPanel<out S : MatteryScreen<*>> @JvmOverloads constru
|
||||
SLOT_BACKGROUND.render(stack, width = width, height = height)
|
||||
}
|
||||
|
||||
protected open fun renderRegular(stack: PoseStack, itemstack: ItemStack, count_override: String? = null) {
|
||||
protected open fun renderRegular(stack: PoseStack, itemstack: ItemStack, countOverride: String? = null) {
|
||||
RenderSystem.setShader(GameRenderer::getPositionTexShader)
|
||||
|
||||
if (!itemstack.isEmpty) {
|
||||
RenderSystem.enableDepthTest()
|
||||
|
||||
val systemPoseStack = RenderSystem.getModelViewStack()
|
||||
|
||||
systemPoseStack.pushPose()
|
||||
systemPoseStack.translate((absoluteX + 1f).toDouble(), (absoluteY + 1f).toDouble(), 0.0)
|
||||
RenderSystem.applyModelViewMatrix()
|
||||
RenderSystem.depthFunc(GL11.GL_LESS)
|
||||
|
||||
// Thanks Mojang
|
||||
// Very cool
|
||||
// (for int x, int y, which are then cast into doubles anyway)
|
||||
screen.itemRenderer.blitOffset = 1f // Z pos
|
||||
|
||||
screen.itemRenderer.renderAndDecorateItem(
|
||||
requireNotNull(minecraft.player) { "yo, dude, what the fuck" },
|
||||
itemstack,
|
||||
0,
|
||||
0,
|
||||
(absoluteX + absoluteY * 1000f).toInt()
|
||||
)
|
||||
|
||||
RenderSystem.depthFunc(GL11.GL_ALWAYS)
|
||||
screen.itemRenderer.renderGuiItemDecorations(screen.font, itemstack, 0, 0, count_override)
|
||||
screen.itemRenderer.blitOffset = 0f
|
||||
|
||||
// too big accumulations can lead to Z near clipping issues
|
||||
systemPoseStack.popPose()
|
||||
RenderSystem.applyModelViewMatrix()
|
||||
|
||||
screen.renderItemStack(absoluteX, absoluteY, itemstack, countOverride)
|
||||
clearDepth(stack)
|
||||
}
|
||||
|
||||
|
@ -139,16 +139,15 @@ class ItemMonitorScreen(menu: ItemMonitorMenu, inventory: Inventory, title: Comp
|
||||
|
||||
val refillPriority = SmallEnumRectangleButtonPanel(this, arrowLine,
|
||||
enum = ItemMonitorPlayerSettings.IngredientPriority::class.java,
|
||||
prop = menu.settings::ingredientPriority.asGetterSetter(),
|
||||
defaultValue = ItemMonitorPlayerSettings.IngredientPriority.SYSTEM,
|
||||
onChange = { menu.sendSettingsToServer() })
|
||||
prop = menu.settings::ingredientPriority.asGetterSetter(watch = { _, _ -> menu.sendSettingsToServer() }),
|
||||
defaultValue = ItemMonitorPlayerSettings.IngredientPriority.SYSTEM)
|
||||
|
||||
refillPriority.mainTooltip = TranslatableComponent("otm.gui.item_monitor.refill_source.desc")
|
||||
refillPriority.add(ItemMonitorPlayerSettings.IngredientPriority.SYSTEM, ItemMonitorPlayerSettings.IngredientPriority.SYSTEM.component, Widgets8.WHITE_ARROW_DOWN, UVWindingOrder.FLIP)
|
||||
refillPriority.add(ItemMonitorPlayerSettings.IngredientPriority.INVENTORY, ItemMonitorPlayerSettings.IngredientPriority.INVENTORY.component, Widgets8.WHITE_ARROW_DOWN)
|
||||
refillPriority.add(ItemMonitorPlayerSettings.IngredientPriority.INVENTORY_FIRST, ItemMonitorPlayerSettings.IngredientPriority.INVENTORY_FIRST.component, Widgets8.ARROW_SIDEWAYS, UVWindingOrder.FLIP)
|
||||
refillPriority.add(ItemMonitorPlayerSettings.IngredientPriority.SYSTEM_FIRST, ItemMonitorPlayerSettings.IngredientPriority.SYSTEM_FIRST.component, Widgets8.ARROW_SIDEWAYS)
|
||||
refillPriority.add(ItemMonitorPlayerSettings.IngredientPriority.DO_NOT, ItemMonitorPlayerSettings.IngredientPriority.DO_NOT.component, Widgets8.MINUS)
|
||||
refillPriority.tooltip = TranslatableComponent("otm.gui.item_monitor.refill_source.desc")
|
||||
refillPriority.add(ItemMonitorPlayerSettings.IngredientPriority.SYSTEM, tooltip = ItemMonitorPlayerSettings.IngredientPriority.SYSTEM.component, skinElement = Widgets8.WHITE_ARROW_DOWN, winding = UVWindingOrder.FLIP)
|
||||
refillPriority.add(ItemMonitorPlayerSettings.IngredientPriority.INVENTORY, tooltip = ItemMonitorPlayerSettings.IngredientPriority.INVENTORY.component, skinElement = Widgets8.WHITE_ARROW_DOWN)
|
||||
refillPriority.add(ItemMonitorPlayerSettings.IngredientPriority.INVENTORY_FIRST, tooltip = ItemMonitorPlayerSettings.IngredientPriority.INVENTORY_FIRST.component, skinElement = Widgets8.ARROW_SIDEWAYS, winding = UVWindingOrder.FLIP)
|
||||
refillPriority.add(ItemMonitorPlayerSettings.IngredientPriority.SYSTEM_FIRST, tooltip = ItemMonitorPlayerSettings.IngredientPriority.SYSTEM_FIRST.component, skinElement = Widgets8.ARROW_SIDEWAYS)
|
||||
refillPriority.add(ItemMonitorPlayerSettings.IngredientPriority.DO_NOT, tooltip = ItemMonitorPlayerSettings.IngredientPriority.DO_NOT.component, skinElement = Widgets8.MINUS)
|
||||
|
||||
refillPriority.dock = Dock.LEFT
|
||||
|
||||
@ -161,25 +160,23 @@ class ItemMonitorScreen(menu: ItemMonitorMenu, inventory: Inventory, title: Comp
|
||||
|
||||
val resultTarget = SmallEnumRectangleButtonPanel(this, resultAndButtons, y = 38f,
|
||||
enum = ItemMonitorPlayerSettings.ResultTarget::class.java,
|
||||
prop = menu.settings::resultTarget.asGetterSetter(),
|
||||
defaultValue = ItemMonitorPlayerSettings.ResultTarget.MIXED,
|
||||
onChange = { menu.sendSettingsToServer() })
|
||||
prop = menu.settings::resultTarget.asGetterSetter(watch = { _, _ -> menu.sendSettingsToServer() }),
|
||||
defaultValue = ItemMonitorPlayerSettings.ResultTarget.MIXED)
|
||||
|
||||
resultTarget.mainTooltip = TranslatableComponent("otm.gui.item_monitor.result_target.desc")
|
||||
resultTarget.add(ItemMonitorPlayerSettings.ResultTarget.MIXED, ItemMonitorPlayerSettings.ResultTarget.MIXED.component, Widgets8.ARROW_SIDEWAYS)
|
||||
resultTarget.add(ItemMonitorPlayerSettings.ResultTarget.ALL_INVENTORY, ItemMonitorPlayerSettings.ResultTarget.ALL_INVENTORY.component, Widgets8.ARROW_PAINTED_UP, UVWindingOrder.FLIP)
|
||||
resultTarget.add(ItemMonitorPlayerSettings.ResultTarget.ALL_SYSTEM, ItemMonitorPlayerSettings.ResultTarget.ALL_SYSTEM.component, Widgets8.ARROW_PAINTED_UP)
|
||||
resultTarget.tooltip = TranslatableComponent("otm.gui.item_monitor.result_target.desc")
|
||||
resultTarget.add(ItemMonitorPlayerSettings.ResultTarget.MIXED, tooltip = ItemMonitorPlayerSettings.ResultTarget.MIXED.component, skinElement = Widgets8.ARROW_SIDEWAYS)
|
||||
resultTarget.add(ItemMonitorPlayerSettings.ResultTarget.ALL_INVENTORY, tooltip = ItemMonitorPlayerSettings.ResultTarget.ALL_INVENTORY.component, skinElement = Widgets8.ARROW_PAINTED_UP, winding = UVWindingOrder.FLIP)
|
||||
resultTarget.add(ItemMonitorPlayerSettings.ResultTarget.ALL_SYSTEM, tooltip = ItemMonitorPlayerSettings.ResultTarget.ALL_SYSTEM.component, skinElement = Widgets8.ARROW_PAINTED_UP)
|
||||
|
||||
val craftingAmount = SmallEnumRectangleButtonPanel(this, resultAndButtons, x = 10f, y = 38f,
|
||||
enum = ItemMonitorPlayerSettings.Amount::class.java,
|
||||
prop = menu.settings::craftingAmount.asGetterSetter(),
|
||||
defaultValue = ItemMonitorPlayerSettings.Amount.STACK,
|
||||
onChange = { menu.sendSettingsToServer() })
|
||||
prop = menu.settings::craftingAmount.asGetterSetter(watch = { _, _ -> menu.sendSettingsToServer() }),
|
||||
defaultValue = ItemMonitorPlayerSettings.Amount.STACK)
|
||||
|
||||
craftingAmount.mainTooltip = TranslatableComponent("otm.gui.item_monitor.amount.desc")
|
||||
craftingAmount.add(ItemMonitorPlayerSettings.Amount.ONE, ItemMonitorPlayerSettings.Amount.ONE.component, Widgets8.ONE)
|
||||
craftingAmount.add(ItemMonitorPlayerSettings.Amount.STACK, ItemMonitorPlayerSettings.Amount.STACK.component, Widgets8.S)
|
||||
craftingAmount.add(ItemMonitorPlayerSettings.Amount.FULL, ItemMonitorPlayerSettings.Amount.FULL.component, Widgets8.F)
|
||||
craftingAmount.tooltip = TranslatableComponent("otm.gui.item_monitor.amount.desc")
|
||||
craftingAmount.add(ItemMonitorPlayerSettings.Amount.ONE, tooltip = ItemMonitorPlayerSettings.Amount.ONE.component, skinElement = Widgets8.ONE)
|
||||
craftingAmount.add(ItemMonitorPlayerSettings.Amount.STACK, tooltip = ItemMonitorPlayerSettings.Amount.STACK.component, skinElement = Widgets8.S)
|
||||
craftingAmount.add(ItemMonitorPlayerSettings.Amount.FULL, tooltip = ItemMonitorPlayerSettings.Amount.FULL.component, skinElement = Widgets8.F)
|
||||
|
||||
val craftingHistory = GridPanel(this, bottomPanel, width = 3 * 18f, height = 3 * 18f, columns = 3, rows = 3)
|
||||
craftingHistory.dock = Dock.LEFT
|
||||
|
@ -66,5 +66,28 @@ interface GetterSetter<V> : Supplier<V>, Consumer<V>, ReadWriteProperty<Any?, V>
|
||||
}
|
||||
}
|
||||
|
||||
fun <V> KMutableProperty0<V>.asGetterSetter() = GetterSetter.of(this)
|
||||
fun <V> KMutableProperty0<V>.asGetterSetter(watch: ((old: V, new: V) -> Unit)? = null): GetterSetter<V> {
|
||||
return GetterSetter.of(this).let {
|
||||
if (watch != null) {
|
||||
it.watch(watch)
|
||||
} else {
|
||||
it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun <V> GetterSetter<V>.watch(watch: (old: V, new: V) -> Unit): GetterSetter<V> {
|
||||
return object : GetterSetter<V> {
|
||||
override fun get(): V {
|
||||
return this@watch.get()
|
||||
}
|
||||
|
||||
override fun accept(t: V) {
|
||||
val old = get()
|
||||
this@watch.accept(t)
|
||||
watch.invoke(old, t)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun <V> KMutableProperty0<V>.asGetterOnly() = GetterSetter.of(Supplier { this.get() }, Consumer { /* do nothing */ })
|
||||
|
@ -76,7 +76,8 @@ val VarLongValueCodec = StreamCodec(DataInputStream::readVarLongLE, DataOutputSt
|
||||
val BinaryStringCodec = StreamCodec(DataInputStream::readBinaryString, DataOutputStream::writeBinaryString)
|
||||
|
||||
class EnumValueCodec<V : Enum<V>>(clazz: Class<out V>, val writeByIndices: Boolean = false) : IStreamCodec<V> {
|
||||
private val values = search(clazz) ?: throw ClassCastException("$clazz does not have enum constants. Not an enum?")
|
||||
val clazz = searchClass(clazz)
|
||||
private val values = searchClass(clazz).enumConstants!!
|
||||
|
||||
override fun read(stream: DataInputStream): V {
|
||||
if (writeByIndices) {
|
||||
@ -109,14 +110,18 @@ class EnumValueCodec<V : Enum<V>>(clazz: Class<out V>, val writeByIndices: Boole
|
||||
*
|
||||
* is there an already existing solution?
|
||||
*/
|
||||
fun <V : Enum<V>> search(clazz: Class<out V>): Array<V>? {
|
||||
fun <V : Enum<V>> searchClass(clazz: Class<out V>): Class<out V> {
|
||||
var search: Class<*> = clazz
|
||||
|
||||
while (search.enumConstants == null && search.superclass != null) {
|
||||
search = search.superclass
|
||||
}
|
||||
|
||||
return search.enumConstants as? Array<V>
|
||||
if (search.enumConstants == null) {
|
||||
throw ClassCastException("$clazz does not represent an enum or enum subclass")
|
||||
}
|
||||
|
||||
return search as Class<out V>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,11 @@ package ru.dbotthepony.mc.otm.menu.decorative
|
||||
|
||||
import net.minecraft.world.entity.player.Inventory
|
||||
import net.minecraft.world.inventory.Slot
|
||||
import ru.dbotthepony.mc.otm.block.entity.RedstoneSetting
|
||||
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.EnumInputWithFeedback
|
||||
import ru.dbotthepony.mc.otm.menu.input.StringInputWithFeedback
|
||||
import ru.dbotthepony.mc.otm.registry.MMenus
|
||||
|
||||
@ -15,14 +17,17 @@ class HoloSignMenu @JvmOverloads constructor(
|
||||
) : MatteryMenu(MMenus.HOLO_SIGN, containerId, inventory, tile) {
|
||||
val text = StringInputWithFeedback(this)
|
||||
val locked = BooleanInputWithFeedback(this)
|
||||
val redstone = EnumInputWithFeedback(this, RedstoneSetting::class.java)
|
||||
|
||||
init {
|
||||
text.filter { it.isCreative || !locked.value }
|
||||
redstone.filter { it.isCreative || !locked.value }
|
||||
locked.filter { it.isCreative }
|
||||
|
||||
if (tile != null) {
|
||||
text.withConsumer { if (tile.locked) tile.text = it else tile.text = HoloSignBlockEntity.truncate(it) }.withSupplier(tile::text)
|
||||
locked.with(tile::locked)
|
||||
redstone.with(tile.redstoneControl::redstoneSetting)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,10 @@ interface IPlayerInputWithFeedback<V> : GetterSetter<V>, Predicate<Player?> {
|
||||
}
|
||||
}
|
||||
|
||||
fun <V> of(getterSetter: GetterSetter<V>, filter: Predicate<Player?>): IPlayerInputWithFeedback<V> {
|
||||
return object : IPlayerInputWithFeedback<V>, GetterSetter<V> by getterSetter, Predicate<Player?> by filter {}
|
||||
}
|
||||
|
||||
fun <V> validPlayer(getterSetter: GetterSetter<V>): IPlayerInputWithFeedback<V> {
|
||||
return object : IPlayerInputWithFeedback<V>, GetterSetter<V> by getterSetter {
|
||||
override fun test(t: Player?): Boolean {
|
||||
@ -34,6 +38,10 @@ interface IPlayerInputWithFeedback<V> : GetterSetter<V>, Predicate<Player?> {
|
||||
}
|
||||
}
|
||||
|
||||
fun <V> GetterSetter<V>.wrapAsPlayerInput(filter: Predicate<Player?> = Predicate { it != null }): IPlayerInputWithFeedback<V> {
|
||||
return IPlayerInputWithFeedback.of(this, filter)
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents Server to Client synchronization and Client to Server input
|
||||
*
|
||||
|
@ -0,0 +1,22 @@
|
||||
package ru.dbotthepony.mc.otm.menu.input
|
||||
|
||||
import ru.dbotthepony.mc.otm.core.GetterSetter
|
||||
import ru.dbotthepony.mc.otm.core.util.EnumValueCodec
|
||||
import ru.dbotthepony.mc.otm.menu.MatteryMenu
|
||||
import kotlin.reflect.KMutableProperty0
|
||||
|
||||
class EnumInputWithFeedback<E : Enum<E>>(menu: MatteryMenu, clazz: Class<E>) : AbstractPlayerInputWithFeedback<E>() {
|
||||
val codec = EnumValueCodec(clazz)
|
||||
private val default = codec.clazz.enumConstants!![0]
|
||||
|
||||
override val input = menu.PlayerInput(codec, false) { consumer?.invoke(it) }
|
||||
override val value by menu.mSynchronizer.ComputedField(getter = { supplier?.invoke() ?: default }, codec)
|
||||
|
||||
constructor(menu: MatteryMenu, clazz: Class<E>, state: KMutableProperty0<E>) : this(menu, clazz) {
|
||||
with(state)
|
||||
}
|
||||
|
||||
constructor(menu: MatteryMenu, clazz: Class<E>, state: GetterSetter<E>) : this(menu, clazz) {
|
||||
with(state)
|
||||
}
|
||||
}
|
Binary file not shown.
After Width: | Height: | Size: 736 B |
Binary file not shown.
Loading…
Reference in New Issue
Block a user