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.