Compare commits

...

2 Commits

4 changed files with 251 additions and 27 deletions

View File

@ -14,6 +14,7 @@ import net.shadowfacts.phycon.network.component.NetworkStackProvider
import net.shadowfacts.phycon.network.component.NetworkStackReceiver import net.shadowfacts.phycon.network.component.NetworkStackReceiver
import net.shadowfacts.phycon.network.component.handleItemStack import net.shadowfacts.phycon.network.component.handleItemStack
import net.shadowfacts.phycon.network.packet.* import net.shadowfacts.phycon.network.packet.*
import kotlin.math.min
/** /**
* @author shadowfacts * @author shadowfacts
@ -67,8 +68,16 @@ class InterfaceBlockEntity: DeviceBlockEntity(PhyBlockEntities.INTERFACE),
private fun handleExtractStack(packet: ExtractStackPacket) { private fun handleExtractStack(packet: ExtractStackPacket) {
getInventory()?.also { inv -> getInventory()?.also { inv ->
val extracted = inv.extract(packet.stack, packet.amount) var amount = packet.amount
sendPacket(ItemStackPacket(extracted, ipAddress, packet.source)) while (amount > 0) {
val extracted = inv.extract(packet.stack, min(amount, packet.stack.maxCount))
if (extracted.isEmpty) {
break
} else {
amount -= extracted.count
sendPacket(ItemStackPacket(extracted, ipAddress, packet.source))
}
}
} }
} }

View File

@ -1,11 +1,15 @@
package net.shadowfacts.phycon.network.block.terminal package net.shadowfacts.phycon.network.block.terminal
import com.mojang.blaze3d.platform.GlStateManager import com.mojang.blaze3d.systems.RenderSystem
import net.minecraft.client.MinecraftClient
import net.minecraft.client.gui.DrawableHelper import net.minecraft.client.gui.DrawableHelper
import net.minecraft.client.gui.screen.ingame.HandledScreen import net.minecraft.client.gui.screen.ingame.HandledScreen
import net.minecraft.client.gui.widget.AbstractButtonWidget
import net.minecraft.client.gui.widget.ButtonWidget
import net.minecraft.client.gui.widget.TextFieldWidget import net.minecraft.client.gui.widget.TextFieldWidget
import net.minecraft.client.util.math.MatrixStack import net.minecraft.client.util.math.MatrixStack
import net.minecraft.entity.player.PlayerInventory import net.minecraft.entity.player.PlayerInventory
import net.minecraft.item.ItemStack
import net.minecraft.screen.slot.Slot import net.minecraft.screen.slot.Slot
import net.minecraft.screen.slot.SlotActionType import net.minecraft.screen.slot.SlotActionType
import net.minecraft.text.LiteralText import net.minecraft.text.LiteralText
@ -13,6 +17,9 @@ import net.minecraft.text.Text
import net.minecraft.util.Identifier import net.minecraft.util.Identifier
import net.shadowfacts.phycon.PhysicalConnectivity import net.shadowfacts.phycon.PhysicalConnectivity
import org.lwjgl.glfw.GLFW import org.lwjgl.glfw.GLFW
import java.lang.NumberFormatException
import kotlin.math.ceil
import kotlin.math.floor
/** /**
* @author shadowfacts * @author shadowfacts
@ -20,10 +27,31 @@ import org.lwjgl.glfw.GLFW
// todo: translate title // todo: translate title
class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory, title: Text): HandledScreen<TerminalScreenHandler>(handler, playerInv, title) { class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory, title: Text): HandledScreen<TerminalScreenHandler>(handler, playerInv, title) {
companion object { companion object {
val BACKGROUND = Identifier(PhysicalConnectivity.MODID, "textures/gui/terminal.png") private val BACKGROUND = Identifier(PhysicalConnectivity.MODID, "textures/gui/terminal.png")
private val DIALOG = Identifier(PhysicalConnectivity.MODID, "textures/gui/terminal_amount.png")
} }
private lateinit var searchBox: TextFieldWidget private lateinit var searchBox: TextFieldWidget
private lateinit var amountBox: TextFieldWidget
private var dialogStack = ItemStack.EMPTY
private var showingAmountDialog = false
set(value) {
val oldValue = field
field = value
for (e in dialogChildren) {
e.visible = value
}
amountBox.isVisible
searchBox.setSelected(!value)
amountBox.setSelected(value)
if (value && !oldValue) {
amountBox.text = "1"
}
}
private var dialogChildren = mutableListOf<AbstractButtonWidget>()
private val dialogWidth = 158
private val dialogHeight = 62
init { init {
backgroundWidth = 252 backgroundWidth = 252
@ -33,6 +61,9 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory,
override fun init() { override fun init() {
super.init() super.init()
children.clear()
dialogChildren.clear()
client!!.keyboard.setRepeatEvents(true) client!!.keyboard.setRepeatEvents(true)
searchBox = TextFieldWidget(textRenderer, x + 138, y + 6, 80, 9, LiteralText("Search")) searchBox = TextFieldWidget(textRenderer, x + 138, y + 6, 80, 9, LiteralText("Search"))
@ -43,11 +74,68 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory,
searchBox.setSelected(true) searchBox.setSelected(true)
searchBox.setEditableColor(0xffffff) searchBox.setEditableColor(0xffffff)
children.add(searchBox) children.add(searchBox)
val dialogMinX = width / 2 - dialogWidth / 2
val dialogMinY = height / 2 - dialogHeight / 2
amountBox = TextFieldWidget(textRenderer, dialogMinX + 8, dialogMinY + 27, 80, 9, LiteralText("Amount"))
amountBox.setHasBorder(false)
amountBox.isVisible = false
amountBox.setSelected(false)
amountBox.setEditableColor(0xffffff)
amountBox.setTextPredicate {
if (it.isEmpty()) {
true
} else {
try {
Integer.parseInt(it) > 0
} catch (e: NumberFormatException) {
false
}
}
}
dialogChildren.add(amountBox)
val plusOne = SmallButton(dialogMinX + 7, dialogMinY + 7, 28, LiteralText("+1")) {
amountBox.intValue += 1
}
dialogChildren.add(plusOne)
val plusTen = SmallButton(dialogMinX + 7 + 28 + 3, dialogMinY + 7, 28, LiteralText("+10")) {
amountBox.intValue = ceil((amountBox.intValue + 1) / 10.0).toInt() * 10
}
dialogChildren.add(plusTen)
val plusHundred = SmallButton(dialogMinX + 7 + (28 + 3) * 2, dialogMinY + 7, 28, LiteralText("+100")) {
amountBox.intValue = ceil((amountBox.intValue + 1) / 100.0).toInt() * 100
}
dialogChildren.add(plusHundred)
val minusOne = SmallButton(dialogMinX + 7, dialogMinY + 39, 28, LiteralText("-1")) {
amountBox.intValue -= 1
}
dialogChildren.add(minusOne)
val minusTen = SmallButton(dialogMinX + 7 + 28 + 3, dialogMinY + 39, 28, LiteralText("-10")) {
amountBox.intValue = floor((amountBox.intValue - 1) / 10.0).toInt() * 10
}
dialogChildren.add(minusTen)
val minusHundred = SmallButton(dialogMinX + 7 + (28 + 3) * 2, dialogMinY + 39, 28, LiteralText("-100")) {
amountBox.intValue = floor((amountBox.intValue - 1) / 100.0).toInt() * 100
}
dialogChildren.add(minusHundred)
// 101,25
val request = ButtonWidget(dialogMinX + 101, dialogMinY + 21, 50, 20, LiteralText("Request")) {
doDialogRequest()
}
dialogChildren.add(request)
} }
override fun tick() { override fun tick() {
super.tick() super.tick()
searchBox.tick() searchBox.tick()
amountBox.tick()
} }
override fun drawForeground(matrixStack: MatrixStack, mouseX: Int, mouseY: Int) { override fun drawForeground(matrixStack: MatrixStack, mouseX: Int, mouseY: Int) {
@ -58,21 +146,50 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory,
} }
override fun drawBackground(matrixStack: MatrixStack, delta: Float, mouseX: Int, mouseY: Int) { override fun drawBackground(matrixStack: MatrixStack, delta: Float, mouseX: Int, mouseY: Int) {
renderBackground(matrixStack) // if the dialog is open, the background gradient will be drawn in front of the main terminal gui
if (!showingAmountDialog) {
renderBackground(matrixStack)
}
GlStateManager.color4f(1f, 1f, 1f, 1f) RenderSystem.color4f(1f, 1f, 1f, 1f)
client!!.textureManager.bindTexture(BACKGROUND) client!!.textureManager.bindTexture(BACKGROUND)
val x = (width - backgroundWidth) / 2 val x = (width - backgroundWidth) / 2
val y = (height - backgroundHeight) / 2 val y = (height - backgroundHeight) / 2
drawTexture(matrixStack, x, y, 0, 0, backgroundWidth, backgroundHeight) drawTexture(matrixStack, x, y, 0, 0, backgroundWidth, backgroundHeight)
} }
@ExperimentalUnsignedTypes
override fun render(matrixStack: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) { override fun render(matrixStack: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) {
super.render(matrixStack, mouseX, mouseY, delta) if (showingAmountDialog) {
RenderSystem.pushMatrix()
// items are rendered at some stupidly high z offset. item amounts at an even higher one
RenderSystem.translatef(0f, 0f, -350f)
// fake the mouse x/y while showing a dialog so slot mouseover highlights aren't drawn
super.render(matrixStack, -1, -1, delta)
RenderSystem.popMatrix()
} else {
super.render(matrixStack, mouseX, mouseY, delta)
}
searchBox.render(matrixStack, mouseX, mouseY, delta) searchBox.render(matrixStack, mouseX, mouseY, delta)
drawMouseoverTooltip(matrixStack, mouseX, mouseY) if (showingAmountDialog) {
renderBackground(matrixStack)
RenderSystem.color4f(1f, 1f, 1f, 1f)
client!!.textureManager.bindTexture(DIALOG)
val dialogMinX = width / 2 - dialogWidth / 2
val dialogMinY = height / 2 - dialogHeight / 2
drawTexture(matrixStack, dialogMinX, dialogMinY, 0, 0, dialogWidth, dialogHeight)
for (e in dialogChildren) {
e.render(matrixStack, mouseX, mouseY, delta)
}
} else {
drawMouseoverTooltip(matrixStack, mouseX, mouseY)
}
} }
@ExperimentalUnsignedTypes @ExperimentalUnsignedTypes
@ -90,37 +207,107 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory,
DrawableHelper.fill(matrixStack, slot.x, slot.y, slot.x + 16, slot.y + 16, color.toInt()) DrawableHelper.fill(matrixStack, slot.x, slot.y, slot.x + 16, slot.y + 16, color.toInt())
} }
override fun onMouseClick(slot: Slot?, i: Int, j: Int, slotActionType: SlotActionType?) { override fun onMouseClick(slot: Slot?, invSlot: Int, clickData: Int, type: SlotActionType?) {
super.onMouseClick(slot, i, j, slotActionType) super.onMouseClick(slot, invSlot, clickData, type)
// don't unfocus the search box on mouse click // don't unfocus the search box on mouse click
searchBox.setSelected(true) searchBox.setSelected(true)
if (type == SlotActionType.PICKUP && clickData == 0 && slot != null && handler.isNetworkSlot(slot.id) && !slot.stack.isEmpty) {
dialogStack = slot.stack
showingAmountDialog = true
searchBox.setSelected(false)
}
}
override fun mouseClicked(mouseX: Double, mouseY: Double, button: Int): Boolean {
if (showingAmountDialog) {
for (e in dialogChildren) {
if (e.mouseClicked(mouseX, mouseY, button)) {
return true
}
}
return false
} else {
return super.mouseClicked(mouseX, mouseY, button)
}
}
override fun mouseDragged(d: Double, e: Double, i: Int, f: Double, g: Double): Boolean {
if (showingAmountDialog) {
return false
} else {
return super.mouseDragged(d, e, i, f, g)
}
}
override fun mouseMoved(d: Double, e: Double) {
if (showingAmountDialog) {
} else {
super.mouseMoved(d, e)
}
}
override fun mouseReleased(d: Double, e: Double, i: Int): Boolean {
if (showingAmountDialog) {
return false
} else {
return super.mouseReleased(d, e, i)
}
}
override fun mouseScrolled(d: Double, e: Double, f: Double): Boolean {
if (showingAmountDialog) {
return false
} else {
return super.mouseScrolled(d, e, f)
}
} }
override fun charTyped(c: Char, i: Int): Boolean { override fun charTyped(c: Char, i: Int): Boolean {
val oldText = searchBox.text if (showingAmountDialog) {
if (searchBox.charTyped(c, i)) { return amountBox.charTyped(c, i)
if (searchBox.text != oldText) { } else {
search() val oldText = searchBox.text
if (searchBox.charTyped(c, i)) {
if (searchBox.text != oldText) {
search()
}
return true
} }
return true
}
return super.charTyped(c, i) return super.charTyped(c, i)
}
} }
override fun keyPressed(key: Int, j: Int, k: Int): Boolean { override fun keyPressed(key: Int, j: Int, k: Int): Boolean {
val oldText = searchBox.text if (showingAmountDialog) {
if (searchBox.keyPressed(key, j, k)) { return when (key) {
if (searchBox.text != oldText) { GLFW.GLFW_KEY_ESCAPE -> {
search() showingAmountDialog = false
true
}
GLFW.GLFW_KEY_ENTER -> {
doDialogRequest()
true
}
else -> {
amountBox.keyPressed(key, j, k)
}
} }
return true
}
return if (searchBox.isFocused && searchBox.isVisible && key != GLFW.GLFW_KEY_ESCAPE) {
true
} else { } else {
super.keyPressed(key, j, k) val oldText = searchBox.text
if (searchBox.keyPressed(key, j, k)) {
if (searchBox.text != oldText) {
search()
}
return true
}
return if (searchBox.isFocused && searchBox.isVisible && key != GLFW.GLFW_KEY_ESCAPE) {
true
} else {
super.keyPressed(key, j, k)
}
} }
} }
@ -128,4 +315,32 @@ class TerminalScreen(handler: TerminalScreenHandler, playerInv: PlayerInventory,
screenHandler.search(searchBox.text) screenHandler.search(searchBox.text)
} }
private fun doDialogRequest() {
showingAmountDialog = false
handler.requestItem(client!!.player!!, dialogStack, amountBox.intValue)
}
private var TextFieldWidget.intValue: Int
get() = if (text.isEmpty()) 0 else Integer.parseInt(text)
set(value) {
text = value.toString()
setSelected(true)
}
class SmallButton(x: Int, y: Int, width: Int, title: Text, action: PressAction): ButtonWidget(x, y, width, 14, title, action) {
@ExperimentalUnsignedTypes
override fun renderButton(matrixStack: MatrixStack, mouseX: Int, mouseY: Int, delta: Float) {
val client = MinecraftClient.getInstance()
client.textureManager.bindTexture(DIALOG)
RenderSystem.color4f(1f, 1f, 1f, 1f)
val v = if (isHovered) 142 else 128
RenderSystem.enableBlend()
RenderSystem.defaultBlendFunc()
RenderSystem.enableDepthTest()
drawTexture(matrixStack, x, y, 0, v, width / 2, height)
drawTexture(matrixStack, x + width / 2, y, 200 - width / 2, v, width / 2, height)
drawCenteredText(matrixStack, client.textRenderer, message, x + width / 2, y + (height - 8) / 2, 0xffffffffu.toInt())
}
}
} }

View File

@ -134,7 +134,7 @@ class TerminalScreenHandler(syncId: Int, playerInv: PlayerInventory, val termina
return super.onSlotClick(slotId, clickData, actionType, player) return super.onSlotClick(slotId, clickData, actionType, player)
} }
private fun requestItem(player: PlayerEntity, stack: ItemStack, amount: Int) { fun requestItem(player: PlayerEntity, stack: ItemStack, amount: Int) {
if (!player.world.isClient) return if (!player.world.isClient) return
val handler = (player as ClientPlayerEntity).networkHandler val handler = (player as ClientPlayerEntity).networkHandler
val packet = C2STerminalRequestItem(terminal, stack, amount) val packet = C2STerminalRequestItem(terminal, stack, amount)

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB