From 7a38f2fc9a840bcf6f15bb85de2cc2cb6ac8d3be Mon Sep 17 00:00:00 2001 From: firenoo <49818773+firenoo@users.noreply.github.com> Date: Sun, 30 Jul 2023 03:57:13 -0700 Subject: [PATCH] Rewrite Net code, add dual interface compat (#32) * Add dual interfaces to supported P2P list * Fix the AMC eating a static p2p without changing type * Move packet data into a dedicated package in network * Remove unused classes TransportPlayer -> It's no longer allowed! AEPartLocationMessage -> Superceded in the next version LinkException -> Never used. * Rewrite the network code Performs major changes to the structure of how netcode is laid out. 1. Move packets to their own package and rewrite them. 2. Move methods from P2PUtil to GridServerCache, which will serve as the main channel for client <-> server communication. 3. Remove P2PCache - merged with GridServerCache and ModNetwork. Specific packets of note: 1. S2CListP2P has been renamed to S2COpenGui, as that was its original intent. It is only sent when the memory card is used. Use S2CUpdateInfo to send only a list of changed P2PInfos (see below). 2. P2PLocation - This is used to store p2p location information and is the preferred data structure to send across the network. True, it has more data to be sent over the net, but it ensures that hash collisions don't break the card's functionality. Most packet types will use this for operations. 3. P2PInfo - This is used to handle sending updated p2p information over the net. When P2PLocation does not provide enough info (such as when connections are dirty) * Finishing touches to the refactor + rewrite * Change shown type when changing P2P type Because Sampsa wanted it * Remove debug --- dependencies.gradle | 1 + .../java/com/projecturanus/betterp2p/Proxy.kt | 72 ++-- .../betterp2p/capability/MemoryInfo.kt | 12 - .../betterp2p/capability/P2PTunnelInfo.kt | 10 - .../client/gui/GuiAdvancedMemoryCard.kt | 78 ++-- .../betterp2p/client/gui/InfoList.kt | 41 +- .../betterp2p/client/gui/InfoWrapper.kt | 35 +- .../client/gui/widget/WidgetP2PColumn.kt | 28 +- .../client/gui/widget/WidgetP2PDevice.kt | 13 +- .../client/gui/widget/WidgetTypeSelector.kt | 1 + .../betterp2p/item/ItemAdvancedMemoryCard.kt | 68 ++-- .../network/AEPartLocationMessage.kt | 24 -- .../betterp2p/network/C2SCloseGui.kt | 13 - .../betterp2p/network/C2SLinkP2P.kt | 16 - .../betterp2p/network/C2SP2PTunnelInfo.kt | 36 -- .../betterp2p/network/C2SRefreshP2PList.kt | 45 --- .../betterp2p/network/C2STransportPlayer.kt | 15 - .../betterp2p/network/C2STypeChange.kt | 36 -- .../betterp2p/network/C2SUnlinkP2P.kt | 48 --- .../betterp2p/network/C2SUpdateInfo.kt | 45 --- .../betterp2p/network/ClientOpenGuiHandler.kt | 22 -- .../network/ClientRefreshInfoHandler.kt | 20 - .../betterp2p/network/ModNetwork.kt | 162 +++++--- .../betterp2p/network/P2PInfo.kt | 34 -- .../betterp2p/network/S2CListP2P.kt | 26 -- .../betterp2p/network/S2CRefreshInfo.kt | 59 --- .../betterp2p/network/ServerLinkP2PHandler.kt | 21 -- .../network/ServerPlayerDisconnectHandler.kt | 7 +- .../network/ServerRenameP2PTunnel.kt | 30 -- .../network/ServerTransportHandler.kt | 25 -- .../network/ServerUpdateInfoHandler.kt | 17 - .../betterp2p/network/data/GridServerCache.kt | 353 ++++++++++++++++++ .../network/{ => data}/HashHelper.kt | 12 +- .../betterp2p/network/data/MemoryInfo.kt | 58 +++ .../betterp2p/network/data/P2PInfo.kt | 109 ++++++ .../betterp2p/network/data/P2PLocation.kt | 94 +++++ .../C2SCloseGui.kt} | 16 +- .../betterp2p/network/packet/C2SLinkP2P.kt | 43 +++ .../network/packet/C2SRefreshP2PList.kt | 35 ++ .../betterp2p/network/packet/C2SRenameP2P.kt | 79 ++++ .../betterp2p/network/packet/C2STypeChange.kt | 43 +++ .../betterp2p/network/packet/C2SUnlinkP2P.kt | 47 +++ .../network/packet/C2SUpdateMemoryInfo.kt | 39 ++ .../betterp2p/network/packet/S2COpenGui.kt | 57 +++ .../betterp2p/network/packet/S2CUpdateP2P.kt | 62 +++ .../betterp2p/util/CableBusUtil.kt | 42 +-- .../betterp2p/util/p2p/LinkException.kt | 3 - .../betterp2p/util/p2p/P2PCache.kt | 10 - .../betterp2p/util/p2p/P2PStatus.kt | 53 --- .../betterp2p/util/p2p/P2PUtil.kt | 259 +------------ .../betterp2p/util/p2p/TunnelInfo.kt | 3 +- .../assets/betterp2p/lang/en_US.lang | 1 + 52 files changed, 1355 insertions(+), 1123 deletions(-) delete mode 100644 src/main/java/com/projecturanus/betterp2p/capability/MemoryInfo.kt delete mode 100644 src/main/java/com/projecturanus/betterp2p/capability/P2PTunnelInfo.kt delete mode 100644 src/main/java/com/projecturanus/betterp2p/network/AEPartLocationMessage.kt delete mode 100644 src/main/java/com/projecturanus/betterp2p/network/C2SCloseGui.kt delete mode 100644 src/main/java/com/projecturanus/betterp2p/network/C2SLinkP2P.kt delete mode 100644 src/main/java/com/projecturanus/betterp2p/network/C2SP2PTunnelInfo.kt delete mode 100644 src/main/java/com/projecturanus/betterp2p/network/C2SRefreshP2PList.kt delete mode 100644 src/main/java/com/projecturanus/betterp2p/network/C2STransportPlayer.kt delete mode 100644 src/main/java/com/projecturanus/betterp2p/network/C2STypeChange.kt delete mode 100644 src/main/java/com/projecturanus/betterp2p/network/C2SUnlinkP2P.kt delete mode 100644 src/main/java/com/projecturanus/betterp2p/network/C2SUpdateInfo.kt delete mode 100644 src/main/java/com/projecturanus/betterp2p/network/ClientOpenGuiHandler.kt delete mode 100644 src/main/java/com/projecturanus/betterp2p/network/ClientRefreshInfoHandler.kt delete mode 100644 src/main/java/com/projecturanus/betterp2p/network/P2PInfo.kt delete mode 100644 src/main/java/com/projecturanus/betterp2p/network/S2CListP2P.kt delete mode 100644 src/main/java/com/projecturanus/betterp2p/network/S2CRefreshInfo.kt delete mode 100644 src/main/java/com/projecturanus/betterp2p/network/ServerLinkP2PHandler.kt delete mode 100644 src/main/java/com/projecturanus/betterp2p/network/ServerRenameP2PTunnel.kt delete mode 100644 src/main/java/com/projecturanus/betterp2p/network/ServerTransportHandler.kt delete mode 100644 src/main/java/com/projecturanus/betterp2p/network/ServerUpdateInfoHandler.kt create mode 100644 src/main/java/com/projecturanus/betterp2p/network/data/GridServerCache.kt rename src/main/java/com/projecturanus/betterp2p/network/{ => data}/HashHelper.kt (87%) create mode 100644 src/main/java/com/projecturanus/betterp2p/network/data/MemoryInfo.kt create mode 100644 src/main/java/com/projecturanus/betterp2p/network/data/P2PInfo.kt create mode 100644 src/main/java/com/projecturanus/betterp2p/network/data/P2PLocation.kt rename src/main/java/com/projecturanus/betterp2p/network/{ServerCloseGuiHandler.kt => packet/C2SCloseGui.kt} (51%) create mode 100644 src/main/java/com/projecturanus/betterp2p/network/packet/C2SLinkP2P.kt create mode 100644 src/main/java/com/projecturanus/betterp2p/network/packet/C2SRefreshP2PList.kt create mode 100644 src/main/java/com/projecturanus/betterp2p/network/packet/C2SRenameP2P.kt create mode 100644 src/main/java/com/projecturanus/betterp2p/network/packet/C2STypeChange.kt create mode 100644 src/main/java/com/projecturanus/betterp2p/network/packet/C2SUnlinkP2P.kt create mode 100644 src/main/java/com/projecturanus/betterp2p/network/packet/C2SUpdateMemoryInfo.kt create mode 100644 src/main/java/com/projecturanus/betterp2p/network/packet/S2COpenGui.kt create mode 100644 src/main/java/com/projecturanus/betterp2p/network/packet/S2CUpdateP2P.kt delete mode 100644 src/main/java/com/projecturanus/betterp2p/util/p2p/LinkException.kt delete mode 100644 src/main/java/com/projecturanus/betterp2p/util/p2p/P2PCache.kt delete mode 100644 src/main/java/com/projecturanus/betterp2p/util/p2p/P2PStatus.kt diff --git a/dependencies.gradle b/dependencies.gradle index 4af852a..6ffdf7a 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -8,4 +8,5 @@ dependencies { compileOnly('net.industrial-craft:industrialcraft-2:2.2.828-experimental:api') devOnlyNonPublishable('com.github.GTNewHorizons:OpenComputers:1.9.5-GTNH:dev') {transitive = false} compileOnly('pneumaticCraft:PneumaticCraft-1.7.10:1.12.7-152:api') {transitive = false} + api('com.github.GTNewHorizons:AE2FluidCraft-Rework:1.1.29-gtnh-pre:dev') {transitive = false} } diff --git a/src/main/java/com/projecturanus/betterp2p/Proxy.kt b/src/main/java/com/projecturanus/betterp2p/Proxy.kt index 10688a1..1c9020a 100644 --- a/src/main/java/com/projecturanus/betterp2p/Proxy.kt +++ b/src/main/java/com/projecturanus/betterp2p/Proxy.kt @@ -1,7 +1,18 @@ package com.projecturanus.betterp2p +import net.minecraft.item.ItemStack +import net.minecraft.item.crafting.ShapelessRecipes +import net.minecraft.util.IIcon + +import com.glodblock.github.common.parts.PartFluidP2PInterface +import com.glodblock.github.loader.ItemAndBlockHolder +import com.projecturanus.betterp2p.client.render.RenderHandler +import com.projecturanus.betterp2p.item.ItemAdvancedMemoryCard +import com.projecturanus.betterp2p.network.ServerPlayerDisconnectHandler +import com.projecturanus.betterp2p.util.p2p.ClientTunnelInfo +import com.projecturanus.betterp2p.util.p2p.TunnelInfo + import appeng.api.AEApi -import appeng.api.config.TunnelType import appeng.api.definitions.IItemDefinition import appeng.parts.p2p.PartP2PGT5Power import appeng.parts.p2p.PartP2PIC2Power @@ -15,15 +26,8 @@ import appeng.parts.p2p.PartP2PRFPower import appeng.parts.p2p.PartP2PRedstone import appeng.parts.p2p.PartP2PTunnel import appeng.parts.p2p.PartP2PTunnelME -import com.projecturanus.betterp2p.client.render.RenderHandler -import com.projecturanus.betterp2p.item.ItemAdvancedMemoryCard -import com.projecturanus.betterp2p.network.ServerPlayerDisconnectHandler -import com.projecturanus.betterp2p.util.p2p.ClientTunnelInfo -import com.projecturanus.betterp2p.util.p2p.TunnelInfo +import cpw.mods.fml.common.Loader import cpw.mods.fml.common.registry.GameRegistry -import net.minecraft.item.ItemStack -import net.minecraft.item.crafting.ShapelessRecipes -import net.minecraft.util.IIcon /** * A proxy for the server @@ -97,6 +101,16 @@ open class CommonProxy { def = partDefs.p2PTunnelMEInterface(), type = typeId++, classType = PartP2PInterface::class.java) + if (Loader.isModLoaded("ae2fc")) { + val item = ItemAndBlockHolder.FLUID_INTERFACE_P2P + if (item != null) { + val clazz = PartFluidP2PInterface::class.java + val type = typeId++ + val info = TunnelInfo(type, item.stack(), clazz) + tunnelTypes[clazz] = info + tunnelIndices[type] = info + } + } } private fun registerTunnel(def: IItemDefinition, type: Int, classType: Class>) { @@ -136,72 +150,84 @@ class ClientProxy: CommonProxy() { */ override fun initTunnels() { val partDefs = AEApi.instance().definitions().parts() + var typeId = 0 registerTunnel( def = partDefs.p2PTunnelME(), - type = TunnelType.ME, + type = typeId++, classType = PartP2PTunnelME::class.java, icon = { PartP2PTunnelME(it).typeTexture }) registerTunnel( def = partDefs.p2PTunnelEU(), - type = TunnelType.IC2_POWER, + type = typeId++, classType = PartP2PIC2Power::class.java, icon = { PartP2PIC2Power(it).typeTexture }) registerTunnel( def = partDefs.p2PTunnelRF(), - type = TunnelType.RF_POWER, + type = typeId++, classType = PartP2PRFPower::class.java, icon = { PartP2PRFPower(it).typeTexture }) registerTunnel( def = partDefs.p2PTunnelRedstone(), - type = TunnelType.REDSTONE, + type = typeId++, classType = PartP2PRedstone::class.java, icon = { PartP2PRedstone(it).typeTexture }) registerTunnel( def = partDefs.p2PTunnelLiquids(), - type = TunnelType.FLUID, + type = typeId++, classType = PartP2PLiquids::class.java, icon = { PartP2PLiquids(it).typeTexture }) registerTunnel( def = partDefs.p2PTunnelItems(), - type = TunnelType.ITEM, + type = typeId++, classType = PartP2PItems::class.java, icon = { PartP2PItems(it).typeTexture }) registerTunnel( def = partDefs.p2PTunnelLight(), - type = TunnelType.LIGHT, + type = typeId++, classType = PartP2PLight::class.java, icon = { PartP2PLight(it).typeTexture }) registerTunnel( def = partDefs.p2PTunnelOpenComputers(), - type = TunnelType.COMPUTER_MESSAGE, + type = typeId++, classType = PartP2POpenComputers::class.java, icon = { PartP2POpenComputers(it).typeTexture }) registerTunnel( def = partDefs.p2PTunnelPneumaticCraft(), - type = TunnelType.PRESSURE, + type = typeId++, classType = PartP2PPressure::class.java, icon = { PartP2PPressure(it).typeTexture }) registerTunnel( def = partDefs.p2PTunnelGregtech(), - type = TunnelType.GT_POWER, + type = typeId++, classType = PartP2PGT5Power::class.java, icon = { PartP2PGT5Power(it).typeTexture }) registerTunnel( def = partDefs.p2PTunnelMEInterface(), - type = TunnelType.ME_INTERFACE, + type = typeId++, classType = PartP2PInterface::class.java, icon = { PartP2PInterface(it).typeTexture }) + if (Loader.isModLoaded("ae2fc")) { + val item = ItemAndBlockHolder.FLUID_INTERFACE_P2P + if (item != null) { + val clazz = PartFluidP2PInterface::class.java + val stack = item.stack() + val type = typeId++ + val info = ClientTunnelInfo(type, stack, clazz) { PartFluidP2PInterface(stack).typeTexture } + tunnelTypes[clazz] = info + tunnelIndices[type] = info + } + } } private inline fun registerTunnel(def: IItemDefinition, - type: TunnelType, + type: Int, classType: Class>, crossinline icon: (ItemStack) -> IIcon) { if (def.isEnabled) { val stack = def.maybeStack(1).get() - val info = ClientTunnelInfo(type.ordinal, stack, classType) { icon(stack) } + val info = ClientTunnelInfo(type, stack, classType) { icon(stack) } tunnelTypes[classType] = info - tunnelIndices[type.ordinal] = info + tunnelIndices[type] = info } } } diff --git a/src/main/java/com/projecturanus/betterp2p/capability/MemoryInfo.kt b/src/main/java/com/projecturanus/betterp2p/capability/MemoryInfo.kt deleted file mode 100644 index 71ad62d..0000000 --- a/src/main/java/com/projecturanus/betterp2p/capability/MemoryInfo.kt +++ /dev/null @@ -1,12 +0,0 @@ -package com.projecturanus.betterp2p.capability - -import com.projecturanus.betterp2p.client.gui.widget.GuiScale -import com.projecturanus.betterp2p.item.BetterMemoryCardModes -import com.projecturanus.betterp2p.network.NONE_SELECTED - -const val TUNNEL_ANY: Int = -1 -data class MemoryInfo(var selectedEntry: Long = NONE_SELECTED, - var frequency: Long = 0, - var mode: BetterMemoryCardModes = BetterMemoryCardModes.OUTPUT, - var gui: GuiScale = GuiScale.DYNAMIC, - var type: Int = TUNNEL_ANY) diff --git a/src/main/java/com/projecturanus/betterp2p/capability/P2PTunnelInfo.kt b/src/main/java/com/projecturanus/betterp2p/capability/P2PTunnelInfo.kt deleted file mode 100644 index 58edf56..0000000 --- a/src/main/java/com/projecturanus/betterp2p/capability/P2PTunnelInfo.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.projecturanus.betterp2p.capability - -data class P2PTunnelInfo( - var posX: Int = 0, - var posY: Int = 0, - var posZ: Int = 0, - var world: Int = 0, - var side: Int = 0, - var name:String? = null -) diff --git a/src/main/java/com/projecturanus/betterp2p/client/gui/GuiAdvancedMemoryCard.kt b/src/main/java/com/projecturanus/betterp2p/client/gui/GuiAdvancedMemoryCard.kt index 3f26403..84bba4c 100644 --- a/src/main/java/com/projecturanus/betterp2p/client/gui/GuiAdvancedMemoryCard.kt +++ b/src/main/java/com/projecturanus/betterp2p/client/gui/GuiAdvancedMemoryCard.kt @@ -1,36 +1,43 @@ package com.projecturanus.betterp2p.client.gui +import net.minecraft.client.Minecraft +import net.minecraft.client.gui.FontRenderer +import net.minecraft.client.gui.GuiScreen +import net.minecraft.client.renderer.Tessellator +import net.minecraft.client.resources.I18n +import net.minecraft.util.ResourceLocation + +import com.projecturanus.betterp2p.BetterP2P +import com.projecturanus.betterp2p.MODID +import com.projecturanus.betterp2p.network.data.MemoryInfo +import com.projecturanus.betterp2p.network.data.TUNNEL_ANY +import com.projecturanus.betterp2p.client.ClientCache +import com.projecturanus.betterp2p.client.TextureBound +import com.projecturanus.betterp2p.client.gui.widget.* +import com.projecturanus.betterp2p.item.BetterMemoryCardModes +import com.projecturanus.betterp2p.item.MAX_TOOLTIP_LENGTH +import com.projecturanus.betterp2p.network.* +import com.projecturanus.betterp2p.network.data.P2PInfo +import com.projecturanus.betterp2p.network.data.P2PLocation +import com.projecturanus.betterp2p.network.packet.C2SCloseGui +import com.projecturanus.betterp2p.network.packet.C2SRefreshP2PList +import com.projecturanus.betterp2p.network.packet.C2SUpdateMemoryInfo +import com.projecturanus.betterp2p.network.packet.S2COpenGui +import com.projecturanus.betterp2p.util.p2p.ClientTunnelInfo + 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 -import com.projecturanus.betterp2p.BetterP2P -import com.projecturanus.betterp2p.MODID -import com.projecturanus.betterp2p.capability.MemoryInfo -import com.projecturanus.betterp2p.capability.TUNNEL_ANY -import com.projecturanus.betterp2p.client.ClientCache -import com.projecturanus.betterp2p.client.TextureBound -import com.projecturanus.betterp2p.client.gui.widget.* -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 -import net.minecraft.client.renderer.Tessellator -import net.minecraft.client.resources.I18n -import net.minecraft.util.ResourceLocation import org.lwjgl.input.Keyboard import org.lwjgl.input.Mouse import org.lwjgl.opengl.GL11 const val GUI_WIDTH = 288 const val GUI_TEX_HEIGHT = 264 -class GuiAdvancedMemoryCard(msg: S2CListP2P) : GuiScreen(), TextureBound { +class GuiAdvancedMemoryCard(msg: S2COpenGui) : GuiScreen(), TextureBound { private var guiLeft: Int = 0 @@ -51,7 +58,7 @@ class GuiAdvancedMemoryCard(msg: S2CListP2P) : GuiScreen(), TextureBound { _ySize = lazy { value } } - private var scale = msg.memoryInfo.gui + private var scale = msg.memoryInfo.guiScale private val resizeButton: WidgetButton private var mode = msg.memoryInfo.mode @@ -260,7 +267,7 @@ class GuiAdvancedMemoryCard(msg: S2CListP2P) : GuiScreen(), TextureBound { this.index = type?.index ?: TUNNEL_ANY gui.type = type commitType() - gui.closeTypeSelector() + gui.closeTypeSelector(type) } override fun x(): Int { @@ -353,7 +360,7 @@ class GuiAdvancedMemoryCard(msg: S2CListP2P) : GuiScreen(), TextureBound { buttonList.add(refreshButton) if (typeSelector.parent != typeButton) { - closeTypeSelector() + closeTypeSelector(type) } else { typeSelector.setPos(typeSelector.parent.x(), typeSelector.parent.y()) } @@ -370,7 +377,8 @@ class GuiAdvancedMemoryCard(msg: S2CListP2P) : GuiScreen(), TextureBound { typeSelector.visible = true } - fun closeTypeSelector() { + fun closeTypeSelector(type: ClientTunnelInfo?) { + this.type = type typeSelector.visible = false } @@ -386,14 +394,20 @@ class GuiAdvancedMemoryCard(msg: S2CListP2P) : GuiScreen(), TextureBound { } fun refreshInfo(infos: List) { - this.infos.rebuild(infos.map(::InfoWrapper)) + this.infos.rebuild(infos.map(::InfoWrapper), scrollBar, scale.size(height - 75)) + checkInfo() + refreshOverlay() + } + + fun updateInfo(infos: List) { + this.infos.update(infos.map(::InfoWrapper), scrollBar, scale.size(height - 75)) checkInfo() refreshOverlay() } private fun syncMemoryInfo() { ModNetwork.channel.sendToServer( - C2SUpdateInfo(MemoryInfo(infos.selectedEntry, selectedInfo?.frequency ?: 0, mode, scale, type?.index ?: TUNNEL_ANY))) + C2SUpdateMemoryInfo(MemoryInfo(infos.selectedEntry, selectedInfo?.frequency ?: 0, mode, scale, type?.index ?: TUNNEL_ANY))) } override fun onGuiClosed() { @@ -450,8 +464,8 @@ class GuiAdvancedMemoryCard(msg: S2CListP2P) : GuiScreen(), TextureBound { * Selects the info with the hashCode, if it exists. Otherwise, * deselect the entry. */ - fun selectInfo(hash: Long) { - infos.select(hash) + fun selectInfo(which: P2PLocation?) { + infos.select(which) syncMemoryInfo() refreshOverlay() } @@ -462,15 +476,15 @@ class GuiAdvancedMemoryCard(msg: S2CListP2P) : GuiScreen(), TextureBound { ClientCache.selectedFacing = null } else { - ClientCache.selectedPosition = arrayListOf(selectedInfo?.posX, selectedInfo?.posY, selectedInfo?.posZ) - ClientCache.selectedFacing = selectedInfo?.facing + ClientCache.selectedPosition = arrayListOf(selectedInfo?.loc?.x, selectedInfo?.loc?.y, selectedInfo?.loc?.z) + ClientCache.selectedFacing = selectedInfo?.loc?.facing } ClientCache.positions.clear() ClientCache.positions.addAll(infos.sorted.filter { it.frequency == selectedInfo?.frequency && it != selectedInfo && - it.dim == mc.thePlayer.dimension - }.map { arrayListOf(it.posX, it.posY, it.posZ) to it.facing }) + it.loc.dim == mc.thePlayer.dimension + }.map { arrayListOf(it.loc.x, it.loc.y, it.loc.z) to it.loc.facing }) } override fun mouseClicked(mouseX: Int, mouseY: Int, mouseButton: Int) { @@ -559,7 +573,7 @@ class GuiAdvancedMemoryCard(msg: S2CListP2P) : GuiScreen(), TextureBound { override fun keyTyped(char: Char, key: Int) { if (key == Keyboard.KEY_ESCAPE && typeSelector.visible) { - closeTypeSelector() + closeTypeSelector(type) return } if (key == Keyboard.KEY_LSHIFT || col.keyTyped(char, key)) return diff --git a/src/main/java/com/projecturanus/betterp2p/client/gui/InfoList.kt b/src/main/java/com/projecturanus/betterp2p/client/gui/InfoList.kt index 8f05c0b..ef77007 100644 --- a/src/main/java/com/projecturanus/betterp2p/client/gui/InfoList.kt +++ b/src/main/java/com/projecturanus/betterp2p/client/gui/InfoList.kt @@ -1,6 +1,7 @@ package com.projecturanus.betterp2p.client.gui -import com.projecturanus.betterp2p.network.NONE_SELECTED +import com.projecturanus.betterp2p.client.gui.widget.WidgetScrollBar +import com.projecturanus.betterp2p.network.data.P2PLocation import kotlin.reflect.KProperty0 /** @@ -17,7 +18,7 @@ class InfoList (initList: Collection, * The master map, acts as the source of truth for all items * in this list. */ - private val masterMap: HashMap = hashMapOf() + private val masterMap: HashMap = hashMapOf() /** * Sorted view of the master map. This is resorted whenever @@ -39,20 +40,26 @@ class InfoList (initList: Collection, get() = search.get() val selectedInfo: InfoWrapper? - get() = masterMap[selectedEntry] + get() { + return if (selectedEntry == null) { + null + } else { + masterMap[selectedEntry] + } + } - var selectedEntry: Long = NONE_SELECTED + var selectedEntry: P2PLocation? = null val size: Int get() = masterMap.size init { - initList.forEach { masterMap[it.code] = it } + initList.forEach { masterMap[it.loc] = it } } fun resort() { sorted.sortBy { - if (it.code == selectedEntry) { + if (it.loc == selectedEntry) { -2 // Put the selected p2p at the front // Non-Zero frequencies } else if (it.frequency != 0L && it.frequency == selectedInfo?.frequency && !it.output) { @@ -72,7 +79,7 @@ class InfoList (initList: Collection, fun refilter() { filter.updateFilter(searchStr.lowercase()) filtered = sorted.filter { - if (it.code == selectedEntry) { + if (it.loc == selectedEntry) { return@filter true } for ((f, strs) in filter.activeFilters) { @@ -83,7 +90,7 @@ class InfoList (initList: Collection, true }.sortedBy { when { - it.code == selectedEntry -> Long.MIN_VALUE + 1 + it.loc == selectedEntry -> Long.MIN_VALUE + 1 it.frequency != 0L && it.frequency == selectedInfo?.frequency && !it.output -> Long.MIN_VALUE // Put the same frequency to the front it.frequency != 0.toLong() && it.frequency == selectedInfo?.frequency -> Long.MIN_VALUE + 2 @@ -116,33 +123,31 @@ class InfoList (initList: Collection, /** * Completely refresh the master list. */ - fun rebuild(updateList: Collection) { + fun rebuild(updateList: Collection, scrollbar: WidgetScrollBar, numEntries: Int) { masterMap.clear() - updateList.forEach { masterMap[it.code] = it } + updateList.forEach { masterMap[it.loc] = it } sorted.clear() sorted.addAll(masterMap.values) resort() // TODO: Extend the filtering mechanism. refilter() + scrollbar.setRange(0, masterMap.size.coerceIn(0, (masterMap.size - numEntries).coerceAtLeast(0)), 23) } /** * Updates the master list and sends the changes downstream to sorted/filtered. */ - fun update(updateList: Collection) { - updateList.forEach { masterMap[it.code] = it } + fun update(updateList: Collection, scrollbar: WidgetScrollBar, numEntries: Int) { + updateList.forEach { masterMap[it.loc] = it } sorted.clear() sorted.addAll(masterMap.values) resort() // TODO: Extend the filtering mechanism. refilter() + scrollbar.setRange(0, masterMap.size.coerceIn(0, (masterMap.size - numEntries).coerceAtLeast(0)), 23) } - fun select(hashCode: Long) { - if (masterMap.containsKey(hashCode)) { - selectedEntry = hashCode - } else { - selectedEntry = NONE_SELECTED - } + fun select(which: P2PLocation?) { + selectedEntry = masterMap.getOrDefault(which, null)?.loc } } diff --git a/src/main/java/com/projecturanus/betterp2p/client/gui/InfoWrapper.kt b/src/main/java/com/projecturanus/betterp2p/client/gui/InfoWrapper.kt index 5c5a37f..4240f09 100644 --- a/src/main/java/com/projecturanus/betterp2p/client/gui/InfoWrapper.kt +++ b/src/main/java/com/projecturanus/betterp2p/client/gui/InfoWrapper.kt @@ -1,19 +1,18 @@ package com.projecturanus.betterp2p.client.gui import com.projecturanus.betterp2p.BetterP2P -import com.projecturanus.betterp2p.network.P2PInfo -import com.projecturanus.betterp2p.network.hashP2P +import com.projecturanus.betterp2p.network.data.P2PInfo +import com.projecturanus.betterp2p.network.data.P2PLocation import com.projecturanus.betterp2p.util.p2p.ClientTunnelInfo +import cpw.mods.fml.relauncher.Side +import cpw.mods.fml.relauncher.SideOnly import net.minecraft.client.gui.GuiButton import net.minecraft.client.resources.I18n import net.minecraft.util.IIcon import net.minecraftforge.common.util.ForgeDirection +@SideOnly(Side.CLIENT) class InfoWrapper(info: P2PInfo) { - // Basic information - val code: Long by lazy { - hashP2P(posX, posY, posZ, facing.ordinal, dim) - } var frequency: Long = info.frequency set(value) { if (error || value == 0L) { @@ -25,11 +24,7 @@ class InfoWrapper(info: P2PInfo) { } val hasChannel = info.hasChannel - val posX: Int = info.posX - val posY: Int = info.posY - val posZ: Int = info.posZ - val dim: Int = info.world - val facing: ForgeDirection = info.facing + val loc: P2PLocation = P2PLocation(info.posX, info.posY, info.posZ, info.facing, info.dim) val output: Boolean = info.output val type: Int = info.type @@ -96,7 +91,7 @@ class InfoWrapper(info: P2PInfo) { "§bP2P - ${p2pType.dispName}", "§e" + I18n.format("gui.advanced_memory_card.pos", info.posX, info.posY, info.posZ), "§e" + I18n.format("gui.advanced_memory_card.side", info.facing.name), - "§e" + I18n.format("gui.advanced_memory_card.dim", info.world) + "§e" + I18n.format("gui.advanced_memory_card.dim", info.dim) ) if (error || frequency == 0L) { hoverInfo.add("§c" + I18n.format("gui.advanced_memory_card.p2p_status.unbound")) @@ -107,19 +102,15 @@ class InfoWrapper(info: P2PInfo) { } override fun hashCode(): Int { - return code.hashCode() + return loc.hashCode() } override fun equals(other: Any?): Boolean { - return if (other is InfoWrapper) { - this.posX == other.posX && - this.posY == other.posY && - this.posZ == other.posZ && - this.dim == other.dim && - this.facing == other.facing - } else { - false - } + if (this === other) return true + if (this.javaClass != other?.javaClass) return false + other as InfoWrapper + + return this.loc == other.loc } } diff --git a/src/main/java/com/projecturanus/betterp2p/client/gui/widget/WidgetP2PColumn.kt b/src/main/java/com/projecturanus/betterp2p/client/gui/widget/WidgetP2PColumn.kt index 928a509..3fd6915 100644 --- a/src/main/java/com/projecturanus/betterp2p/client/gui/widget/WidgetP2PColumn.kt +++ b/src/main/java/com/projecturanus/betterp2p/client/gui/widget/WidgetP2PColumn.kt @@ -2,14 +2,15 @@ package com.projecturanus.betterp2p.client.gui.widget import appeng.core.localization.GuiColors import com.projecturanus.betterp2p.BetterP2P -import com.projecturanus.betterp2p.capability.P2PTunnelInfo import com.projecturanus.betterp2p.client.gui.GuiAdvancedMemoryCard import com.projecturanus.betterp2p.client.gui.InfoList import com.projecturanus.betterp2p.client.gui.InfoWrapper import com.projecturanus.betterp2p.item.BetterMemoryCardModes -import com.projecturanus.betterp2p.network.* +import com.projecturanus.betterp2p.network.ModNetwork +import com.projecturanus.betterp2p.network.packet.C2SLinkP2P +import com.projecturanus.betterp2p.network.packet.C2SRenameP2P +import com.projecturanus.betterp2p.network.packet.C2SUnlinkP2P import net.minecraft.client.gui.GuiTextField -import net.minecraftforge.common.util.ForgeDirection import org.lwjgl.input.Keyboard import kotlin.reflect.KProperty0 @@ -59,9 +60,10 @@ class WidgetP2PColumn(private val gui: GuiAdvancedMemoryCard, widget.renderNameTextField = true } if(renameBar.info != null && renameBar.text.isNotEmpty() && renameBar.info.name != renameBar.text){ - val info:InfoWrapper = renameBar.info + val info: InfoWrapper = renameBar.info + renameBar.text = renameBar.text.trim() - ModNetwork.channel.sendToServer(C2SP2PTunnelInfo(P2PTunnelInfo(info.posX,info.posY,info.posZ,info.dim, ForgeDirection.valueOf(info.facing.name).ordinal,renameBar.text))) + ModNetwork.channel.sendToServer(C2SRenameP2P(info.loc, renameBar.text)) } renameBar.isVisible = false renameBar.text = "" @@ -86,26 +88,26 @@ class WidgetP2PColumn(private val gui: GuiAdvancedMemoryCard, if (mouseButton == 1) { gui.openTypeSelector(widget, false) } else if (selectedInfo.get() != info) { - gui.selectInfo(info.code) + gui.selectInfo(info.loc) } info.bindButton.func_146113_a(gui.mc.soundHandler) } private fun onBindButtonClicked(info: InfoWrapper) { - if (infos.selectedEntry == NONE_SELECTED) return + if (infos.selectedEntry == null) return when (mode()) { BetterMemoryCardModes.INPUT -> { - BetterP2P.logger.debug("Bind ${info.code} as input") - ModNetwork.channel.sendToServer(C2SLinkP2P(info.code, infos.selectedEntry)) + BetterP2P.logger.debug("Bind ${info.loc} as input") + ModNetwork.channel.sendToServer(C2SLinkP2P(info.loc, infos.selectedEntry)) } BetterMemoryCardModes.OUTPUT -> { - BetterP2P.logger.debug("Bind ${info.code} as output") - ModNetwork.channel.sendToServer(C2SLinkP2P(infos.selectedEntry, info.code)) + BetterP2P.logger.debug("Bind ${info.loc} as output") + ModNetwork.channel.sendToServer(C2SLinkP2P(infos.selectedEntry, info.loc)) } BetterMemoryCardModes.COPY -> { val input = findInput(infos.selectedInfo?.frequency) if (input != null) - ModNetwork.channel.sendToServer(C2SLinkP2P(input.code, info.code)) + ModNetwork.channel.sendToServer(C2SLinkP2P(input.loc, info.loc)) } else -> { BetterP2P.logger.debug("Somehow bind button was pressed while in UNBIND mode.") @@ -116,7 +118,7 @@ class WidgetP2PColumn(private val gui: GuiAdvancedMemoryCard, private fun onUnbindButtonClicked(info: InfoWrapper) { if (info.frequency != 0L) { - ModNetwork.channel.sendToServer(C2SUnlinkP2P(info.code, gui.getTypeID())) + ModNetwork.channel.sendToServer(C2SUnlinkP2P(info.loc, gui.getTypeID())) info.frequency = 0L } } diff --git a/src/main/java/com/projecturanus/betterp2p/client/gui/widget/WidgetP2PDevice.kt b/src/main/java/com/projecturanus/betterp2p/client/gui/widget/WidgetP2PDevice.kt index 29f9f9c..f48d0d9 100644 --- a/src/main/java/com/projecturanus/betterp2p/client/gui/widget/WidgetP2PDevice.kt +++ b/src/main/java/com/projecturanus/betterp2p/client/gui/widget/WidgetP2PDevice.kt @@ -1,12 +1,11 @@ package com.projecturanus.betterp2p.client.gui.widget -import com.projecturanus.betterp2p.capability.TUNNEL_ANY +import com.projecturanus.betterp2p.network.data.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.packet.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 @@ -58,7 +57,7 @@ class WidgetP2PDevice(private val selectedInfoProperty: KProperty0 } else { // Other modes: // Bind allowed only if currently not selected && selected is unbound; OR not bound to selected - info.bindButton.enabled = info.code != selectedInfo!!.code && + info.bindButton.enabled = info.loc != selectedInfo!!.loc && (selectedInfo!!.frequency == 0L || info.frequency != selectedInfo!!.frequency) info.unbindButton.enabled = false @@ -69,7 +68,7 @@ class WidgetP2PDevice(private val selectedInfoProperty: KProperty0 val info = infoSupplier() if (info != null) { // Draw the background first - if (selectedInfo?.code == info.code) + if (selectedInfo?.loc == info.loc) GuiScreen.drawRect(x, y, x + P2PEntryConstants.WIDTH, y + P2PEntryConstants.HEIGHT, P2PEntryConstants.SELECTED_COLOR) else if (info.error) { // P2P output without an input, or unbound @@ -138,8 +137,8 @@ class WidgetP2PDevice(private val selectedInfoProperty: KProperty0 } override fun accept(type: ClientTunnelInfo?) { - ModNetwork.channel.sendToServer(C2STypeChange(type?.index ?: TUNNEL_ANY, infoSupplier()!!.code)) - gui.closeTypeSelector() + ModNetwork.channel.sendToServer(C2STypeChange(type?.index ?: TUNNEL_ANY, infoSupplier()!!.loc)) + gui.closeTypeSelector(type) } override fun x(): Int { diff --git a/src/main/java/com/projecturanus/betterp2p/client/gui/widget/WidgetTypeSelector.kt b/src/main/java/com/projecturanus/betterp2p/client/gui/widget/WidgetTypeSelector.kt index 5a197ce..6c72854 100644 --- a/src/main/java/com/projecturanus/betterp2p/client/gui/widget/WidgetTypeSelector.kt +++ b/src/main/java/com/projecturanus/betterp2p/client/gui/widget/WidgetTypeSelector.kt @@ -2,6 +2,7 @@ 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.network.data.TUNNEL_ANY import com.projecturanus.betterp2p.util.p2p.ClientTunnelInfo import com.projecturanus.betterp2p.util.p2p.TunnelInfo import net.minecraft.client.gui.GuiScreen diff --git a/src/main/java/com/projecturanus/betterp2p/item/ItemAdvancedMemoryCard.kt b/src/main/java/com/projecturanus/betterp2p/item/ItemAdvancedMemoryCard.kt index c870787..2a62a41 100644 --- a/src/main/java/com/projecturanus/betterp2p/item/ItemAdvancedMemoryCard.kt +++ b/src/main/java/com/projecturanus/betterp2p/item/ItemAdvancedMemoryCard.kt @@ -1,27 +1,26 @@ package com.projecturanus.betterp2p.item +import appeng.api.config.SecurityPermissions import appeng.api.networking.IGridHost +import appeng.api.networking.security.ISecurityGrid import appeng.core.CreativeTab import appeng.parts.p2p.PartP2PTunnel import com.projecturanus.betterp2p.MODID -import com.projecturanus.betterp2p.capability.MemoryInfo -import com.projecturanus.betterp2p.capability.TUNNEL_ANY import com.projecturanus.betterp2p.client.ClientCache import com.projecturanus.betterp2p.client.gui.widget.GuiScale import com.projecturanus.betterp2p.network.ModNetwork -import com.projecturanus.betterp2p.network.NONE_SELECTED -import com.projecturanus.betterp2p.network.S2CListP2P -import com.projecturanus.betterp2p.network.hashP2P +import com.projecturanus.betterp2p.network.data.MemoryInfo +import com.projecturanus.betterp2p.network.data.TUNNEL_ANY +import com.projecturanus.betterp2p.network.data.readP2PLocation +import com.projecturanus.betterp2p.network.data.toLoc +import com.projecturanus.betterp2p.network.data.writeP2PLocation import com.projecturanus.betterp2p.util.getPart -import com.projecturanus.betterp2p.util.p2p.P2PCache -import com.projecturanus.betterp2p.util.p2p.P2PStatus import com.projecturanus.betterp2p.util.p2p.getTypeIndex import cpw.mods.fml.relauncher.Side import cpw.mods.fml.relauncher.SideOnly import net.minecraft.client.renderer.texture.IIconRegister import net.minecraft.entity.Entity import net.minecraft.entity.player.EntityPlayer -import net.minecraft.entity.player.EntityPlayerMP import net.minecraft.item.Item import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound @@ -42,11 +41,6 @@ object ItemAdvancedMemoryCard : Item() { super.onUpdate(stack, worldIn, entityIn, itemSlot, isSelected) } - private fun sendStatus(status: P2PStatus, info: MemoryInfo, player: EntityPlayerMP) { - P2PCache.statusMap[player.uniqueID] = status - ModNetwork.channel.sendTo(S2CListP2P(status.refresh(info.type), info), player) - } - @SideOnly(Side.CLIENT) override fun addInformation(stack: ItemStack, player: EntityPlayer, tooltip: MutableList, boolean: Boolean) { val info = getInfo(stack) @@ -70,29 +64,27 @@ object ItemAdvancedMemoryCard : Item() { val te = w.getTileEntity(x, y, z) if (te is IGridHost && te.getGridNode(ForgeDirection.getOrientation(side)) != null) { val part = getPart(w, x, y, z, hx, hy, hz) + val grid = part?.gridNode?.grid ?: return false + + if (grid is ISecurityGrid && !grid.hasPermission(player, SecurityPermissions.BUILD)) { + // Check security grid permissions. Only BUILD is required. + return false + } + val stack = player.heldItem val info = getInfo(stack) val type: Int - val status: P2PStatus + if (part is PartP2PTunnel<*>) { type = part.getTypeIndex() - status = P2PStatus(part.gridNode.grid, player, type) - info.selectedEntry = hashP2P(part) + info.selectedEntry = part.toLoc() } else { type = TUNNEL_ANY - status = if (part != null) { - // If we have a PartP2PTunnelME, it looks at the P2P grid node, - // so we should use the part instead. - P2PStatus(part.gridNode.grid, player, type) - } else { - // Fall back to the tile entity. - P2PStatus(te.getGridNode(ForgeDirection.getOrientation(side)).grid, player, type) - } - info.selectedEntry = NONE_SELECTED + info.selectedEntry = null } info.type = type writeInfo(stack, info) - sendStatus(status, info, player as EntityPlayerMP) + ModNetwork.initConnection(player, grid, info) return true } } @@ -110,12 +102,22 @@ object ItemAdvancedMemoryCard : Item() { fun getInfo(stack: ItemStack): MemoryInfo { if (stack.item != this) throw ClassCastException("Cannot cast ${stack.item.javaClass.name} to ${javaClass.name}") - - if (stack.tagCompound == null) stack.tagCompound = NBTTagCompound() + // Initialize NBT if it isn't already a thing + if (stack.tagCompound == null) { + stack.tagCompound = NBTTagCompound() + } val compound = stack.tagCompound!! - if (!compound.hasKey("gui")) compound.setByte("gui", GuiScale.DYNAMIC.ordinal.toByte()) - if (!compound.hasKey("selectedIndex", Constants.NBT.TAG_LONG)) compound.setLong("selectedIndex", NONE_SELECTED) - return MemoryInfo(compound.getLong("selectedIndex"), compound.getLong("frequency"), BetterMemoryCardModes.values()[compound.getInteger("mode")], GuiScale.values()[compound.getByte("gui").toInt()]) + if (!compound.hasKey("gui")) { + compound.setByte("gui", GuiScale.DYNAMIC.ordinal.toByte()) + } + if (!compound.hasKey("selectedIndex", Constants.NBT.TAG_COMPOUND)) { + compound.setTag("selectedIndex", NBTTagCompound()) + } + return MemoryInfo( + selectedEntry = readP2PLocation(compound.getCompoundTag("selectedIndex")), + frequency = compound.getLong("frequency"), + mode = BetterMemoryCardModes.values()[compound.getInteger("mode")], + guiScale = GuiScale.values()[compound.getByte("gui").toInt()]) } fun writeInfo(stack: ItemStack, info: MemoryInfo) { @@ -123,9 +125,9 @@ object ItemAdvancedMemoryCard : Item() { if (stack.tagCompound == null) stack.tagCompound = NBTTagCompound() val compound = stack.tagCompound!! - compound.setLong("selectedIndex", info.selectedEntry) + compound.setTag("selectedIndex", writeP2PLocation(info.selectedEntry)) compound.setLong("frequency", info.frequency) compound.setInteger("mode", info.mode.ordinal) - compound.setByte("gui", info.gui.ordinal.toByte()) + compound.setByte("gui", info.guiScale.ordinal.toByte()) } } diff --git a/src/main/java/com/projecturanus/betterp2p/network/AEPartLocationMessage.kt b/src/main/java/com/projecturanus/betterp2p/network/AEPartLocationMessage.kt deleted file mode 100644 index 8e643b5..0000000 --- a/src/main/java/com/projecturanus/betterp2p/network/AEPartLocationMessage.kt +++ /dev/null @@ -1,24 +0,0 @@ -package com.projecturanus.betterp2p.network - -import cpw.mods.fml.common.network.simpleimpl.IMessage -import io.netty.buffer.ByteBuf - -class AEPartLocationMessage(var x: Int = 0, var y: Int = 0, var z: Int = 0, var hitX: Float = 0f, var hitY: Float = 0f, var hitZ: Float = 0f): IMessage { - override fun fromBytes(buf: ByteBuf) { - x = buf.readInt() - y = buf.readInt() - z = buf.readInt() - hitX = buf.readFloat() - hitY = buf.readFloat() - hitZ = buf.readFloat() - } - - override fun toBytes(buf: ByteBuf) { - buf.writeInt(x) - buf.writeInt(y) - buf.writeInt(z) - buf.writeFloat(hitX) - buf.writeFloat(hitY) - buf.writeFloat(hitZ) - } -} diff --git a/src/main/java/com/projecturanus/betterp2p/network/C2SCloseGui.kt b/src/main/java/com/projecturanus/betterp2p/network/C2SCloseGui.kt deleted file mode 100644 index 1382abb..0000000 --- a/src/main/java/com/projecturanus/betterp2p/network/C2SCloseGui.kt +++ /dev/null @@ -1,13 +0,0 @@ -package com.projecturanus.betterp2p.network - -import cpw.mods.fml.common.network.simpleimpl.IMessage -import io.netty.buffer.ByteBuf - -class C2SCloseGui : IMessage { - override fun fromBytes(buf: ByteBuf) { - - } - - override fun toBytes(buf: ByteBuf) { - } -} diff --git a/src/main/java/com/projecturanus/betterp2p/network/C2SLinkP2P.kt b/src/main/java/com/projecturanus/betterp2p/network/C2SLinkP2P.kt deleted file mode 100644 index 81a6d00..0000000 --- a/src/main/java/com/projecturanus/betterp2p/network/C2SLinkP2P.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.projecturanus.betterp2p.network - -import cpw.mods.fml.common.network.simpleimpl.IMessage -import io.netty.buffer.ByteBuf - -class C2SLinkP2P(var input: Long = NONE_SELECTED, var output: Long = NONE_SELECTED): IMessage { - override fun fromBytes(buf: ByteBuf) { - input = buf.readLong() - output = buf.readLong() - } - - override fun toBytes(buf: ByteBuf) { - buf.writeLong(input) - buf.writeLong(output) - } -} diff --git a/src/main/java/com/projecturanus/betterp2p/network/C2SP2PTunnelInfo.kt b/src/main/java/com/projecturanus/betterp2p/network/C2SP2PTunnelInfo.kt deleted file mode 100644 index a42b3fc..0000000 --- a/src/main/java/com/projecturanus/betterp2p/network/C2SP2PTunnelInfo.kt +++ /dev/null @@ -1,36 +0,0 @@ -package com.projecturanus.betterp2p.network - -import com.projecturanus.betterp2p.capability.P2PTunnelInfo -import cpw.mods.fml.common.network.simpleimpl.IMessage -import io.netty.buffer.ByteBuf - -fun readP2PTunnelInfo(buf: ByteBuf): P2PTunnelInfo { - return P2PTunnelInfo(buf.readInt(),buf.readInt(),buf.readInt(),buf.readInt(),buf.readInt(), buf.readBytes(buf.readInt()).toString(Charsets.UTF_8)) -} - -fun writeP2PTunnelInfo(buf: ByteBuf,info: P2PTunnelInfo) { - buf.writeInt(info.posX) - buf.writeInt(info.posY) - buf.writeInt(info.posZ) - buf.writeInt(info.world) - buf.writeInt(info.side) - if(info.name ==null) { - buf.writeInt(0) - }else{ - val arr = info.name?.toByteArray(Charsets.UTF_8) - arr?.let { buf.writeInt(it.size) } - buf.writeBytes(arr) - } -} - - -class C2SP2PTunnelInfo(var info: P2PTunnelInfo = P2PTunnelInfo()): IMessage { - - override fun fromBytes(buf: ByteBuf) { - info = readP2PTunnelInfo(buf) - } - - override fun toBytes(buf: ByteBuf) { - writeP2PTunnelInfo(buf,info) - } -} diff --git a/src/main/java/com/projecturanus/betterp2p/network/C2SRefreshP2PList.kt b/src/main/java/com/projecturanus/betterp2p/network/C2SRefreshP2PList.kt deleted file mode 100644 index 258b595..0000000 --- a/src/main/java/com/projecturanus/betterp2p/network/C2SRefreshP2PList.kt +++ /dev/null @@ -1,45 +0,0 @@ -package com.projecturanus.betterp2p.network - -import com.projecturanus.betterp2p.BetterP2P -import com.projecturanus.betterp2p.capability.TUNNEL_ANY -import com.projecturanus.betterp2p.util.listAllGridP2P -import com.projecturanus.betterp2p.util.listTargetGridP2P -import com.projecturanus.betterp2p.util.p2p.P2PCache -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 - -/** - * Send a request to the server to refresh the p2p list with the - * given type. - */ -class C2SRefreshP2PList(var type: Int = TUNNEL_ANY): IMessage { - override fun fromBytes(buf: ByteBuf) { - type = buf.readByte().toInt() - } - - override fun toBytes(buf: ByteBuf) { - buf.writeByte(type) - } -} - -/** - * Client -> C2SRefreshP2P -> Server - * Handler on server side - */ -class ServerRefreshP2PListHandler : IMessageHandler { - override fun onMessage(message: C2SRefreshP2PList, ctx: MessageContext): S2CListP2P? { - if (!P2PCache.statusMap.containsKey(ctx.serverHandler.playerEntity.uniqueID)) return null - val status = P2PCache.statusMap[ctx.serverHandler.playerEntity.uniqueID]!! - status.lastP2PType = message.type - val tunnelType = BetterP2P.proxy.getP2PFromIndex(message.type) - if (tunnelType != null) { - listTargetGridP2P(status.grid, status.player, tunnelType.clazz) - } else { - listAllGridP2P(status.grid, status.player) - } - ModNetwork.queueP2PListUpdate(status, ctx.serverHandler.playerEntity) - return null - } -} diff --git a/src/main/java/com/projecturanus/betterp2p/network/C2STransportPlayer.kt b/src/main/java/com/projecturanus/betterp2p/network/C2STransportPlayer.kt deleted file mode 100644 index 5371083..0000000 --- a/src/main/java/com/projecturanus/betterp2p/network/C2STransportPlayer.kt +++ /dev/null @@ -1,15 +0,0 @@ -package com.projecturanus.betterp2p.network -import com.projecturanus.betterp2p.capability.P2PTunnelInfo -import cpw.mods.fml.common.network.simpleimpl.IMessage -import io.netty.buffer.ByteBuf - -class C2STransportPlayer(var info: P2PTunnelInfo = P2PTunnelInfo()):IMessage{ - override fun fromBytes(buf: ByteBuf) { - info = readP2PTunnelInfo(buf) - } - - - override fun toBytes(buf: ByteBuf) { - writeP2PTunnelInfo(buf,info) - } -} diff --git a/src/main/java/com/projecturanus/betterp2p/network/C2STypeChange.kt b/src/main/java/com/projecturanus/betterp2p/network/C2STypeChange.kt deleted file mode 100644 index 4840557..0000000 --- a/src/main/java/com/projecturanus/betterp2p/network/C2STypeChange.kt +++ /dev/null @@ -1,36 +0,0 @@ -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 { - 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 - } -} diff --git a/src/main/java/com/projecturanus/betterp2p/network/C2SUnlinkP2P.kt b/src/main/java/com/projecturanus/betterp2p/network/C2SUnlinkP2P.kt deleted file mode 100644 index 2be0e71..0000000 --- a/src/main/java/com/projecturanus/betterp2p/network/C2SUnlinkP2P.kt +++ /dev/null @@ -1,48 +0,0 @@ -package com.projecturanus.betterp2p.network - -import com.projecturanus.betterp2p.BetterP2P -import com.projecturanus.betterp2p.capability.TUNNEL_ANY -import com.projecturanus.betterp2p.util.listAllGridP2P -import com.projecturanus.betterp2p.util.listTargetGridP2P -import com.projecturanus.betterp2p.util.p2p.P2PCache -import com.projecturanus.betterp2p.util.p2p.unlinkP2P -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 - -/** - * Unlink input from outputs message (set freq to 0) - */ -class C2SUnlinkP2P(var p2pId: Long = NONE_SELECTED, var type: Int = TUNNEL_ANY): IMessage { - override fun fromBytes(buf: ByteBuf) { - p2pId = buf.readLong() - type = buf.readByte().toInt() - } - - override fun toBytes(buf: ByteBuf) { - buf.writeLong(p2pId) - buf.writeByte(type) - } -} - -/** - * Client -> C2SUnlinkP2P -> Server - * Handler on server side - */ -class ServerUnlinkP2PHandler : IMessageHandler { - override fun onMessage(message: C2SUnlinkP2P, ctx: MessageContext): S2CListP2P? { - val status = P2PCache.statusMap[ctx.serverHandler.playerEntity.uniqueID] ?: return null - - unlinkP2P(ctx.serverHandler.playerEntity, message.p2pId, status) - status.lastP2PType = message.type - val tunnelType = BetterP2P.proxy.getP2PFromIndex(message.type) - if (tunnelType != null) { - listTargetGridP2P(status.grid, status.player, tunnelType.clazz) - } else { - listAllGridP2P(status.grid, status.player) - } - ModNetwork.queueP2PListUpdate(status, ctx.serverHandler.playerEntity) - return null - } -} diff --git a/src/main/java/com/projecturanus/betterp2p/network/C2SUpdateInfo.kt b/src/main/java/com/projecturanus/betterp2p/network/C2SUpdateInfo.kt deleted file mode 100644 index 7690591..0000000 --- a/src/main/java/com/projecturanus/betterp2p/network/C2SUpdateInfo.kt +++ /dev/null @@ -1,45 +0,0 @@ -package com.projecturanus.betterp2p.network - -import com.projecturanus.betterp2p.capability.MemoryInfo -import com.projecturanus.betterp2p.client.gui.widget.GuiScale -import com.projecturanus.betterp2p.item.BetterMemoryCardModes -import cpw.mods.fml.common.network.simpleimpl.IMessage -import io.netty.buffer.ByteBuf - -fun writeMemoryInfo(buf: ByteBuf, info: MemoryInfo) { - buf.writeLong(info.selectedEntry) - buf.writeLong(info.frequency) - buf.writeInt(info.mode.ordinal) - buf.writeByte(info.gui.ordinal) - buf.writeByte(info.type) -} - -fun readMemoryInfo(buf: ByteBuf): MemoryInfo { - val selectedEntry = buf.readLong() - val frequency = buf.readLong() - val mode = try { - BetterMemoryCardModes.values()[buf.readInt()] - } catch (e: Exception) { - BetterMemoryCardModes.OUTPUT - } - val gui = try { - GuiScale.values()[buf.readByte().toInt()] - } catch (e: ArrayIndexOutOfBoundsException) { - GuiScale.DYNAMIC - } - val type = buf.readByte().toInt() - return MemoryInfo(selectedEntry, frequency, mode, gui, type) -} - -/** - * Request from client -> server - */ -class C2SUpdateInfo(var info: MemoryInfo = MemoryInfo()) : IMessage { - override fun fromBytes(buf: ByteBuf) { - info = readMemoryInfo(buf) - } - - override fun toBytes(buf: ByteBuf) { - writeMemoryInfo(buf, info) - } -} diff --git a/src/main/java/com/projecturanus/betterp2p/network/ClientOpenGuiHandler.kt b/src/main/java/com/projecturanus/betterp2p/network/ClientOpenGuiHandler.kt deleted file mode 100644 index c2de49e..0000000 --- a/src/main/java/com/projecturanus/betterp2p/network/ClientOpenGuiHandler.kt +++ /dev/null @@ -1,22 +0,0 @@ -package com.projecturanus.betterp2p.network - -import com.projecturanus.betterp2p.client.gui.GuiAdvancedMemoryCard -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 cpw.mods.fml.relauncher.Side -import cpw.mods.fml.relauncher.SideOnly -import net.minecraft.client.Minecraft - -class ClientOpenGuiHandler : IMessageHandler { - @SideOnly(Side.CLIENT) - override fun onMessage(message: S2CListP2P, ctx: MessageContext): IMessage? { - val gui = Minecraft.getMinecraft().currentScreen - if(gui is GuiAdvancedMemoryCard){ - gui.refreshInfo(message.infos) - }else { - Minecraft.getMinecraft().displayGuiScreen(GuiAdvancedMemoryCard(message)) - } - return null - } -} diff --git a/src/main/java/com/projecturanus/betterp2p/network/ClientRefreshInfoHandler.kt b/src/main/java/com/projecturanus/betterp2p/network/ClientRefreshInfoHandler.kt deleted file mode 100644 index 3ea8548..0000000 --- a/src/main/java/com/projecturanus/betterp2p/network/ClientRefreshInfoHandler.kt +++ /dev/null @@ -1,20 +0,0 @@ -package com.projecturanus.betterp2p.network - -import com.projecturanus.betterp2p.client.gui.GuiAdvancedMemoryCard -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 cpw.mods.fml.relauncher.Side -import cpw.mods.fml.relauncher.SideOnly -import net.minecraft.client.Minecraft - -class ClientRefreshInfoHandler : IMessageHandler { - @SideOnly(Side.CLIENT) - override fun onMessage(message: S2CRefreshInfo, ctx: MessageContext): IMessage? { - val gui = Minecraft.getMinecraft().currentScreen - if (gui is GuiAdvancedMemoryCard) { - gui.refreshInfo(message.infos) - } - return null - } -} diff --git a/src/main/java/com/projecturanus/betterp2p/network/ModNetwork.kt b/src/main/java/com/projecturanus/betterp2p/network/ModNetwork.kt index f4fc349..9e2c318 100644 --- a/src/main/java/com/projecturanus/betterp2p/network/ModNetwork.kt +++ b/src/main/java/com/projecturanus/betterp2p/network/ModNetwork.kt @@ -1,34 +1,71 @@ package com.projecturanus.betterp2p.network -import com.projecturanus.betterp2p.MODID -import com.projecturanus.betterp2p.capability.MemoryInfo -import com.projecturanus.betterp2p.util.p2p.P2PStatus -import cpw.mods.fml.common.network.NetworkRegistry -import cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper -import cpw.mods.fml.relauncher.Side -import net.minecraft.entity.player.EntityPlayer -import net.minecraft.entity.player.EntityPlayerMP -import java.util.UUID import java.util.concurrent.ScheduledThreadPoolExecutor import java.util.concurrent.ThreadFactory import java.util.concurrent.TimeUnit +import java.util.Collections +import java.util.UUID +import java.util.WeakHashMap +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.entity.player.EntityPlayerMP + +import com.projecturanus.betterp2p.MODID +import com.projecturanus.betterp2p.network.data.GridServerCache +import com.projecturanus.betterp2p.network.data.MemoryInfo +import com.projecturanus.betterp2p.network.packet.C2SCloseGui +import com.projecturanus.betterp2p.network.packet.C2SLinkP2P +import com.projecturanus.betterp2p.network.packet.C2SRefreshP2PList +import com.projecturanus.betterp2p.network.packet.C2SRenameP2P +import com.projecturanus.betterp2p.network.packet.C2STypeChange +import com.projecturanus.betterp2p.network.packet.C2SUnlinkP2P +import com.projecturanus.betterp2p.network.packet.C2SUpdateMemoryInfo +import com.projecturanus.betterp2p.network.packet.ClientOpenGuiHandler +import com.projecturanus.betterp2p.network.packet.ClientUpdateP2PHandler +import com.projecturanus.betterp2p.network.packet.S2COpenGui +import com.projecturanus.betterp2p.network.packet.S2CUpdateP2P +import com.projecturanus.betterp2p.network.packet.ServerCloseGuiHandler +import com.projecturanus.betterp2p.network.packet.ServerLinkP2PHandler +import com.projecturanus.betterp2p.network.packet.ServerRefreshP2PListHandler +import com.projecturanus.betterp2p.network.packet.ServerRenameP2PTunnel +import com.projecturanus.betterp2p.network.packet.ServerTypeChangeHandler +import com.projecturanus.betterp2p.network.packet.ServerUnlinkP2PHandler +import com.projecturanus.betterp2p.network.packet.ServerUpdateInfoHandler + + +import appeng.api.networking.IGrid +import cpw.mods.fml.common.network.NetworkRegistry +import cpw.mods.fml.common.network.simpleimpl.SimpleNetworkWrapper +import cpw.mods.fml.relauncher.Side + +/** + * Network cooldown time in milliseconds + */ +const val NETWORK_CD = 250L + +/** + * Mod network manager. Handles server <-> client communication. + */ object ModNetwork { val channel: SimpleNetworkWrapper = NetworkRegistry.INSTANCE.newSimpleChannel(MODID) - private var netCache: MutableMap = mutableMapOf() + + /** For client requests (changing viewed p2p) */ + val playerState: MutableMap = Collections.synchronizedMap(WeakHashMap()) + + /** Network thread. */ private lateinit var networkWorker: ScheduledThreadPoolExecutor fun registerNetwork() { - channel.registerMessage(ClientOpenGuiHandler::class.java, S2CListP2P::class.java, 0, Side.CLIENT) - channel.registerMessage(ClientRefreshInfoHandler::class.java, S2CRefreshInfo::class.java, 1, Side.CLIENT) - channel.registerMessage(ServerLinkP2PHandler::class.java, C2SLinkP2P::class.java, 2, Side.SERVER) - channel.registerMessage(ServerCloseGuiHandler::class.java, C2SCloseGui::class.java, 3, Side.SERVER) - channel.registerMessage(ServerUpdateInfoHandler::class.java, C2SUpdateInfo::class.java, 4, Side.SERVER) - channel.registerMessage(ServerTransportHandler::class.java, C2STransportPlayer::class.java, 5, Side.SERVER) - 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) + var id = 0 + channel.registerMessage(ClientOpenGuiHandler::class.java, S2COpenGui::class.java, id++, Side.CLIENT) + channel.registerMessage(ClientUpdateP2PHandler::class.java, S2CUpdateP2P::class.java, id++, Side.CLIENT) + channel.registerMessage(ServerLinkP2PHandler::class.java, C2SLinkP2P::class.java, id++, Side.SERVER) + channel.registerMessage(ServerCloseGuiHandler::class.java, C2SCloseGui::class.java, id++, Side.SERVER) + channel.registerMessage(ServerUpdateInfoHandler::class.java, C2SUpdateMemoryInfo::class.java, id++, Side.SERVER) + channel.registerMessage(ServerRenameP2PTunnel::class.java, C2SRenameP2P::class.java, id++, Side.SERVER) + channel.registerMessage(ServerRefreshP2PListHandler::class.java, C2SRefreshP2PList::class.java, id++, Side.SERVER) + channel.registerMessage(ServerUnlinkP2PHandler::class.java, C2SUnlinkP2P::class.java, id++, Side.SERVER) + channel.registerMessage(ServerTypeChangeHandler::class.java, C2STypeChange::class.java, id, Side.SERVER) networkWorker = ScheduledThreadPoolExecutor(1, ThreadFactory { val th = Thread(it) th.name = "BetterP2P-NetworkWorker" @@ -39,42 +76,77 @@ object ModNetwork { } /** - * Utility function that asks for a p2p update. Multiple requests are bundled into 1. + * Utility function that asks for a full refresh of a specific p2p type. */ - fun queueP2PListUpdate(status: P2PStatus, player: EntityPlayer, info: MemoryInfo? = null) { - synchronized(netCache) { - val state = netCache.getOrPut(player.uniqueID) { NetworkState() } - if (state.updateReady + NETWORK_CD < System.currentTimeMillis()) { - channel.sendTo(S2CListP2P(status.refresh(status.lastP2PType)), player as EntityPlayerMP) - state.updateReady = System.currentTimeMillis() + NETWORK_CD - } else if (!state.updatePending) { - state.updatePending = true + fun requestP2PList(player: EntityPlayer, type: Int) { + synchronized(playerState) { + val playerState = playerState[player.uniqueID] ?: return + val cache = playerState.gridCache + + cache.type = type + if (playerState.updateReady + NETWORK_CD < System.currentTimeMillis()) { + channel.sendTo(S2CUpdateP2P(cache.retrieveP2PList(), true), player as EntityPlayerMP) + playerState.updateReady = System.currentTimeMillis() + NETWORK_CD + } else if (!playerState.updatePending) { + playerState.updatePending = true networkWorker.schedule({ - if (info == null) { - channel.sendTo(S2CListP2P(status.refresh(status.lastP2PType)), player as EntityPlayerMP) - } else { - channel.sendTo(S2CListP2P(status.refresh(status.lastP2PType), info), player as EntityPlayerMP) + synchronized(ModNetwork.playerState) { + channel.sendTo(S2CUpdateP2P(cache.retrieveP2PList(), true), player as EntityPlayerMP) + playerState.updatePending = false } - synchronized(netCache) { - state.updatePending = false - } - }, state.updateReady - System.currentTimeMillis(), TimeUnit.MILLISECONDS) + }, playerState.updateReady - System.currentTimeMillis(), TimeUnit.MILLISECONDS) } } } + /** + * Utility function that asks for a p2p update. Multiple requests are bundled into 1. + * If dirty, only an incremental update is sent. + */ + fun requestP2PUpdate(player: EntityPlayer) { + synchronized(playerState) { + val playerState = playerState[player.uniqueID] ?: return + val cache = playerState.gridCache + + if (playerState.updateReady + NETWORK_CD < System.currentTimeMillis()) { + channel.sendTo(S2CUpdateP2P(cache.getP2PUpdates()), player as EntityPlayerMP) + playerState.updateReady = System.currentTimeMillis() + NETWORK_CD + } else if (!playerState.updatePending) { + playerState.updatePending = true + networkWorker.schedule({ + synchronized(ModNetwork.playerState) { + channel.sendTo(S2CUpdateP2P(cache.getP2PUpdates()), player as EntityPlayerMP) + playerState.updatePending = false + } + }, playerState.updateReady - System.currentTimeMillis(), TimeUnit.MILLISECONDS) + } + } + } + + /** + * Sets up a connection. + */ + fun initConnection(player: EntityPlayer, grid: IGrid, info: MemoryInfo) { + val cache = GridServerCache(grid, player, info.type) + + playerState[player.uniqueID] = PlayerRequest(gridCache = cache) + channel.sendTo(S2COpenGui(cache.retrieveP2PList(), info), player as EntityPlayerMP) + } + + fun removeConnection(player: EntityPlayer) { + playerState.remove(player.uniqueID) + } + fun stop() { networkWorker.shutdown() } } -internal data class NetworkState( - internal var updatePending: Boolean = false, - internal var updateReady: Long = System.currentTimeMillis() -) - /** - * Network cooldown time in milliseconds + * Keeps track of when to send network updates. */ -const val NETWORK_CD = 250L - +data class PlayerRequest ( + internal var updatePending: Boolean = false, + internal var updateReady: Long = System.currentTimeMillis(), + val gridCache: GridServerCache, +) diff --git a/src/main/java/com/projecturanus/betterp2p/network/P2PInfo.kt b/src/main/java/com/projecturanus/betterp2p/network/P2PInfo.kt deleted file mode 100644 index cd2d5cd..0000000 --- a/src/main/java/com/projecturanus/betterp2p/network/P2PInfo.kt +++ /dev/null @@ -1,34 +0,0 @@ -package com.projecturanus.betterp2p.network - -import com.projecturanus.betterp2p.client.gui.InfoWrapper -import net.minecraftforge.common.util.ForgeDirection - -class P2PInfo(val frequency: Long, - val posX: Int, - val posY: Int, - val posZ: Int, - val world: Int, - val facing: ForgeDirection, - val name: String, - val output: Boolean, - val hasChannel: Boolean, - // # of channels if ME P2P, or -1 else - val channels: Int, - // type of p2p, corresponds to registry in proxy - val type: Int) { - - override fun hashCode(): Int { - return hashP2P(posX, posY, posZ, facing.ordinal, world).hashCode() - } - - override fun equals(other: Any?): Boolean { - return if (other is InfoWrapper) { - this.posX == other.posX && - this.posY == other.posY && - this.posZ == other.posZ && - this.facing == other.facing - } else { - false - } - } -} diff --git a/src/main/java/com/projecturanus/betterp2p/network/S2CListP2P.kt b/src/main/java/com/projecturanus/betterp2p/network/S2CListP2P.kt deleted file mode 100644 index 47c23c1..0000000 --- a/src/main/java/com/projecturanus/betterp2p/network/S2CListP2P.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.projecturanus.betterp2p.network - -import com.projecturanus.betterp2p.capability.MemoryInfo -import cpw.mods.fml.common.network.simpleimpl.IMessage -import io.netty.buffer.ByteBuf - -class S2CListP2P(var infos: List = emptyList(), - var memoryInfo: MemoryInfo = MemoryInfo()) : IMessage { - override fun fromBytes(buf: ByteBuf) { - val length = buf.readInt() - val list = ArrayList(length) - for (i in 0 until length) { - list += readInfo(buf) - } - infos = list - memoryInfo = readMemoryInfo(buf) - } - - override fun toBytes(buf: ByteBuf) { - buf.writeInt(infos.size) - for (info in infos) { - writeInfo(buf, info) - } - writeMemoryInfo(buf, memoryInfo) - } -} diff --git a/src/main/java/com/projecturanus/betterp2p/network/S2CRefreshInfo.kt b/src/main/java/com/projecturanus/betterp2p/network/S2CRefreshInfo.kt deleted file mode 100644 index 9f9abbb..0000000 --- a/src/main/java/com/projecturanus/betterp2p/network/S2CRefreshInfo.kt +++ /dev/null @@ -1,59 +0,0 @@ -package com.projecturanus.betterp2p.network - -import cpw.mods.fml.common.network.simpleimpl.IMessage -import io.netty.buffer.ByteBuf -import net.minecraftforge.common.util.ForgeDirection - -fun readInfo(buf: ByteBuf): P2PInfo { - val freq = buf.readLong() - val posX = buf.readInt() - val posY = buf.readInt() - val posZ = buf.readInt() - val world = buf.readInt() - val facing = ForgeDirection.values()[buf.readInt()] - val nameLength = buf.readShort() - 1 - var name = "" - for (i in 0..nameLength) { - name += buf.readChar() - } - val output = buf.readBoolean() - val hasChannel = buf.readBoolean() - val channels = buf.readByte().toInt() - val type = buf.readByte().toInt() - return P2PInfo(freq, posX, posY, posZ,world, facing, name, output, hasChannel, channels, type) -} - -fun writeInfo(buf: ByteBuf, info: P2PInfo) { - buf.writeLong(info.frequency) - buf.writeInt(info.posX) - buf.writeInt(info.posY) - buf.writeInt(info.posZ) - buf.writeInt(info.world) - buf.writeInt(info.facing.ordinal) - buf.writeShort(info.name.length) - for (c in info.name) { - buf.writeChar(c.code) - } - buf.writeBoolean(info.output) - buf.writeBoolean(info.hasChannel) - buf.writeByte(info.channels) - buf.writeByte(info.type) -} - -class S2CRefreshInfo(var infos: List = emptyList()) : IMessage { - override fun fromBytes(buf: ByteBuf) { - val length = buf.readInt() - val list = ArrayList(length) - for (i in 0 until length) { - list += readInfo(buf) - } - infos = list - } - - override fun toBytes(buf: ByteBuf) { - buf.writeInt(infos.size) - for (info in infos) { - writeInfo(buf, info) - } - } -} diff --git a/src/main/java/com/projecturanus/betterp2p/network/ServerLinkP2PHandler.kt b/src/main/java/com/projecturanus/betterp2p/network/ServerLinkP2PHandler.kt deleted file mode 100644 index 5cfb674..0000000 --- a/src/main/java/com/projecturanus/betterp2p/network/ServerLinkP2PHandler.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.projecturanus.betterp2p.network - -import com.projecturanus.betterp2p.util.p2p.P2PCache -import com.projecturanus.betterp2p.util.p2p.linkP2P -import cpw.mods.fml.common.network.simpleimpl.IMessage -import cpw.mods.fml.common.network.simpleimpl.IMessageHandler -import cpw.mods.fml.common.network.simpleimpl.MessageContext - -class ServerLinkP2PHandler : IMessageHandler { - override fun onMessage(message: C2SLinkP2P, ctx: MessageContext): IMessage? { - val status = P2PCache.statusMap[ctx.serverHandler.playerEntity.uniqueID] ?: return null - val result = linkP2P(ctx.serverHandler.playerEntity, message.input, message.output, status) - - if (result != null) { - status.listP2P[message.input] = result.first - status.listP2P[message.output] = result.second - ModNetwork.queueP2PListUpdate(status, ctx.serverHandler.playerEntity) - } - return null - } -} diff --git a/src/main/java/com/projecturanus/betterp2p/network/ServerPlayerDisconnectHandler.kt b/src/main/java/com/projecturanus/betterp2p/network/ServerPlayerDisconnectHandler.kt index 79b64e7..27ce82f 100644 --- a/src/main/java/com/projecturanus/betterp2p/network/ServerPlayerDisconnectHandler.kt +++ b/src/main/java/com/projecturanus/betterp2p/network/ServerPlayerDisconnectHandler.kt @@ -1,20 +1,21 @@ package com.projecturanus.betterp2p.network -import com.projecturanus.betterp2p.util.p2p.P2PCache +import net.minecraftforge.common.MinecraftForge + import cpw.mods.fml.common.FMLCommonHandler import cpw.mods.fml.common.eventhandler.SubscribeEvent import cpw.mods.fml.common.gameevent.PlayerEvent -import net.minecraftforge.common.MinecraftForge object ServerPlayerDisconnectHandler { @SubscribeEvent fun onLoggedOut(event: PlayerEvent.PlayerLoggedOutEvent) { - P2PCache.statusMap.remove(event.player.uniqueID) + ModNetwork.removeConnection(event.player) } fun register() { val handler = ServerPlayerDisconnectHandler + MinecraftForge.EVENT_BUS.register(handler) FMLCommonHandler.instance().bus().register(handler) } diff --git a/src/main/java/com/projecturanus/betterp2p/network/ServerRenameP2PTunnel.kt b/src/main/java/com/projecturanus/betterp2p/network/ServerRenameP2PTunnel.kt deleted file mode 100644 index 812dd2f..0000000 --- a/src/main/java/com/projecturanus/betterp2p/network/ServerRenameP2PTunnel.kt +++ /dev/null @@ -1,30 +0,0 @@ -package com.projecturanus.betterp2p.network -import appeng.api.networking.IGridHost -import appeng.api.parts.IPartHost -import appeng.parts.p2p.PartP2PTunnel -import com.projecturanus.betterp2p.item.ItemAdvancedMemoryCard -import com.projecturanus.betterp2p.util.p2p.P2PCache -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 net.minecraft.tileentity.TileEntity -import net.minecraft.world.World -import net.minecraftforge.common.DimensionManager -import net.minecraftforge.common.util.ForgeDirection - -/** - * Handler for renaming p2p tunnels. - */ -class ServerRenameP2PTunnel : IMessageHandler { - override fun onMessage(message: C2SP2PTunnelInfo, ctx: MessageContext): IMessage? { - val world: World = DimensionManager.getWorld(message.info.world) - val te: TileEntity = world.getTileEntity(message.info.posX, message.info.posY, message.info.posZ) - val cache = P2PCache.statusMap[ctx.serverHandler.playerEntity.uniqueID] ?: return null - if (te is IGridHost && te.getGridNode(ForgeDirection.getOrientation(message.info.side)) != null) { - val p = (te as IPartHost).getPart(ForgeDirection.getOrientation(message.info.side)) as PartP2PTunnel<*> - p.customName = message.info.name - ModNetwork.queueP2PListUpdate(cache, ctx.serverHandler.playerEntity, ItemAdvancedMemoryCard.getInfo(cache.player.heldItem)) - } - return null - } -} diff --git a/src/main/java/com/projecturanus/betterp2p/network/ServerTransportHandler.kt b/src/main/java/com/projecturanus/betterp2p/network/ServerTransportHandler.kt deleted file mode 100644 index 76be13e..0000000 --- a/src/main/java/com/projecturanus/betterp2p/network/ServerTransportHandler.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.projecturanus.betterp2p.network - - -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 net.minecraft.entity.player.EntityPlayerMP -import net.minecraft.server.MinecraftServer -import net.minecraft.util.ChatComponentText - -class ServerTransportHandler : IMessageHandler { - - override fun onMessage(message: C2STransportPlayer, ctx: MessageContext): IMessage? { - val player:EntityPlayerMP = ctx.serverHandler.playerEntity - val op = MinecraftServer.getServer().configurationManager.func_152596_g(player.gameProfile) - if(!op){ - player.addChatMessage(ChatComponentText("You are not OP")) - }else{ - if(player.worldObj.provider.dimensionId!= message.info.world) - player.travelToDimension(message.info.world) - player.setPositionAndUpdate(message.info.posX.toDouble(), message.info.posY.toDouble(), message.info.posZ.toDouble()) - } - return null - } -} diff --git a/src/main/java/com/projecturanus/betterp2p/network/ServerUpdateInfoHandler.kt b/src/main/java/com/projecturanus/betterp2p/network/ServerUpdateInfoHandler.kt deleted file mode 100644 index 20f90ea..0000000 --- a/src/main/java/com/projecturanus/betterp2p/network/ServerUpdateInfoHandler.kt +++ /dev/null @@ -1,17 +0,0 @@ -package com.projecturanus.betterp2p.network - -import com.projecturanus.betterp2p.item.ItemAdvancedMemoryCard -import cpw.mods.fml.common.network.simpleimpl.IMessage -import cpw.mods.fml.common.network.simpleimpl.IMessageHandler -import cpw.mods.fml.common.network.simpleimpl.MessageContext - -class ServerUpdateInfoHandler : IMessageHandler { - override fun onMessage(message: C2SUpdateInfo, ctx: MessageContext): IMessage? { - val player = ctx.serverHandler.playerEntity - val stack = player.heldItem - if (stack.item is ItemAdvancedMemoryCard) { - ItemAdvancedMemoryCard.writeInfo(stack, message.info) - } - return null - } -} diff --git a/src/main/java/com/projecturanus/betterp2p/network/data/GridServerCache.kt b/src/main/java/com/projecturanus/betterp2p/network/data/GridServerCache.kt new file mode 100644 index 0000000..e872c4c --- /dev/null +++ b/src/main/java/com/projecturanus/betterp2p/network/data/GridServerCache.kt @@ -0,0 +1,353 @@ +package com.projecturanus.betterp2p.network.data + +import java.lang.IllegalStateException + +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.item.ItemStack +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.util.ChatComponentTranslation +import net.minecraftforge.common.util.ForgeDirection + +import com.projecturanus.betterp2p.BetterP2P +import com.projecturanus.betterp2p.util.p2p.TunnelInfo +import com.projecturanus.betterp2p.util.p2p.outputProperty +import com.projecturanus.betterp2p.util.p2p.getTypeIndex + +import appeng.api.config.SecurityPermissions +import appeng.api.networking.IGrid +import appeng.api.networking.security.ISecurityGrid +import appeng.api.parts.IPart +import appeng.api.parts.PartItemStack +import appeng.helpers.IInterfaceHost +import appeng.me.GridAccessException +import appeng.me.cache.P2PCache +import appeng.parts.automation.UpgradeInventory +import appeng.parts.p2p.PartP2PTunnel +import appeng.parts.p2p.PartP2PTunnelStatic +import appeng.tile.inventory.AppEngInternalInventory +import appeng.util.Platform + +/** + * When the player uses the adv memory card, this is cached on the server side + * to provide access to the Grid when the player performs actions in the GUI + * Each player has a list of p2ps that will be sent. These are tracked in [listP2P]. + */ +class GridServerCache(private val grid: IGrid, val player: EntityPlayer, var type: Int) { + /** + * The P2P list. On init, this is the full list. + */ + private val listP2P: MutableMap> = mutableMapOf() + + /** + * The dirty P2P list. Updates are accumulated here and sent altogether. + */ + private val dirtyP2P: MutableSet = mutableSetOf() + + init { + rebuildList(type) + } + + /** + * Refreshes the global p2p list + */ + private fun rebuildList(type: Int) { + synchronized(listP2P) { + listP2P.clear() + dirtyP2P.clear() + grid.machinesClasses.forEach { + // Find all P2P tunnels... + if (it.superclass.superclass == PartP2PTunnel::class.java && + (type == TUNNEL_ANY || BetterP2P.proxy.getP2PFromIndex(type)?.clazz == it)) { + grid.getMachines(it).forEach { gridNode -> + val p2p = gridNode.machine as PartP2PTunnel<*> + listP2P[p2p.toLoc()] = p2p + } + } + } + } + } + + /** + * Refreshes and gets the p2p list of the targeted type + * If [type] is [TUNNEL_ANY] or invalid, returns the full list; else filters the list to the + * targeted type + */ + fun retrieveP2PList(): List { + if (grid is ISecurityGrid && !grid.hasPermission(player, SecurityPermissions.BUILD)) { + return emptyList() + } + rebuildList(type) + + return listP2P.values.mapNotNull { + val index = BetterP2P.proxy.getP2PFromClass(it.javaClass)?.index ?: TUNNEL_ANY + if (type == TUNNEL_ANY || index == type) { + it.toInfo() + } else null + } + } + + /** + * Sets the entry to the p2p tunnel and marks it as dirty to be sent in the next network update. + * Only p2ps of the currently targeted type can be shown + */ + fun markDirty(key: P2PLocation, p2p: PartP2PTunnel<*>) { + synchronized(listP2P) { + if (type == TUNNEL_ANY || p2p.getTypeIndex() == type) { + listP2P[key] = p2p + dirtyP2P.add(key) + } + } + } + + /** + * Returns the list of P2Ps that are currently marked dirty, and clears the dirty list. + */ + fun getP2PUpdates(): List { + val result = dirtyP2P.mapNotNull { + listP2P[it]?.toInfo() + } + + dirtyP2P.clear() + + return result; + } + + /** + * Link the two P2P tunnels together. Returns the pair of P2P tunnels on success, or null otherwise. + */ + fun linkP2P(inputIndex: P2PLocation, outputIndex: P2PLocation): + Pair, PartP2PTunnel<*>>? { + // If these calls mess up we have bigger problems... + val input = listP2P[inputIndex] ?: return null + var output = listP2P[outputIndex] ?: return null + + // Double check security permissions. In theory, the cache won't be set up in the first place + // for intruders. + if (grid is ISecurityGrid && !grid.hasPermission(player, SecurityPermissions.BUILD)) { + return null + } + + //change type if necessary + if (input.javaClass != output.javaClass) { + output = changeP2PType(output, BetterP2P.proxy.getP2PFromClass(input.javaClass)!!) ?: return null + } + + // Network loop + if (input == output) { + return null + } + + var frequency = input.frequency + val cache = input.proxy.p2P + + // Generate a new frequency if needed + if (input.frequency == 0L || input.isOutput) { + frequency = System.currentTimeMillis() + } + + // If tunnel was already bound, unbind that one + if (cache.getInput(frequency) != null) { + val originalInput = cache.getInput(frequency) + if (originalInput != input) { + updateP2P(originalInput.toLoc(), originalInput, frequency, true, input.customName) + } + } + + // Perform the link + val inputResult: PartP2PTunnel<*> = updateP2P(inputIndex, input, frequency, false, input.customName) + val outputResult: PartP2PTunnel<*> = updateP2P(outputIndex, output, frequency, true, input.customName) + + // Special case for interfaces + if (input is IInterfaceHost && output is IInterfaceHost) { + val drops = mutableListOf() + handleInterface(input, output, inputResult as IInterfaceHost, outputResult as IInterfaceHost, drops) + Platform.spawnDrops(player.worldObj, output.location.x, output.location.y, output.location.z, drops) + } + + return inputResult to outputResult + } + + fun unlinkP2P(p2pIndex: P2PLocation): PartP2PTunnel<*>? { + val tunnel = listP2P[p2pIndex] ?: return null + val oldFreq = tunnel.frequency + if (oldFreq == 0L) { + return tunnel + } + + return updateP2P(p2pIndex, tunnel, 0L, false, tunnel.customName) + } + + /** + * Sets the p2p tunnel to the frequency, output, and custom name. Removes the old one and replaces it, which lets + * AE2 trigger the Grid refresh for us (though we need to update the tunnels ourselves) + */ + private fun updateP2P(key: P2PLocation, tunnel: PartP2PTunnel<*>, frequency: Long, output: Boolean, name: String): PartP2PTunnel<*> { + val side = tunnel.side + val data = NBTTagCompound() + + tunnel.host.removePart(side, true) + + val p2pItem: ItemStack = tunnel.getItemStack(PartItemStack.Wrench) + + + p2pItem.writeToNBT(data) + data.setLong("freq", frequency) + + val newType = ItemStack.loadItemStackFromNBT(data) + val dir: ForgeDirection = tunnel.host?.addPart(newType, side, player) ?: throw RuntimeException("Cannot bind") + val newBus: IPart = tunnel.host.getPart(dir) + if (newBus is PartP2PTunnel<*>) { + newBus.outputProperty = output + if (!name.isBlank()) { + newBus.customName = name + } + try { + val p2p = newBus.proxy.p2P + p2p.updateFreq(newBus, frequency) + } catch (e: GridAccessException) { + // :P + } + newBus.onTunnelNetworkChange() + markDirty(key, newBus) + return newBus + } else { + throw IllegalStateException("Cannot bind") + } + } + + /** + * Converts one P2P into the type + */ + private fun changeP2PType(tunnel: PartP2PTunnel<*>, newType: TunnelInfo): PartP2PTunnel<*>? { + if (BetterP2P.proxy.getP2PFromClass(tunnel.javaClass) == newType) { + player.addChatMessage(ChatComponentTranslation("gui.advanced_memory_card.error.same_type")) + return null + } + // Change to a static P2P type = require p2p in inventory + if (newType.clazz.superclass == PartP2PTunnelStatic::class.java) { + var canConvert = false + for ((i, stack) in player.inventory.mainInventory.withIndex()) { + if (stack?.isItemEqual(newType.stack) == true) { + player.inventory.decrStackSize(i, 1) + canConvert = true + break + } + } + if (!canConvert) { + player.addChatMessage(ChatComponentTranslation("gui.advanced_memory_card.error.missing_items", 1, newType.stack.displayName)) + return null + } + } + // Change from a static P2P type = give p2p back to the player + if (tunnel is PartP2PTunnelStatic<*>) { + val drop = ItemStack.copyItemStack(tunnel.itemStack) + drop.stackSize = 1 + if (!player.inventory.addItemStackToInventory(drop)) { + val drops = mutableListOf(drop) + tunnel.getDrops(drops, false) + Platform.spawnDrops(player.worldObj, player.serverPosX, player.serverPosY, player.serverPosZ, drops) + } + } + + 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(p2p: P2PLocation, newType: TunnelInfo): Boolean { + if (grid is ISecurityGrid && !grid.hasPermission(player, SecurityPermissions.BUILD)) { + return false + } + + var tunnel = listP2P[p2p] ?: return false + + try { + if (tunnel.isOutput && tunnel.input != null) { + tunnel = tunnel.input + } + + val outputs = tunnel.outputs.toMutableList() + if (newType.clazz.superclass == PartP2PTunnelStatic::class.java) { + val amt = outputs.size + 1 + var hasItems = 0 + for (stack in player.inventory.mainInventory) { + if (stack?.isItemEqual(newType.stack) == true) { + hasItems += stack.stackSize + if (hasItems >= amt) { + break + } + } + } + if (hasItems < amt) { + player.addChatMessage(ChatComponentTranslation("gui.advanced_memory_card.error.missing_items", amt, newType.stack.displayName)) + return false + } + } + changeP2PType(tunnel, newType) + for (o in outputs) { + changeP2PType(o, newType) + } + return true + } catch (e: GridAccessException) { + // :P + } + return false + } + + /** + * Handles a p2p interface/dual interface case. + */ + private fun handleInterface(oldIn: IInterfaceHost, oldOut: IInterfaceHost, + newIn: IInterfaceHost, newOut: IInterfaceHost, + drops: MutableList) { + // For input and output, retain upgrades, items, and settings. + val upgradesIn = oldIn.interfaceDuality.getInventoryByName("upgrades") as UpgradeInventory + upgradesIn.forEachIndexed { index, stack -> + (newIn.interfaceDuality.getInventoryByName("upgrades") as UpgradeInventory).setInventorySlotContents(index, stack) + } + val upgradesOut = oldOut.interfaceDuality.getInventoryByName("upgrades") as UpgradeInventory + upgradesOut.forEachIndexed { index, stack -> + (newOut.interfaceDuality.getInventoryByName("upgrades") as UpgradeInventory).setInventorySlotContents(index, stack) + } + val itemsIn = oldIn.interfaceDuality.storage as AppEngInternalInventory + itemsIn.forEachIndexed { index, stack -> + (newIn.interfaceDuality.storage as AppEngInternalInventory).setInventorySlotContents(index, stack) + } + val itemsOut = oldOut.interfaceDuality.storage as AppEngInternalInventory + itemsOut.forEachIndexed { index, stack -> + (newOut.interfaceDuality.storage as AppEngInternalInventory).setInventorySlotContents(index, stack) + } + val settingsIn = oldIn.interfaceDuality.configManager + settingsIn.settings.forEach { + newIn.configManager.putSetting(it, settingsIn.getSetting(it)) + } + val settingsOut = oldOut.interfaceDuality.configManager + settingsOut.settings.forEach { + newOut.configManager.putSetting(it, settingsOut.getSetting(it)) + } + + // For input, just copy the patterns over + val patternsIn = oldIn.interfaceDuality.patterns as AppEngInternalInventory + patternsIn.forEachIndexed { index, stack -> + (newIn.interfaceDuality.patterns as AppEngInternalInventory).setInventorySlotContents(index, stack) + } + // For output, drop items + val patternsOut = oldOut.interfaceDuality.patterns as AppEngInternalInventory + drops.addAll(patternsOut) + } +} diff --git a/src/main/java/com/projecturanus/betterp2p/network/HashHelper.kt b/src/main/java/com/projecturanus/betterp2p/network/data/HashHelper.kt similarity index 87% rename from src/main/java/com/projecturanus/betterp2p/network/HashHelper.kt rename to src/main/java/com/projecturanus/betterp2p/network/data/HashHelper.kt index 0162e77..b1b3ecd 100644 --- a/src/main/java/com/projecturanus/betterp2p/network/HashHelper.kt +++ b/src/main/java/com/projecturanus/betterp2p/network/data/HashHelper.kt @@ -1,8 +1,7 @@ -package com.projecturanus.betterp2p.network +package com.projecturanus.betterp2p.network.data import appeng.parts.p2p.PartP2PTunnel - /** * Generates a 64-bit hash code from X, Y, Z, Facing, and Dimension info. * bits 0-47: FashHash of (x, y, z) -> @@ -11,11 +10,11 @@ import appeng.parts.p2p.PartP2PTunnel * bit 63: Reserved */ fun hashP2P(x: Int, y: Int, z: Int, facing: Int, dim: Int): Long { - var ret = facing.toULong() shl 61 + val ret = facing.toULong() shl 60 val lo: ULong = x.toULong() or (y.toULong() shl 32) val hi: ULong = z.toULong() or (dim.toULong() shl 32) var hash = hashLen16(lo, hi) - hash = hash xor (hash shr 60) + hash = hash xor (hash shr 59) return (ret or hash).toLong() } @@ -54,8 +53,3 @@ private fun hashLen16(lo: ULong, hi: ULong): ULong { return f } - -/** - * Using `0x80000000` to represent none is selected (aka MSB set) - */ -const val NONE_SELECTED: Long = Long.MIN_VALUE diff --git a/src/main/java/com/projecturanus/betterp2p/network/data/MemoryInfo.kt b/src/main/java/com/projecturanus/betterp2p/network/data/MemoryInfo.kt new file mode 100644 index 0000000..36b83c5 --- /dev/null +++ b/src/main/java/com/projecturanus/betterp2p/network/data/MemoryInfo.kt @@ -0,0 +1,58 @@ +package com.projecturanus.betterp2p.network.data + +import com.projecturanus.betterp2p.client.gui.widget.GuiScale +import com.projecturanus.betterp2p.item.BetterMemoryCardModes + +import io.netty.buffer.ByteBuf + +/** + * Using `-1` to represent any tunnel type. + */ +const val TUNNEL_ANY: Int = -1 + +/** + * A data class for serializing p2p + * @param selectedEntry Points to the index of the selected p2p in the list. + * @param frequency Selected Frequency. 0 = not selected + * @param mode The mode + * @param guiScale The saved gui scale + * @param type The P2P type, indexed in TunnelInfo.kt + */ +data class MemoryInfo( + var selectedEntry: P2PLocation? = null, + var frequency: Long = 0, + var mode: BetterMemoryCardModes = BetterMemoryCardModes.OUTPUT, + var guiScale: GuiScale = GuiScale.DYNAMIC, + var type: Int = TUNNEL_ANY) +fun readMemoryInfo(buf: ByteBuf): MemoryInfo { + var selectedEntry: P2PLocation? = null + if (buf.readBoolean()) { + selectedEntry = readP2PLocation(buf) + } + val frequency = buf.readLong() + val mode = try { + BetterMemoryCardModes.values()[buf.readInt()] + } catch (e: Exception) { + BetterMemoryCardModes.OUTPUT + } + val guiScale = try { + GuiScale.values()[buf.readByte().toInt()] + } catch (e: ArrayIndexOutOfBoundsException) { + GuiScale.DYNAMIC + } + val type = buf.readByte().toInt() + return MemoryInfo(selectedEntry, frequency, mode, guiScale, type) +} + +fun writeMemoryInfo(buf: ByteBuf, info: MemoryInfo) { + val hasSelected = info.selectedEntry != null + + buf.writeBoolean(hasSelected) + if (hasSelected) { + writeP2PLocation(buf, info.selectedEntry!!) + } + buf.writeLong(info.frequency) + buf.writeInt(info.mode.ordinal) + buf.writeByte(info.guiScale.ordinal) + buf.writeByte(info.type) +} diff --git a/src/main/java/com/projecturanus/betterp2p/network/data/P2PInfo.kt b/src/main/java/com/projecturanus/betterp2p/network/data/P2PInfo.kt new file mode 100644 index 0000000..493437f --- /dev/null +++ b/src/main/java/com/projecturanus/betterp2p/network/data/P2PInfo.kt @@ -0,0 +1,109 @@ +package com.projecturanus.betterp2p.network.data + +import net.minecraftforge.common.util.ForgeDirection + +import com.projecturanus.betterp2p.util.p2p.getTypeIndex +import com.projecturanus.betterp2p.util.p2p.hasChannel + +import appeng.me.GridNode +import appeng.parts.p2p.PartP2PTunnel +import io.netty.buffer.ByteBuf + +/** + * Sent over the network to clients. + */ +data class P2PInfo( + val frequency: Long, + val posX: Int, + val posY: Int, + val posZ: Int, + val dim: Int, + val facing: ForgeDirection, + val name: String, + val output: Boolean, + val hasChannel: Boolean, + // # of channels if ME P2P, or -1 else + val channels: Int, + // type of p2p, corresponds to registry in proxy + val type: Int) { + + override fun hashCode(): Int { + return hashP2P(posX, posY, posZ, facing.ordinal, dim).hashCode() + } + + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as P2PInfo + if (this.posX != other.posX) return false + if (this.posY != other.posY) return false + if (this.posZ != other.posZ) return false + if (facing != other.facing) return false + return dim == other.dim + } + +} + +/** + * Deserialize the P2P info over network traffic. + */ +fun readP2PInfo(buf: ByteBuf): P2PInfo? { + try { + val freq = buf.readLong() + val posX = buf.readInt() + val posY = buf.readInt() + val posZ = buf.readInt() + val world = buf.readInt() + val facing = ForgeDirection.values()[buf.readInt()] + val nameLength = buf.readShort() - 1 + val name: StringBuilder = StringBuilder() + for (i in 0..nameLength) { + name.append(buf.readChar()) + } + val output = buf.readBoolean() + val hasChannel = buf.readBoolean() + val channels = buf.readByte().toInt() + val type = buf.readByte().toInt() + return P2PInfo(freq, posX, posY, posZ,world, facing, name.toString(), output, hasChannel, channels, type) + } catch (e: Exception) { + e.printStackTrace() + return null + } +} + +/** + * Serialize the P2P over the network + */ +fun writeP2PInfo(buf: ByteBuf, info: P2PInfo) { + buf.writeLong(info.frequency) + buf.writeInt(info.posX) + buf.writeInt(info.posY) + buf.writeInt(info.posZ) + buf.writeInt(info.dim) + buf.writeInt(info.facing.ordinal) + buf.writeShort(info.name.length) + for (c in info.name) { + buf.writeChar(c.code) + } + buf.writeBoolean(info.output) + buf.writeBoolean(info.hasChannel) + buf.writeByte(info.channels) + buf.writeByte(info.type) +} + +/** + * Convert to [P2PInfo] by extracting the necessary fields + */ +fun PartP2PTunnel<*>.toInfo() = P2PInfo( + frequency, + location.x, + location.y, + location.z, + location.dimension, + side, + customName, + isOutput, + hasChannel, + (externalFacingNode as? GridNode)?.usedChannels() ?: -1, + getTypeIndex()) diff --git a/src/main/java/com/projecturanus/betterp2p/network/data/P2PLocation.kt b/src/main/java/com/projecturanus/betterp2p/network/data/P2PLocation.kt new file mode 100644 index 0000000..5c0b87c --- /dev/null +++ b/src/main/java/com/projecturanus/betterp2p/network/data/P2PLocation.kt @@ -0,0 +1,94 @@ +/* + Hi reviewer. If you see this message, you should make a comment about it and request changes to remove this ;) + */ +package com.projecturanus.betterp2p.network.data + +import net.minecraft.nbt.NBTTagCompound +import net.minecraftforge.common.util.ForgeDirection + +import appeng.parts.p2p.PartP2PTunnel +import io.netty.buffer.ByteBuf + +/** + * A simplified version of P2PInfo that holds only location data. This distinction is useful for + * client->server interactions + */ +data class P2PLocation( + val x: Int, + val y: Int, + val z: Int, + val facing: ForgeDirection, + val dim: Int) { + + override fun hashCode(): Int { + return hashP2P(x, y, z, facing.ordinal, dim).hashCode() + } + + /** + * Autogenerated equals by IntelliJ + */ + override fun equals(other: Any?): Boolean { + if (this === other) return true + if (javaClass != other?.javaClass) return false + + other as P2PLocation + + if (x != other.x) return false + if (y != other.y) return false + if (z != other.z) return false + if (facing != other.facing) return false + return dim == other.dim + } +} + +fun writeP2PLocation(buf: ByteBuf, loc: P2PLocation) { + buf.writeInt(loc.x) + buf.writeInt(loc.y) + buf.writeInt(loc.z) + buf.writeByte(loc.facing.ordinal) + buf.writeInt(loc.dim) +} + +fun readP2PLocation(buf: ByteBuf): P2PLocation? { + return try { + P2PLocation( + x = buf.readInt(), + y = buf.readInt(), + z = buf.readInt(), + facing = ForgeDirection.values()[buf.readByte().toInt()], + dim = buf.readInt()) + } catch (e: Exception) { + e.printStackTrace() + null + } +} + +fun writeP2PLocation(loc: P2PLocation?): NBTTagCompound { + val nbt = NBTTagCompound() + + if (loc != null) { + nbt.setInteger("x", loc.x) + nbt.setInteger("y", loc.y) + nbt.setInteger("z", loc.z) + nbt.setByte("f", loc.facing.ordinal.toByte()) + nbt.setInteger("d", loc.dim) + } + + return nbt +} + +fun readP2PLocation(tag: NBTTagCompound): P2PLocation? { + return try { + P2PLocation( + x = tag.getInteger("x"), + y = tag.getInteger("y"), + z = tag.getInteger("z"), + facing = ForgeDirection.values()[tag.getByte("f").toInt()], + dim = tag.getInteger("d")) + } catch (e: Exception) { + e.printStackTrace() + null + } +} + +fun PartP2PTunnel<*>.toLoc() = P2PLocation(location.x, location.y, location.z, side, location.dimension) diff --git a/src/main/java/com/projecturanus/betterp2p/network/ServerCloseGuiHandler.kt b/src/main/java/com/projecturanus/betterp2p/network/packet/C2SCloseGui.kt similarity index 51% rename from src/main/java/com/projecturanus/betterp2p/network/ServerCloseGuiHandler.kt rename to src/main/java/com/projecturanus/betterp2p/network/packet/C2SCloseGui.kt index eb743df..a3005b2 100644 --- a/src/main/java/com/projecturanus/betterp2p/network/ServerCloseGuiHandler.kt +++ b/src/main/java/com/projecturanus/betterp2p/network/packet/C2SCloseGui.kt @@ -1,13 +1,23 @@ -package com.projecturanus.betterp2p.network +package com.projecturanus.betterp2p.network.packet + +import com.projecturanus.betterp2p.network.ModNetwork -import com.projecturanus.betterp2p.util.p2p.P2PCache 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 C2SCloseGui : IMessage { + override fun fromBytes(buf: ByteBuf) { + } + + override fun toBytes(buf: ByteBuf) { + } +} class ServerCloseGuiHandler : IMessageHandler { override fun onMessage(message: C2SCloseGui, ctx: MessageContext): IMessage? { - P2PCache.statusMap.remove(ctx.serverHandler.playerEntity.uniqueID) + ModNetwork.playerState.remove(ctx.serverHandler.playerEntity.uniqueID) return null } diff --git a/src/main/java/com/projecturanus/betterp2p/network/packet/C2SLinkP2P.kt b/src/main/java/com/projecturanus/betterp2p/network/packet/C2SLinkP2P.kt new file mode 100644 index 0000000..625d3b9 --- /dev/null +++ b/src/main/java/com/projecturanus/betterp2p/network/packet/C2SLinkP2P.kt @@ -0,0 +1,43 @@ +package com.projecturanus.betterp2p.network.packet + +import com.projecturanus.betterp2p.network.ModNetwork +import com.projecturanus.betterp2p.network.data.P2PLocation +import com.projecturanus.betterp2p.network.data.readP2PLocation +import com.projecturanus.betterp2p.network.data.writeP2PLocation + +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 + +/** + * Client->Server packet that links 2 P2Ps together. + */ +class C2SLinkP2P(var input: P2PLocation? = null, var output: P2PLocation? = null): IMessage { + override fun fromBytes(buf: ByteBuf) { + input = readP2PLocation(buf) + output = readP2PLocation(buf) + } + + override fun toBytes(buf: ByteBuf) { + writeP2PLocation(buf, input!!) + writeP2PLocation(buf, output!!) + } +} + +class ServerLinkP2PHandler : IMessageHandler { + override fun onMessage(message: C2SLinkP2P, ctx: MessageContext): IMessage? { + // Validate message + if (message.input == null || message.output == null) { + return null + } + val state = ModNetwork.playerState[ctx.serverHandler.playerEntity.uniqueID] ?: return null + val result = state.gridCache.linkP2P(message.input!!, message.output!!) + + if (result != null) { + ModNetwork.requestP2PUpdate(ctx.serverHandler.playerEntity) + } + + return null + } +} diff --git a/src/main/java/com/projecturanus/betterp2p/network/packet/C2SRefreshP2PList.kt b/src/main/java/com/projecturanus/betterp2p/network/packet/C2SRefreshP2PList.kt new file mode 100644 index 0000000..f8d4a17 --- /dev/null +++ b/src/main/java/com/projecturanus/betterp2p/network/packet/C2SRefreshP2PList.kt @@ -0,0 +1,35 @@ +package com.projecturanus.betterp2p.network.packet + +import com.projecturanus.betterp2p.network.ModNetwork +import com.projecturanus.betterp2p.network.data.TUNNEL_ANY + +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 + +/** + * Send a request to the server to refresh the p2p list with the given type. This must be validated + * by the server side. This is a full refresh (not just an update). + */ +class C2SRefreshP2PList(var type: Int = TUNNEL_ANY): IMessage { + override fun fromBytes(buf: ByteBuf) { + type = buf.readByte().toInt() + } + + override fun toBytes(buf: ByteBuf) { + buf.writeByte(type) + } +} + +/** + * Server handler. + * Handler on server side + */ +class ServerRefreshP2PListHandler : IMessageHandler { + override fun onMessage(message: C2SRefreshP2PList, ctx: MessageContext): IMessage? { + ModNetwork.requestP2PList(ctx.serverHandler.playerEntity, message.type) + + return null + } +} diff --git a/src/main/java/com/projecturanus/betterp2p/network/packet/C2SRenameP2P.kt b/src/main/java/com/projecturanus/betterp2p/network/packet/C2SRenameP2P.kt new file mode 100644 index 0000000..3874a41 --- /dev/null +++ b/src/main/java/com/projecturanus/betterp2p/network/packet/C2SRenameP2P.kt @@ -0,0 +1,79 @@ +package com.projecturanus.betterp2p.network.packet + +import net.minecraft.tileentity.TileEntity +import net.minecraft.world.World +import net.minecraftforge.common.DimensionManager + +import com.projecturanus.betterp2p.network.ModNetwork +import com.projecturanus.betterp2p.network.data.P2PLocation +import com.projecturanus.betterp2p.network.data.readP2PLocation +import com.projecturanus.betterp2p.network.data.writeP2PLocation + +import appeng.api.networking.IGridHost +import appeng.api.parts.IPartHost +import appeng.parts.p2p.PartP2PTunnel +import com.projecturanus.betterp2p.network.data.toLoc +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 + +/** + * Client->Server packet for rename operation + */ +class C2SRenameP2P(var p2p: P2PLocation? = null, var name: String = ""): IMessage { + + override fun fromBytes(buf: ByteBuf) { + p2p = readP2PLocation(buf) + val length = buf.readInt() + val nameB = StringBuilder() + for (i in 0 until length) { + nameB.append(buf.readChar()) + } + name = nameB.toString() + } + + override fun toBytes(buf: ByteBuf) { + writeP2PLocation(buf, p2p!!) + buf.writeInt(name.length) + for (c in name) { + buf.writeChar(c.code) + } + } +} + +/** + * Handler for renaming p2p tunnels. + */ +class ServerRenameP2PTunnel : IMessageHandler { + override fun onMessage(message: C2SRenameP2P, ctx: MessageContext): IMessage? { + if (message.p2p == null) { + return null + } + + val world: World = DimensionManager.getWorld(message.p2p!!.dim) + val te: TileEntity = world.getTileEntity(message.p2p!!.x, message.p2p!!.y, message.p2p!!.z) + val state = ModNetwork.playerState[ctx.serverHandler.playerEntity.uniqueID] ?: return null + val facing = message.p2p!!.facing + if (te is IGridHost && te.getGridNode(facing) != null) { + val partTunnel = (te as IPartHost).getPart(facing) + + if (partTunnel is PartP2PTunnel<*>) { + partTunnel.customName = message.name + val input: PartP2PTunnel<*> = if (partTunnel.isOutput) { + partTunnel.input + } else { + partTunnel + } + // Mark all dirty. + input.outputs.forEach { + state.gridCache.markDirty(it.toLoc(), it) + } + state.gridCache.markDirty(input.toLoc(), input) + + ModNetwork.requestP2PUpdate(ctx.serverHandler.playerEntity) + } + } + return null + } +} diff --git a/src/main/java/com/projecturanus/betterp2p/network/packet/C2STypeChange.kt b/src/main/java/com/projecturanus/betterp2p/network/packet/C2STypeChange.kt new file mode 100644 index 0000000..449802d --- /dev/null +++ b/src/main/java/com/projecturanus/betterp2p/network/packet/C2STypeChange.kt @@ -0,0 +1,43 @@ +package com.projecturanus.betterp2p.network.packet + +import com.projecturanus.betterp2p.BetterP2P +import com.projecturanus.betterp2p.network.ModNetwork +import com.projecturanus.betterp2p.network.data.P2PLocation +import com.projecturanus.betterp2p.network.data.TUNNEL_ANY +import com.projecturanus.betterp2p.network.data.readP2PLocation +import com.projecturanus.betterp2p.network.data.writeP2PLocation + +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: P2PLocation? = null): IMessage { + override fun fromBytes(buf: ByteBuf) { + newType = buf.readByte().toInt() + p2p = readP2PLocation(buf) + } + + override fun toBytes(buf: ByteBuf) { + buf.writeByte(newType) + writeP2PLocation(buf, p2p!!) + } +} + +class ServerTypeChangeHandler : IMessageHandler { + override fun onMessage(message: C2STypeChange, ctx: MessageContext): IMessage? { + // Validate message + if (message.p2p == null) { + return null + } + + val state = ModNetwork.playerState[ctx.serverHandler.playerEntity.uniqueID] ?: return null + val type = BetterP2P.proxy.getP2PFromIndex(message.newType) ?: return null + + if (state.gridCache.changeAllP2Ps(message.p2p!!, type)) { + ModNetwork.requestP2PList(ctx.serverHandler.playerEntity, type.index) + } + + return null + } +} diff --git a/src/main/java/com/projecturanus/betterp2p/network/packet/C2SUnlinkP2P.kt b/src/main/java/com/projecturanus/betterp2p/network/packet/C2SUnlinkP2P.kt new file mode 100644 index 0000000..91ea7e0 --- /dev/null +++ b/src/main/java/com/projecturanus/betterp2p/network/packet/C2SUnlinkP2P.kt @@ -0,0 +1,47 @@ +package com.projecturanus.betterp2p.network.packet + +import com.projecturanus.betterp2p.network.ModNetwork +import com.projecturanus.betterp2p.network.data.P2PLocation +import com.projecturanus.betterp2p.network.data.TUNNEL_ANY +import com.projecturanus.betterp2p.network.data.readP2PLocation +import com.projecturanus.betterp2p.network.data.writeP2PLocation + +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 + +/** + * Unlink input from outputs message (set freq to 0) + */ +class C2SUnlinkP2P(var p2p: P2PLocation? = null, var type: Int = TUNNEL_ANY): IMessage { + override fun fromBytes(buf: ByteBuf) { + p2p = readP2PLocation(buf) + type = buf.readByte().toInt() + } + + override fun toBytes(buf: ByteBuf) { + // Clientside can crash if they want to send faulty packets :P + writeP2PLocation(buf, p2p!!) + buf.writeByte(type) + } +} + +/** + * Client -> Server + * Handler on server side + */ +class ServerUnlinkP2PHandler : IMessageHandler { + override fun onMessage(message: C2SUnlinkP2P, ctx: MessageContext): S2COpenGui? { + // message validation + if (message.p2p == null) { + return null + } + val cache = ModNetwork.playerState[ctx.serverHandler.playerEntity.uniqueID] ?: return null + + cache.gridCache.unlinkP2P(message.p2p!!) + ModNetwork.requestP2PUpdate(ctx.serverHandler.playerEntity) + + return null + } +} diff --git a/src/main/java/com/projecturanus/betterp2p/network/packet/C2SUpdateMemoryInfo.kt b/src/main/java/com/projecturanus/betterp2p/network/packet/C2SUpdateMemoryInfo.kt new file mode 100644 index 0000000..2a6b7ed --- /dev/null +++ b/src/main/java/com/projecturanus/betterp2p/network/packet/C2SUpdateMemoryInfo.kt @@ -0,0 +1,39 @@ +package com.projecturanus.betterp2p.network.packet + +import com.projecturanus.betterp2p.item.ItemAdvancedMemoryCard +import com.projecturanus.betterp2p.network.data.MemoryInfo +import com.projecturanus.betterp2p.network.data.readMemoryInfo +import com.projecturanus.betterp2p.network.data.writeMemoryInfo + +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 + +/** + * Client->Server: Update the advanced memory card data + */ +class C2SUpdateMemoryInfo(var info: MemoryInfo = MemoryInfo()) : IMessage { + + override fun fromBytes(buf: ByteBuf) { + info = readMemoryInfo(buf) + } + + override fun toBytes(buf: ByteBuf) { + writeMemoryInfo(buf, info) + } +} + +class ServerUpdateInfoHandler : IMessageHandler { + + override fun onMessage(message: C2SUpdateMemoryInfo, ctx: MessageContext): IMessage? { + val player = ctx.serverHandler.playerEntity + val stack = player.heldItem + + if (stack.item is ItemAdvancedMemoryCard) { + ItemAdvancedMemoryCard.writeInfo(stack, message.info) + } + + return null + } +} diff --git a/src/main/java/com/projecturanus/betterp2p/network/packet/S2COpenGui.kt b/src/main/java/com/projecturanus/betterp2p/network/packet/S2COpenGui.kt new file mode 100644 index 0000000..a69bedb --- /dev/null +++ b/src/main/java/com/projecturanus/betterp2p/network/packet/S2COpenGui.kt @@ -0,0 +1,57 @@ +package com.projecturanus.betterp2p.network.packet + +import net.minecraft.client.Minecraft + +import com.projecturanus.betterp2p.client.gui.GuiAdvancedMemoryCard +import com.projecturanus.betterp2p.network.data.* +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 cpw.mods.fml.relauncher.Side +import cpw.mods.fml.relauncher.SideOnly +import io.netty.buffer.ByteBuf + +/** + * A Server->Client packet that sends a list of P2Ps over the net. + */ +class S2COpenGui(var infos: List = emptyList(), + var memoryInfo: MemoryInfo = MemoryInfo()) : IMessage { + override fun fromBytes(buf: ByteBuf) { + val length = buf.readInt() + val list = ArrayList(length) + + for (i in 0 until length) { + val info = readP2PInfo(buf) + + if (info != null) { + list.add(info) + } + } + + infos = list + memoryInfo = readMemoryInfo(buf) + } + + override fun toBytes(buf: ByteBuf) { + buf.writeInt(infos.size) + infos.forEach { writeP2PInfo(buf, it) } + writeMemoryInfo(buf, memoryInfo) + } +} + +/** + * Handler on client side for GUI open. + */ +class ClientOpenGuiHandler : IMessageHandler { + @SideOnly(Side.CLIENT) + override fun onMessage(message: S2COpenGui, ctx: MessageContext): IMessage? { + val gui = Minecraft.getMinecraft().currentScreen + if (gui is GuiAdvancedMemoryCard) { + gui.refreshInfo(message.infos) + } else { + Minecraft.getMinecraft().displayGuiScreen(GuiAdvancedMemoryCard(message)) + } + return null + } +} + diff --git a/src/main/java/com/projecturanus/betterp2p/network/packet/S2CUpdateP2P.kt b/src/main/java/com/projecturanus/betterp2p/network/packet/S2CUpdateP2P.kt new file mode 100644 index 0000000..5d82ee8 --- /dev/null +++ b/src/main/java/com/projecturanus/betterp2p/network/packet/S2CUpdateP2P.kt @@ -0,0 +1,62 @@ +package com.projecturanus.betterp2p.network.packet + +import net.minecraft.client.Minecraft + +import com.projecturanus.betterp2p.client.gui.GuiAdvancedMemoryCard +import com.projecturanus.betterp2p.network.data.P2PInfo +import com.projecturanus.betterp2p.network.data.readP2PInfo +import com.projecturanus.betterp2p.network.data.writeP2PInfo + +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 cpw.mods.fml.relauncher.Side +import cpw.mods.fml.relauncher.SideOnly +import io.netty.buffer.ByteBuf + +/** + * Server -> Client packet for sending P2P updates. More lightweight than OpenGui. + */ +class S2CUpdateP2P(var infos: List = emptyList(), var clear: Boolean = false): IMessage { + override fun fromBytes(buf: ByteBuf) { + val length = buf.readInt() + val list = ArrayList(length) + + for (i in 0 until length) { + val info = readP2PInfo(buf) + + if (info != null) { + list.add(info) + } + } + + infos = list + clear = buf.readBoolean() + } + + override fun toBytes(buf: ByteBuf) { + buf.writeInt(infos.size) + infos.forEach { writeP2PInfo(buf, it) } + buf.writeBoolean(clear) + } +} + +/** + * Handler on client side for updating P2Ps. + */ +class ClientUpdateP2PHandler : IMessageHandler { + @SideOnly(Side.CLIENT) + override fun onMessage(message: S2CUpdateP2P, ctx: MessageContext): IMessage? { + val gui = Minecraft.getMinecraft().currentScreen + + if (gui is GuiAdvancedMemoryCard) { + if (message.clear) { + gui.refreshInfo(message.infos) + } else { + gui.updateInfo(message.infos) + } + } + + return null + } +} diff --git a/src/main/java/com/projecturanus/betterp2p/util/CableBusUtil.kt b/src/main/java/com/projecturanus/betterp2p/util/CableBusUtil.kt index 2bc171c..a12280c 100644 --- a/src/main/java/com/projecturanus/betterp2p/util/CableBusUtil.kt +++ b/src/main/java/com/projecturanus/betterp2p/util/CableBusUtil.kt @@ -1,21 +1,16 @@ package com.projecturanus.betterp2p.util -import appeng.api.config.SecurityPermissions -import appeng.api.networking.IGrid -import appeng.api.networking.security.ISecurityGrid +import net.minecraft.tileentity.TileEntity +import net.minecraft.util.EnumFacing +import net.minecraft.util.Vec3 +import net.minecraft.world.IBlockAccess + import appeng.api.parts.IPart import appeng.api.parts.IPartHost import appeng.api.parts.SelectedPart import appeng.parts.AEBasePart import appeng.parts.ICableBusContainer -import appeng.parts.p2p.PartP2PTunnel -import appeng.parts.p2p.PartP2PTunnelNormal import appeng.tile.networking.TileCableBus -import net.minecraft.entity.player.EntityPlayer -import net.minecraft.tileentity.TileEntity -import net.minecraft.util.EnumFacing -import net.minecraft.util.Vec3 -import net.minecraft.world.IBlockAccess /** * @see appeng.block.networking.BlockCableBus.cb @@ -37,33 +32,6 @@ fun getPart(w: IBlockAccess, posX: Int, posY: Int, posZ: Int, hitX: Float, hitY: return p?.part } -/** - * Return a list of p2p in the part's target grid - * @param grid Grid - * @param player Player to check permission - * @param clazz P2P class type - * @return a list of p2p tunnel in the target grid, or an empty list - */ -fun listTargetGridP2P(grid: IGrid?, player: EntityPlayer, clazz: Class>): List> { - if (grid is ISecurityGrid) - if (!grid.hasPermission(player, SecurityPermissions.BUILD)) - return emptyList() - - return grid?.getMachines(clazz)?.map { it.machine as PartP2PTunnel<*> }?.toList() ?: emptyList() -} - -fun listAllGridP2P(grid: IGrid?, player: EntityPlayer): List> { - if (grid is ISecurityGrid && !grid.hasPermission(player, SecurityPermissions.BUILD)) - return emptyList() - val classes = grid?.machinesClasses?.filter { - // Find all P2P tunnels... - c -> c.superclass.superclass == PartP2PTunnel::class.java - } ?: emptyList() - val ret: MutableList> = mutableListOf() - classes.forEach{ c -> ret.addAll(grid?.getMachines(c)?.map { it.machine as PartP2PTunnel<*> } ?: emptyList()) } - return ret -} - val AEBasePart.facingPosX: Int? get() = host?.location?.x?.and(side?.offsetX ?: EnumFacing.UP.frontOffsetX) diff --git a/src/main/java/com/projecturanus/betterp2p/util/p2p/LinkException.kt b/src/main/java/com/projecturanus/betterp2p/util/p2p/LinkException.kt deleted file mode 100644 index 9bb219d..0000000 --- a/src/main/java/com/projecturanus/betterp2p/util/p2p/LinkException.kt +++ /dev/null @@ -1,3 +0,0 @@ -package com.projecturanus.betterp2p.util.p2p - -class LinkException(message: String? = null) : RuntimeException(message) diff --git a/src/main/java/com/projecturanus/betterp2p/util/p2p/P2PCache.kt b/src/main/java/com/projecturanus/betterp2p/util/p2p/P2PCache.kt deleted file mode 100644 index 4405855..0000000 --- a/src/main/java/com/projecturanus/betterp2p/util/p2p/P2PCache.kt +++ /dev/null @@ -1,10 +0,0 @@ -package com.projecturanus.betterp2p.util.p2p - -import java.util.* - -/** - * Cache P2P status for client to use - */ -object P2PCache { - val statusMap: MutableMap = Collections.synchronizedMap(WeakHashMap()) -} diff --git a/src/main/java/com/projecturanus/betterp2p/util/p2p/P2PStatus.kt b/src/main/java/com/projecturanus/betterp2p/util/p2p/P2PStatus.kt deleted file mode 100644 index cd5dda9..0000000 --- a/src/main/java/com/projecturanus/betterp2p/util/p2p/P2PStatus.kt +++ /dev/null @@ -1,53 +0,0 @@ -package com.projecturanus.betterp2p.util.p2p - -import appeng.api.networking.IGrid -import appeng.parts.p2p.PartP2PTunnel -import com.projecturanus.betterp2p.BetterP2P -import com.projecturanus.betterp2p.capability.TUNNEL_ANY -import com.projecturanus.betterp2p.network.P2PInfo -import com.projecturanus.betterp2p.network.hashP2P -import com.projecturanus.betterp2p.util.listAllGridP2P -import net.minecraft.entity.player.EntityPlayer - -/** - * When the player uses the adv memory card, this is cached on the server side - * to provide access to the Grid when the player performs actions in the GUI. - */ -class P2PStatus(val grid: IGrid, val player: EntityPlayer, type: Int) { - /** - * The P2P list. This is a list of all P2Ps, and only the requested - * ones are sent. - */ - val listP2P: MutableMap> = mutableMapOf() - - /** - * Server copy of the p2p currently selected in client - */ - var lastP2PType: Int = type - - /** - * Refreshes the p2p list - */ - private fun rebuildList() { - listP2P.clear() - listAllGridP2P(grid, player).forEach { listP2P[hashP2P(it)] = it } - } - - /** - * Refreshes and gets the p2p list of the targeted type - * @param type if TUNNEL_ANY or invalid, returns the full list; else - * filters the list to the targeted type - */ - fun refresh(type: Int): List { - rebuildList() - return if (type == TUNNEL_ANY) { - listP2P.values.map { it.toInfo() } - } else { - listP2P.values.mapNotNull { - if ((BetterP2P.proxy.getP2PFromClass(it.javaClass)?.index ?: TUNNEL_ANY) == type) { - it.toInfo() - } else null - } - } - } -} diff --git a/src/main/java/com/projecturanus/betterp2p/util/p2p/P2PUtil.kt b/src/main/java/com/projecturanus/betterp2p/util/p2p/P2PUtil.kt index 35fef51..7729d1f 100644 --- a/src/main/java/com/projecturanus/betterp2p/util/p2p/P2PUtil.kt +++ b/src/main/java/com/projecturanus/betterp2p/util/p2p/P2PUtil.kt @@ -1,259 +1,9 @@ package com.projecturanus.betterp2p.util.p2p -import appeng.api.config.SecurityPermissions -import appeng.api.networking.IGrid -import appeng.api.networking.security.ISecurityGrid -import appeng.api.parts.IPart -import appeng.api.parts.PartItemStack -import appeng.helpers.IInterfaceHost -import appeng.me.GridAccessException -import appeng.me.GridNode -import appeng.me.cache.P2PCache -import appeng.parts.automation.UpgradeInventory -import appeng.parts.p2p.PartP2PInterface -import appeng.parts.p2p.PartP2PTunnel -import appeng.parts.p2p.PartP2PTunnelNormal -import appeng.parts.p2p.PartP2PTunnelStatic -import appeng.tile.inventory.AppEngInternalInventory -import appeng.util.Platform import com.projecturanus.betterp2p.BetterP2P -import com.projecturanus.betterp2p.capability.TUNNEL_ANY -import com.projecturanus.betterp2p.network.P2PInfo -import net.minecraft.entity.player.EntityPlayer -import net.minecraft.item.ItemStack -import net.minecraft.nbt.NBTTagCompound -import net.minecraft.util.ChatComponentText -import net.minecraft.util.ChatComponentTranslation -import net.minecraftforge.common.util.ForgeDirection +import com.projecturanus.betterp2p.network.data.TUNNEL_ANY -fun linkP2P(player: EntityPlayer, inputIndex: Long, outputIndex: Long, status: P2PStatus) : Pair, PartP2PTunnel<*>>? { - // If these calls mess up we have bigger problems... - val input = status.listP2P[inputIndex] ?: return null - var output = status.listP2P[outputIndex] ?: return null - - val grid: IGrid? = input.gridNode?.grid - if (grid is ISecurityGrid) { - if (!grid.hasPermission(player, SecurityPermissions.BUILD) || !grid.hasPermission(player, SecurityPermissions.SECURITY)) { - return null - } - } - - // TODO Change to exception - if (input.javaClass != output.javaClass) { - //change output to input - output = changeP2P(output, BetterP2P.proxy.getP2PFromClass(input.javaClass)!!, player) ?: return null - } - if (input == output) { - // Network loop - return null - } - var frequency = input.frequency - val cache = input.proxy.p2P - // TODO reduce changes - if (input.frequency == 0L || input.isOutput) { - frequency = System.currentTimeMillis() - } - // If tunnel was already bound, unbind that one - if (cache.getInput(frequency) != null) { - val originalInput = cache.getInput(frequency) - if (originalInput != input) { - updateP2P(originalInput, frequency, true, player, input.customName) - } - } - val inputResult: PartP2PTunnel<*> = updateP2P(input, frequency, false, player, input.customName) - val outputResult: PartP2PTunnel<*> = updateP2P(output, frequency, true, player, input.customName) - if (input is IInterfaceHost && output is IInterfaceHost) { - // For input and output, retain upgrades, items, and settings. - inputResult as IInterfaceHost - outputResult as IInterfaceHost - val upgradesIn = input.interfaceDuality.getInventoryByName("upgrades") as UpgradeInventory - upgradesIn.forEachIndexed { index, stack -> - (inputResult.interfaceDuality.getInventoryByName("upgrades") as UpgradeInventory).setInventorySlotContents(index, stack) - } - val upgradesOut = output.interfaceDuality.getInventoryByName("upgrades") as UpgradeInventory - upgradesOut.forEachIndexed { index, stack -> - (outputResult.interfaceDuality.getInventoryByName("upgrades") as UpgradeInventory).setInventorySlotContents(index, stack) - } - val itemsIn = input.interfaceDuality.storage as AppEngInternalInventory - itemsIn.forEachIndexed { index, stack -> - (inputResult.interfaceDuality.storage as AppEngInternalInventory).setInventorySlotContents(index, stack) - } - val itemsOut = output.interfaceDuality.storage as AppEngInternalInventory - itemsOut.forEachIndexed { index, stack -> - (outputResult.interfaceDuality.storage as AppEngInternalInventory).setInventorySlotContents(index, stack) - } - val settingsIn = input.interfaceDuality.configManager - settingsIn.settings.forEach { - inputResult.configManager.putSetting(it, settingsIn.getSetting(it)) - } - val settingsOut = output.interfaceDuality.configManager - settingsOut.settings.forEach { - outputResult.configManager.putSetting(it, settingsOut.getSetting(it)) - } - - // For input, just copy the patterns over - val patternsIn = input.interfaceDuality.patterns as AppEngInternalInventory - patternsIn.forEachIndexed { index, stack -> - (inputResult.interfaceDuality.patterns as AppEngInternalInventory).setInventorySlotContents(index, stack) - } - // For output, drop items - val dropItems = mutableListOf() - val patternsOut = output.interfaceDuality.patterns as AppEngInternalInventory - dropItems.addAll(patternsOut) - Platform.spawnDrops(player.worldObj, output.location.x, output.location.y, output.location.z, dropItems) - } - return inputResult to outputResult -} - -fun unlinkP2P(player: EntityPlayer, p2pIndex: Long, status: P2PStatus): PartP2PTunnel<*>? { - if (status.grid is ISecurityGrid) { - if (!status.grid.hasPermission(player, SecurityPermissions.BUILD) || - !status.grid.hasPermission(player, SecurityPermissions.SECURITY)) { - return null - } - } - val tunnel = status.listP2P[p2pIndex] ?: return null - val oldFreq = tunnel.frequency - if (oldFreq == 0L) { - return tunnel - } - - updateP2P(tunnel, 0L, false, player, tunnel.customName) - 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) { - player.addChatMessage(ChatComponentText("P2P already this type.")) - return null - } - if (newType.clazz.superclass == PartP2PTunnelStatic::class.java) { - var canConvert = false - for ((i, stack) in player.inventory.mainInventory.withIndex()) { - if (stack?.isItemEqual(newType.stack) == true) { - player.inventory.decrStackSize(i, 1) - canConvert = true - break - } - } - if (!canConvert) { - player.addChatMessage(ChatComponentTranslation("gui.advanced_memory_card.error.missing_items", 1, newType.stack.displayName)) - return null - } - } - if (tunnel is PartP2PTunnelStatic<*>) { - val drop = ItemStack.copyItemStack(tunnel.itemStack) - drop.stackSize = 1 - if (!player.inventory.addItemStackToInventory(drop)) { - val drops = mutableListOf(drop) - tunnel.getDrops(drops, false) - Platform.spawnDrops(player.worldObj, player.serverPosX, player.serverPosY, player.serverPosZ, drops) - } - } - - 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() - if (newType.clazz.superclass == PartP2PTunnelStatic::class.java) { - val amt = outputs.size + 1 - var hasItems = false - for ((i, stack) in player.inventory.mainInventory.withIndex()) { - if (stack?.isItemEqual(newType.stack) == true && stack.stackSize >= amt) { - player.inventory.decrStackSize(i, 1) - hasItems = true - break - } - } - if (!hasItems) { - player.addChatMessage(ChatComponentTranslation("gui.advanced_memory_card.error.missing_items", amt, newType.stack.displayName)) - return false - } - } - 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 - */ -fun updateP2P(tunnel: PartP2PTunnel<*>, frequency: Long, output: Boolean, player: EntityPlayer, name: String): PartP2PTunnel<*> { - val side = tunnel.side - val data = NBTTagCompound() - - tunnel.host.removePart(side, true) - - val p2pItem: ItemStack = tunnel.getItemStack(PartItemStack.Wrench) - - tunnel.outputProperty = output - tunnel.customName = name - - p2pItem.writeToNBT(data) - data.setLong("freq", frequency) - - val newType = ItemStack.loadItemStackFromNBT(data) - val dir: ForgeDirection = tunnel.host?.addPart(newType, side, player) ?: throw RuntimeException("Cannot bind") - val newBus: IPart = tunnel.host.getPart(dir) - if (newBus is PartP2PTunnel<*>) { - newBus.outputProperty = output - try { - val p2p = newBus.proxy.p2P - p2p.updateFreq(newBus, frequency) - } catch (e: GridAccessException) { - // :P - } - newBus.onTunnelNetworkChange() - return newBus - } else { - throw RuntimeException("Cannot bind") - } -} +import appeng.parts.p2p.PartP2PTunnel var PartP2PTunnel<*>.outputProperty get() = isOutput @@ -266,11 +16,6 @@ var PartP2PTunnel<*>.outputProperty val PartP2PTunnel<*>.hasChannel get() = isPowered && isActive -fun PartP2PTunnel<*>.toInfo() - = P2PInfo(frequency, location.x, location.y, location.z, location.dimension, side, - customName, isOutput, hasChannel, (externalFacingNode as? GridNode)?.usedChannels() ?: -1, - getTypeIndex()) - /** * Get the type index or use TUNNEL_ANY */ diff --git a/src/main/java/com/projecturanus/betterp2p/util/p2p/TunnelInfo.kt b/src/main/java/com/projecturanus/betterp2p/util/p2p/TunnelInfo.kt index 3f8aee3..511df95 100644 --- a/src/main/java/com/projecturanus/betterp2p/util/p2p/TunnelInfo.kt +++ b/src/main/java/com/projecturanus/betterp2p/util/p2p/TunnelInfo.kt @@ -1,9 +1,10 @@ package com.projecturanus.betterp2p.util.p2p -import appeng.parts.p2p.PartP2PTunnel import net.minecraft.item.ItemStack import net.minecraft.util.IIcon +import appeng.parts.p2p.PartP2PTunnel + /** * Common tunnel info to be used on server */ diff --git a/src/main/resources/assets/betterp2p/lang/en_US.lang b/src/main/resources/assets/betterp2p/lang/en_US.lang index 559c000..f6a0523 100644 --- a/src/main/resources/assets/betterp2p/lang/en_US.lang +++ b/src/main/resources/assets/betterp2p/lang/en_US.lang @@ -45,3 +45,4 @@ gui.advanced_memory_card.p2p_status.offline=Offline gui.advanced_memory_card.types.filtered=Showing: %s gui.advanced_memory_card.types.any=§aAll gui.advanced_memory_card.error.missing_items=Cannot change P2P type without %dx %s(s). +gui.advanced_memory_card.error.same_type=P2P already this type.