Add the ability to change P2P types from the GUI

This commit is contained in:
Firenoo committed 2023-05-13 08:14:46 -07:00
1 parent d7f40e33af
commit 74b7698abc
8 files changed
+322 -48

No files matched your search

@@ -1,6 +1,8 @@
package com.projecturanus.betterp2p.client.gui
import appeng.client.gui.widgets.MEGuiTextField
import appeng.parts.p2p.PartP2PGT5Power
import appeng.parts.p2p.PartP2PInterface
import appeng.parts.p2p.PartP2PLiquids
import appeng.parts.p2p.PartP2PRedstone
import appeng.parts.p2p.PartP2PTunnelME
@@ -15,6 +17,7 @@ import com.projecturanus.betterp2p.item.BetterMemoryCardModes
import com.projecturanus.betterp2p.item.MAX_TOOLTIP_LENGTH
import com.projecturanus.betterp2p.network.*
import com.projecturanus.betterp2p.util.p2p.ClientTunnelInfo
import com.projecturanus.betterp2p.util.p2p.TunnelInfo
import net.minecraft.client.Minecraft
import net.minecraft.client.gui.FontRenderer
import net.minecraft.client.gui.GuiScreen
@@ -29,12 +32,7 @@ const val GUI_WIDTH = 288
const val GUI_TEX_HEIGHT = 264
class GuiAdvancedMemoryCard(msg: S2CListP2P) : GuiScreen(), TextureBound {
private lateinit var _guiLeft: Lazy<Int>
private var guiLeft: Int
get() = _guiLeft.value
set(value) {
_guiLeft = lazyOf(value)
}
private var guiLeft: Int = 0
private lateinit var _guiTop: Lazy<Int>
private var guiTop: Int
@@ -69,6 +67,8 @@ class GuiAdvancedMemoryCard(msg: S2CListP2P) : GuiScreen(), TextureBound {
private val infos = InfoList(msg.infos.map(::InfoWrapper), ::searchText)
private val typeSelector: WidgetTypeSelector
private val searchText: String
get() = searchBar.text
@@ -163,7 +163,7 @@ class GuiAdvancedMemoryCard(msg: S2CListP2P) : GuiScreen(), TextureBound {
}
}
typeButton = object: WidgetButton(this, 0, 0, 32, 32) {
typeButton = object: WidgetButton(this, 0, 0, 32, 32), ITypeReceiver {
val types = BetterP2P.proxy.getP2PTypeList()
private var index =
if (type != null) {
@@ -177,7 +177,9 @@ class GuiAdvancedMemoryCard(msg: S2CListP2P) : GuiScreen(), TextureBound {
init {
hoverText = if (type == null) {
mutableListOf(I18n.format("gui.advanced_memory_card.types.any"))
mutableListOf(
I18n.format("gui.advanced_memory_card.types.filtered",
I18n.format("gui.advanced_memory_card.types.any")))
} else {
mutableListOf(
I18n.format("gui.advanced_memory_card.types.filtered", "§a" + type!!.stack.displayName))
@@ -199,17 +201,12 @@ class GuiAdvancedMemoryCard(msg: S2CListP2P) : GuiScreen(), TextureBound {
if (super.mousePressed(mc, mouseX, mouseY)) {
if (button == 1) {
// open type selector?
openTypeSelector(this, true)
return
} else {
type = nextType(false)
}
if (type == null) {
(hoverText as MutableList)[0] = I18n.format("gui.advanced_memory_card.types.any")
} else {
(hoverText as MutableList)[0] =
I18n.format("gui.advanced_memory_card.types.filtered", "§a" + type!!.stack.displayName)
}
ModNetwork.channel.sendToServer(C2SRefreshP2PList(type?.index ?: TUNNEL_ANY))
super.func_146113_a(mc.soundHandler)
commitType()
}
}
@@ -240,6 +237,32 @@ class GuiAdvancedMemoryCard(msg: S2CListP2P) : GuiScreen(), TextureBound {
height = 18.0)
}
}
private fun commitType() {
if (type == null) {
(hoverText as MutableList)[0] = I18n.format("gui.advanced_memory_card.types.any")
} else {
(hoverText as MutableList)[0] =
I18n.format("gui.advanced_memory_card.types.filtered", "§a" + type!!.stack.displayName)
}
ModNetwork.channel.sendToServer(C2SRefreshP2PList(type?.index ?: TUNNEL_ANY))
super.func_146113_a(mc.soundHandler)
}
override fun accept(type: ClientTunnelInfo?) {
this.index = type?.index ?: TUNNEL_ANY
gui.type = type
commitType()
gui.closeTypeSelector()
}
override fun x(): Int {
return guiLeft
}
override fun y(): Int {
return this.yPosition
}
}
refreshButton = object: WidgetButton(this, 0, 0, 32, 32) {
@@ -249,6 +272,31 @@ class GuiAdvancedMemoryCard(msg: S2CListP2P) : GuiScreen(), TextureBound {
}
}
}
val typeSelectorList = mutableListOf<ClientTunnelInfo>()
var toAdd = BetterP2P.proxy.getP2PFromClass(PartP2PTunnelME::class.java) as? ClientTunnelInfo
if (toAdd != null) {
typeSelectorList.add(toAdd)
}
toAdd = BetterP2P.proxy.getP2PFromClass(PartP2PLiquids::class.java) as? ClientTunnelInfo
if (toAdd != null) {
typeSelectorList.add(toAdd)
}
toAdd = BetterP2P.proxy.getP2PFromClass(PartP2PGT5Power::class.java) as? ClientTunnelInfo
if (toAdd != null) {
typeSelectorList.add(toAdd)
}
toAdd = BetterP2P.proxy.getP2PFromClass(PartP2PInterface::class.java) as? ClientTunnelInfo
if (toAdd != null) {
typeSelectorList.add(toAdd)
}
BetterP2P.proxy.getP2PTypeList().forEach {
if (!typeSelectorList.contains(it)) {
typeSelectorList.add(it as ClientTunnelInfo)
}
}
typeSelector = WidgetTypeSelector(0, 0, typeSelectorList)
typeSelector.parent = typeButton
}
/**
@@ -295,12 +343,28 @@ class GuiAdvancedMemoryCard(msg: S2CListP2P) : GuiScreen(), TextureBound {
refreshButton.setTexCoords(32 * 5.0, 200.0)
buttonList.add(refreshButton)
if (typeSelector.parent != typeButton) {
closeTypeSelector()
} else {
typeSelector.setPos(typeSelector.parent.x(), typeSelector.parent.y())
}
infos.refresh()
checkInfo()
refreshOverlay()
col.entries.forEach { it.updateButtonVisibility() }
}
fun openTypeSelector(parent: ITypeReceiver, useAny: Boolean) {
typeSelector.parent = parent
typeSelector.setPos(parent.x(), parent.y())
typeSelector.useAny = useAny
typeSelector.visible = true
}
fun closeTypeSelector() {
typeSelector.visible = false
}
private fun checkInfo() {
// A P2P entry is considered "errored" if it is an output, and has no inputs.
infos.filtered.forEach {
@@ -347,9 +411,13 @@ class GuiAdvancedMemoryCard(msg: S2CListP2P) : GuiScreen(), TextureBound {
GL11.glColor3f(255f, 255f, 255f)
scrollBar.draw(this)
col.render(this, mouseX, mouseY, partialTicks)
col.render(mouseX, mouseY, partialTicks)
// The GL state is already messed up here by string drawing but oh well
GL11.glPopAttrib()
if (typeSelector.visible) {
typeSelector.render(this, mouseX, mouseY, partialTicks)
return
}
var drewHoverText = false
run finished@ {
buttonList.forEach { it as WidgetButton
@@ -397,6 +465,10 @@ class GuiAdvancedMemoryCard(msg: S2CListP2P) : GuiScreen(), TextureBound {
}
override fun mouseClicked(mouseX: Int, mouseY: Int, mouseButton: Int) {
if (typeSelector.visible) {
typeSelector.mousePressed(mouseX, mouseY, mouseButton)
return
}
col.mouseClicked(mouseX, mouseY, mouseButton)
scrollBar.click(mouseX, mouseY)
buttonList.forEach {it as WidgetButton
@@ -474,6 +546,10 @@ class GuiAdvancedMemoryCard(msg: S2CListP2P) : GuiScreen(), TextureBound {
}
override fun keyTyped(char: Char, key: Int) {
if (key == Keyboard.KEY_ESCAPE && typeSelector.visible) {
closeTypeSelector()
return
}
if (key == Keyboard.KEY_LSHIFT || col.keyTyped(char, key)) return
if (!(char.isWhitespace() && searchBar.text.isEmpty()) && searchBar.textboxKeyTyped(char, key)){
infos.refilter()
@@ -38,9 +38,9 @@ class WidgetP2PColumn(private val gui: GuiAdvancedMemoryCard,
fun resize(scale: GuiScale, availableHeight: Int) {
entries.clear()
for (i in 0 until scale.size(availableHeight)) {
val widget = WidgetP2PDevice( selectedInfo, mode,
val widget = WidgetP2PDevice(selectedInfo, mode,
{ infos.filtered.getOrNull(i + scrollBar.currentScroll) },
x, y + i * (P2PEntryConstants.HEIGHT + 1))
gui, x, y + i * (P2PEntryConstants.HEIGHT + 1))
entries.add(widget)
}
}
@@ -90,8 +90,12 @@ class WidgetP2PColumn(private val gui: GuiAdvancedMemoryCard,
renameBar.info = info
}
private fun onSelectButtonClicked(info: InfoWrapper) {
gui.selectInfo(info.code)
private fun onSelectButtonClicked(widget: WidgetP2PDevice, info: InfoWrapper, mouseButton: Int) {
if (mouseButton == 1) {
gui.openTypeSelector(widget, false)
} else if (selectedInfo.get() != info) {
gui.selectInfo(info.code)
}
info.bindButton.func_146113_a(gui.mc.soundHandler)
}
@@ -150,8 +154,8 @@ class WidgetP2PColumn(private val gui: GuiAdvancedMemoryCard,
clickRenameButton = true
} else if (mouseX > widget.x && mouseX < widget.x + P2PEntryConstants.WIDTH &&
mouseY > widget.y && mouseY < widget.y + P2PEntryConstants.HEIGHT &&
info != null && selectedInfo.get() != info) {
onSelectButtonClicked(info)
info != null) {
onSelectButtonClicked(widget, info, mouseButton)
}
}
renameBar.mouseClicked(mouseX,mouseY,mouseButton)
@@ -192,9 +196,9 @@ class WidgetP2PColumn(private val gui: GuiAdvancedMemoryCard,
return false
}
fun render(gui: GuiAdvancedMemoryCard, mouseX: Int, mouseY: Int, partialTicks: Float) {
fun render(mouseX: Int, mouseY: Int, partialTicks: Float) {
for (widget in entries) {
widget.render(gui, mouseX, mouseY, partialTicks)
widget.render(mouseX, mouseY, partialTicks)
}
renameBar.drawTextBox()
}
@@ -1,7 +1,12 @@
package com.projecturanus.betterp2p.client.gui.widget
import com.projecturanus.betterp2p.capability.TUNNEL_ANY
import com.projecturanus.betterp2p.client.gui.*
import com.projecturanus.betterp2p.item.BetterMemoryCardModes
import com.projecturanus.betterp2p.network.C2STypeChange
import com.projecturanus.betterp2p.network.ModNetwork
import com.projecturanus.betterp2p.util.p2p.ClientTunnelInfo
import com.projecturanus.betterp2p.util.p2p.TunnelInfo
import net.minecraft.client.gui.GuiScreen
import net.minecraft.client.renderer.Tessellator
import net.minecraft.client.resources.I18n
@@ -18,7 +23,11 @@ object P2PEntryConstants {
const val LEFT_ALIGN = 24
}
class WidgetP2PDevice(private val selectedInfoProperty: KProperty0<InfoWrapper?>, val modeSupplier: () -> BetterMemoryCardModes, val infoSupplier: () -> InfoWrapper?, var x: Int, var y: Int): Widget() {
class WidgetP2PDevice(private val selectedInfoProperty: KProperty0<InfoWrapper?>,
val modeSupplier: () -> BetterMemoryCardModes,
val infoSupplier: () -> InfoWrapper?,
val gui: GuiAdvancedMemoryCard,
var x: Int, var y: Int): Widget(), ITypeReceiver {
var renderNameTextField = true
@@ -56,7 +65,7 @@ class WidgetP2PDevice(private val selectedInfoProperty: KProperty0<InfoWrapper?>
}
}
fun render(gui: GuiAdvancedMemoryCard, mouseX: Int, mouseY: Int, partialTicks: Float) {
fun render(mouseX: Int, mouseY: Int, partialTicks: Float) {
val info = infoSupplier()
if (info != null) {
// Draw the background first
@@ -127,4 +136,17 @@ class WidgetP2PDevice(private val selectedInfoProperty: KProperty0<InfoWrapper?>
info.unbindButton.drawButton(gui.mc, mouseX, mouseY)
}
}
override fun accept(type: ClientTunnelInfo?) {
ModNetwork.channel.sendToServer(C2STypeChange(type?.index ?: TUNNEL_ANY, infoSupplier()!!.code))
gui.closeTypeSelector()
}
override fun x(): Int {
return this.x + 40
}
override fun y(): Int {
return this.y
}
}
@@ -0,0 +1,96 @@
package com.projecturanus.betterp2p.client.gui.widget
import com.projecturanus.betterp2p.client.gui.GuiAdvancedMemoryCard
import com.projecturanus.betterp2p.client.gui.drawBlockIcon
import com.projecturanus.betterp2p.util.p2p.ClientTunnelInfo
import com.projecturanus.betterp2p.util.p2p.TunnelInfo
import net.minecraft.client.gui.GuiScreen
import net.minecraft.client.resources.I18n
import net.minecraft.init.Blocks
import kotlin.math.min
const val ICONS_PER_ROW = 5
/**
* Select a type.
*/
class WidgetTypeSelector(var x: Int, var y: Int,
val p2pTypes: List<ClientTunnelInfo>): Widget() {
var visible = false
val width: Int
val height: Int
var hoveredIdx: Int = 0
var useAny = false
/**
* Feeds the input into this parent.
*/
lateinit var parent: ITypeReceiver
private val translated: List<List<String>>
init {
val typeCount = p2pTypes.size //we'll use 5 icons per row?
width = min(ICONS_PER_ROW, typeCount) * 18 + 8
height = (typeCount + ICONS_PER_ROW - 1) * 18 / ICONS_PER_ROW + 8
val list = p2pTypes.map { listOf(it.dispName) }.toMutableList()
list.add(listOf(I18n.format("gui.advanced_memory_card.types.any")))
translated = list
}
fun render(gui: GuiAdvancedMemoryCard, mouseX: Int, mouseY: Int, partialTicks: Float) {
// Background
GuiScreen.drawRect(x, y, x + width, y + height, 0xAA000000.toInt())
hoveredIdx = -1
for ((i, type) in p2pTypes.withIndex()) {
val iconPosX = x + 4 + (i % ICONS_PER_ROW) * 18
val iconPosY = y + 4 + (i / ICONS_PER_ROW) * 18
val iconHover = mouseX > iconPosX && mouseX < iconPosX + 18 && mouseY > iconPosY && mouseY < iconPosY + 18
if (iconHover) {
hoveredIdx = i
GuiScreen.drawRect(iconPosX, iconPosY, iconPosX + 18, iconPosY + 18, 0xFF00FF00.toInt())
}
drawBlockIcon(gui.mc, type.icon(), type.stack.iconIndex,
x = iconPosX + 1,
y = iconPosY + 1)
}
if (useAny) {
val iconPosX = x + 4 + (p2pTypes.size % ICONS_PER_ROW) * 18
val iconPosY = y + 4 + (p2pTypes.size / ICONS_PER_ROW) * 18
val iconHover = mouseX > iconPosX && mouseX < iconPosX + 18 && mouseY > iconPosY && mouseY < iconPosY + 18
if (iconHover) {
hoveredIdx = p2pTypes.size
GuiScreen.drawRect(iconPosX, iconPosY, iconPosX + 18, iconPosY + 18, 0xFF00FF00.toInt())
}
drawBlockIcon(gui.mc, Blocks.coal_block.getIcon(0, 0), p2pTypes[0].stack.iconIndex,
x = iconPosX + 1,
y = iconPosY + 1)
gui.mc.fontRenderer.drawString("?", iconPosX + 6, iconPosY + 6, 0xFFFF0000.toInt())
}
if (hoveredIdx != -1) {
gui.drawHoveringText(translated[hoveredIdx], mouseX, mouseY, gui.mc.fontRenderer)
}
}
fun setPos(x: Int, y: Int) {
this.x = x
this.y = y
}
fun mousePressed(mouseX: Int, mouseY: Int, mouseButton: Int) {
if (mouseX > x && mouseX < x + width && mouseY > y && mouseY < y + height) {
// now check which one we clicked on
if (hoveredIdx == -1) return
parent.accept(p2pTypes.getOrNull(hoveredIdx))
} else {
this.visible = false
}
}
}
interface ITypeReceiver {
fun accept(type: ClientTunnelInfo?)
fun x(): Int
fun y(): Int
}
@@ -0,0 +1,36 @@
package com.projecturanus.betterp2p.network
import com.projecturanus.betterp2p.BetterP2P
import com.projecturanus.betterp2p.capability.TUNNEL_ANY
import com.projecturanus.betterp2p.util.p2p.P2PCache
import com.projecturanus.betterp2p.util.p2p.changeAllP2Ps
import cpw.mods.fml.common.network.simpleimpl.IMessage
import cpw.mods.fml.common.network.simpleimpl.IMessageHandler
import cpw.mods.fml.common.network.simpleimpl.MessageContext
import io.netty.buffer.ByteBuf
class C2STypeChange(var newType: Int = TUNNEL_ANY, var p2p: Long = NONE_SELECTED): IMessage {
override fun fromBytes(buf: ByteBuf) {
newType = buf.readByte().toInt()
p2p = buf.readLong()
}
override fun toBytes(buf: ByteBuf) {
buf.writeByte(newType)
buf.writeLong(p2p)
}
}
class ServerTypeChangeHandler : IMessageHandler<C2STypeChange, S2CListP2P?> {
override fun onMessage(message: C2STypeChange, ctx: MessageContext): S2CListP2P? {
if (message.newType == TUNNEL_ANY) return null
val status = P2PCache.statusMap[ctx.serverHandler.playerEntity.uniqueID] ?: return null
val tunnel = status.listP2P[message.p2p] ?: return null
val type = BetterP2P.proxy.getP2PFromIndex(message.newType) ?: return null
val newTunnel = changeAllP2Ps(tunnel, type, ctx.serverHandler.playerEntity)
if (newTunnel) {
ModNetwork.queueP2PListUpdate(status, ctx.serverHandler.playerEntity)
}
return null
}
}
@@ -28,6 +28,7 @@ object ModNetwork {
channel.registerMessage(ServerRenameP2PTunnel::class.java, C2SP2PTunnelInfo::class.java, 6, Side.SERVER)
channel.registerMessage(ServerRefreshP2PListHandler::class.java, C2SRefreshP2PList::class.java, 7, Side.SERVER)
channel.registerMessage(ServerUnlinkP2PHandler::class.java, C2SUnlinkP2P::class.java, 8, Side.SERVER)
channel.registerMessage(ServerTypeChangeHandler::class.java, C2STypeChange::class.java, 9, Side.SERVER)
networkWorker = ScheduledThreadPoolExecutor(1, ThreadFactory {
val th = Thread(it)
th.name = "BetterP2P-NetworkWorker"
@@ -36,26 +36,7 @@ fun linkP2P(player: EntityPlayer, inputIndex: Long, outputIndex: Long, status: P
// TODO Change to exception
if (input.javaClass != output.javaClass) {
//change output to input
val host = output.host
host.removePart(output.side, false)
val dir = host.addPart(input.getItemStack(PartItemStack.Wrench), output.side, player)
val newPart = host.getPart(dir)
if (newPart is PartP2PTunnel<*>) {
newPart.outputProperty = true
newPart.onTunnelNetworkChange()
try {
val p2p: P2PCache = newPart.proxy.p2P
p2p.updateFreq(newPart, output.frequency)
output = newPart
} catch (e: GridAccessException) {
// :P
}
println("part changed")
} else {
// error
return null
}
changeP2P(output, BetterP2P.proxy.getP2PFromClass(input.javaClass)!!, player)
}
if (input == output) {
// Network loop
@@ -135,6 +116,64 @@ fun unlinkP2P(player: EntityPlayer, p2pIndex: Long, status: P2PStatus): PartP2PT
return tunnel
}
/**
* Converts one P2P into the type
*/
fun changeP2P(tunnel: PartP2PTunnel<*>, newType: TunnelInfo, player: EntityPlayer): PartP2PTunnel<*>? {
val grid = tunnel.gridNode.grid
if (grid is ISecurityGrid) {
if (!grid.hasPermission(player, SecurityPermissions.BUILD) ||
!grid.hasPermission(player, SecurityPermissions.SECURITY)) {
return null
}
}
if (BetterP2P.proxy.getP2PFromClass(tunnel.javaClass) == newType) {
return null
}
val host = tunnel.host
host.removePart(tunnel.side, false)
val dir = host.addPart(newType.stack, tunnel.side, player)
val newPart = host.getPart(dir)
if (newPart is PartP2PTunnel<*>) {
newPart.outputProperty = tunnel.isOutput
try {
val p2p: P2PCache = newPart.proxy.p2P
p2p.updateFreq(newPart, tunnel.frequency)
return newPart
} catch (e: GridAccessException) {
// :P
}
}
return null
}
/**
* Converts all connected P2Ps to a new type
*/
fun changeAllP2Ps(tunnel: PartP2PTunnel<*>, newType: TunnelInfo, player: EntityPlayer): Boolean {
val grid = tunnel.gridNode.grid
if (grid is ISecurityGrid) {
if (!grid.hasPermission(player, SecurityPermissions.BUILD) ||
!grid.hasPermission(player, SecurityPermissions.SECURITY)) {
return false
}
}
try {
if (tunnel.isOutput && tunnel.input != null) {
return changeAllP2Ps(tunnel.input, newType, player)
} else {
val outputs = tunnel.outputs.toMutableList()
changeP2P(tunnel, newType, player)
for (o in outputs) {
changeP2P(o, newType, player)
}
return true
}
} catch (e: GridAccessException) {
// :P
}
return false
}
/**
* Due to Applied Energistics' limit
*/
@@ -43,4 +43,4 @@ gui.advanced_memory_card.p2p_status.input=Input
gui.advanced_memory_card.p2p_status.output=Output
gui.advanced_memory_card.p2p_status.offline=Offline
gui.advanced_memory_card.types.filtered=Showing: %s
gui.advanced_memory_card.types.any=Showing: §aAll
gui.advanced_memory_card.types.any=§aAll