diff --git a/build.gradle b/build.gradle index e57a16f..04407ff 100644 --- a/build.gradle +++ b/build.gradle @@ -2,4 +2,4 @@ plugins { id 'com.gtnewhorizons.gtnhconvention' -} +} \ No newline at end of file diff --git a/src/main/resources/assets/ae2stuff/lang/en_US.lang b/src/main/resources/assets/ae2stuff/lang/en_US.lang index 3631f3a..e6b0faf 100644 --- a/src/main/resources/assets/ae2stuff/lang/en_US.lang +++ b/src/main/resources/assets/ae2stuff/lang/en_US.lang @@ -4,6 +4,7 @@ tile.ae2stuff.Inscriber.name=Advanced Inscriber tile.ae2stuff.Wireless.name=Wireless Connector item.ae2stuff.WirelessKit.name=Wireless Setup Kit +item.ae2stuff.AdvWirelessKit.name=Advanced Wireless Setup Kit item.ae2stuff.Visualiser.name=Network Visualisation Tool ae2stuff.error.not_connected=Network not connected @@ -27,6 +28,19 @@ ae2stuff.gui.recipes=Recipes ae2stuff.wireless.tool.empty=Click Wireless Connector to bind ae2stuff.wireless.tool.bound1=Bound to %s,%s,%s ae2stuff.wireless.tool.bound2=Click other Wireless Connector to connect +ae2stuff.wireless.advtool.queueing=§aQueuing Mode +ae2stuff.wireless.advtool.binding=§aBinding Mode +ae2stuff.wireless.advtool.queueing.activated=Queuing mode activated +ae2stuff.wireless.advtool.binding.activated=Binding mode activated +ae2stuff.wireless.advtool.queued=Added connector at %s,%s,%s to queue +ae2stuff.wireless.advtool.queueing.empty=Click Wireless Connectors to add to binding queue +ae2stuff.wireless.advtool.binding.empty=Switch to Queuing Mode to add connectors to queue +ae2stuff.wireless.advtool.queueing.notempty=Current wireless connectors in queue: +ae2stuff.wireless.advtool.binding.notempty=Current wireless connectors in queue to be bound: +ae2stuff.wireless.advtool.connector.next=Next connector in queue: %s,%s,%s +ae2stuff.wireless.advtool.extra=§oSneak right click to change mode between queuing and binding mode +ae2stuff.wireless.advtool.noconnectors=No connectors found in queue. Try putting the tool into queueing mode and adding some +ae2stuff.wireless.advtool.pop=Removed %s,%s,%s from queue ae2stuff.wireless.tool.connected=Connected to %s,%s,%s ae2stuff.wireless.tool.failed=Connection failed ae2stuff.wireless.tool.dimension=Both connectors must be in the same dimension diff --git a/src/main/resources/assets/ae2stuff/textures/items/advwirelesskit.png b/src/main/resources/assets/ae2stuff/textures/items/advwirelesskit.png new file mode 100644 index 0000000..76e6891 Binary files /dev/null and b/src/main/resources/assets/ae2stuff/textures/items/advwirelesskit.png differ diff --git a/src/main/scala/net/bdew/ae2stuff/AE2Stuff.scala b/src/main/scala/net/bdew/ae2stuff/AE2Stuff.scala index 92c2d34..a40f13e 100644 --- a/src/main/scala/net/bdew/ae2stuff/AE2Stuff.scala +++ b/src/main/scala/net/bdew/ae2stuff/AE2Stuff.scala @@ -90,6 +90,7 @@ object AE2Stuff { def postInit(event: FMLPostInitializationEvent): Unit = { TuningLoader.loadDelayed() onPostInit.trigger(event) + Recipes.load() } @EventHandler diff --git a/src/main/scala/net/bdew/ae2stuff/Items.scala b/src/main/scala/net/bdew/ae2stuff/Items.scala index 2156546..4cdbf52 100644 --- a/src/main/scala/net/bdew/ae2stuff/Items.scala +++ b/src/main/scala/net/bdew/ae2stuff/Items.scala @@ -9,14 +9,16 @@ package net.bdew.ae2stuff -import net.bdew.ae2stuff.items.ItemWirelessKit +import net.bdew.ae2stuff.items.{AdvWirelessKit, ItemWirelessKit} import net.bdew.ae2stuff.items.visualiser.ItemVisualiser import net.bdew.ae2stuff.machines.wireless.MachineWireless import net.bdew.lib.config.ItemManager object Items extends ItemManager(CreativeTabs.main) { - if (MachineWireless.enabled) + if (MachineWireless.enabled) { regItem(ItemWirelessKit) + regItem(AdvWirelessKit) + } regItem(ItemVisualiser) } diff --git a/src/main/scala/net/bdew/ae2stuff/Recipes.scala b/src/main/scala/net/bdew/ae2stuff/Recipes.scala new file mode 100644 index 0000000..e0279f8 --- /dev/null +++ b/src/main/scala/net/bdew/ae2stuff/Recipes.scala @@ -0,0 +1,19 @@ +package net.bdew.ae2stuff + +import cpw.mods.fml.common.registry.GameRegistry +import net.bdew.ae2stuff.items.{AdvWirelessKit, ItemWirelessKit} +import net.minecraft.item.ItemStack + +object Recipes { + def load(): Unit = { + // add recipe to clear NBT from adv wireless kit + GameRegistry.addShapelessRecipe( + new ItemStack(AdvWirelessKit), + AdvWirelessKit + ) + GameRegistry.addShapelessRecipe( + new ItemStack(ItemWirelessKit), + ItemWirelessKit + ) + } +} diff --git a/src/main/scala/net/bdew/ae2stuff/items/AdvWirelessKit.scala b/src/main/scala/net/bdew/ae2stuff/items/AdvWirelessKit.scala new file mode 100644 index 0000000..6037788 --- /dev/null +++ b/src/main/scala/net/bdew/ae2stuff/items/AdvWirelessKit.scala @@ -0,0 +1,256 @@ +/* + * Copyright (c) bdew, 2014 - 2015 + * https://github.com/bdew/ae2stuff + * + * This mod is distributed under the terms of the Minecraft Mod Public + * License 1.0, or MMPL. Please check the contents of the license located in + * http://bdew.net/minecraft-mod-public-license/ + */ + +package net.bdew.ae2stuff.items + +import appeng.api.config.SecurityPermissions +import appeng.api.exceptions.FailedConnection +import net.bdew.ae2stuff.grid.Security +import net.bdew.ae2stuff.machines.wireless.{BlockWireless, TileWireless} +import net.bdew.ae2stuff.misc.AdvItemLocationStore +import net.bdew.lib.Misc +import net.bdew.lib.block.BlockRef +import net.bdew.lib.items.SimpleItem +import net.minecraft.entity.EntityLivingBase +import net.minecraft.entity.player.EntityPlayer +import net.minecraft.item.ItemStack +import net.minecraft.world.World + +import java.util + +object AdvWirelessKit + extends SimpleItem("AdvWirelessKit") + with AdvItemLocationStore { + setMaxStackSize(1) + + val MODE_QUEUING = 0; + val MODE_BINDING = 1; + + def checkSecurity(t1: TileWireless, t2: TileWireless, p: EntityPlayer) = { + val pid = Security.getPlayerId(p) + Security.playerHasPermission( + t1.getNode.getGrid, + pid, + SecurityPermissions.BUILD + ) && + Security.playerHasPermission( + t2.getNode.getGrid, + pid, + SecurityPermissions.BUILD + ) + } + + override def onItemRightClick( + stack: ItemStack, + world: World, + player: EntityPlayer + ): ItemStack = { + import net.bdew.lib.helpers.ChatHelper._ + if (!world.isRemote && player.isSneaking) { + toggleMode(stack) + if (getMode(stack) == MODE_QUEUING) { + player.addChatMessage( + L("ae2stuff.wireless.advtool.queueing.activated").setColor( + Color.GREEN + ) + ) + } else { + player.addChatMessage( + L("ae2stuff.wireless.advtool.binding.activated").setColor(Color.GREEN) + ) + } + } + stack + } + + override def onItemUse( + stack: ItemStack, + player: EntityPlayer, + world: World, + x: Int, + y: Int, + z: Int, + side: Int, + xOff: Float, + yOff: Float, + zOff: Float + ): Boolean = { + import net.bdew.lib.helpers.ChatHelper._ + val pos = BlockRef(x, y, z) + if (!pos.blockIs(world, BlockWireless)) return false + if (!world.isRemote) { + if (player.isSneaking) { + toggleMode(stack) + if (getMode(stack) == MODE_QUEUING) { + player.addChatMessage( + L("ae2stuff.wireless.advtool.queueing.activated").setColor( + Color.GREEN + ) + ) + } else if (getMode(stack) == MODE_BINDING) { + player.addChatMessage( + L("ae2stuff.wireless.advtool.binding.activated").setColor( + Color.GREEN + ) + ) + } + return true; + } + pos.getTile[TileWireless](world) foreach { tile => + val pid = Security.getPlayerId(player) + // Check that the player can modify the network + if ( + !Security.playerHasPermission( + tile.getNode.getGrid, + pid, + SecurityPermissions.BUILD + ) + ) { + player.addChatMessage( + L("ae2stuff.wireless.tool.security.player").setColor(Color.RED) + ) + } else if (getMode(stack) == MODE_QUEUING) { + addLocation(stack, pos, world.provider.dimensionId) + player.addChatMessage( + L( + "ae2stuff.wireless.advtool.queued", + pos.x.toString, + pos.y.toString, + pos.z.toString + ).setColor(Color.GREEN) + ) + } else if (getMode(stack) == MODE_BINDING) { + if (hasLocation(stack)) { + // Have other location - start connecting + val otherPos = getNextLocation(stack) + + if (getDimension(stack) != world.provider.dimensionId) { + // Different dimensions - error out + player.addChatMessage( + L("ae2stuff.wireless.tool.dimension").setColor(Color.RED) + ) + } else if (pos == otherPos) { + // Same block - clear the location + popLocation(stack) + } else { + otherPos.getTile[TileWireless](world) match { + // Check that the other tile is still around + case Some(other: TileWireless) => + // And check that the player can modify it too + if ( + !Security.playerHasPermission( + other.getNode.getGrid, + pid, + SecurityPermissions.BUILD + ) + ) { + player.addChatMessage( + L("ae2stuff.wireless.tool.security.player").setColor( + Color.RED + ) + ) + } else { + // Player can modify both sides - unlink current connections if any + tile.doUnlink() + other.doUnlink() + + // Make player the owner of both blocks + tile.getNode.setPlayerID(pid) + other.getNode.setPlayerID(pid) + try { + if (tile.doLink(other)) { + player.addChatMessage( + L( + "ae2stuff.wireless.tool.connected", + pos.x.toString, + pos.y.toString, + pos.z.toString + ).setColor(Color.GREEN) + ) + } else { + player.addChatMessage( + L("ae2stuff.wireless.tool.failed").setColor(Color.RED) + ) + } + } catch { + case e: FailedConnection => + player.addChatComponentMessage( + (L( + "ae2stuff.wireless.tool.failed" + ) & ": " & e.getMessage).setColor(Color.RED) + ) + tile.doUnlink() + print("Failed to link wireless connector: " + e) + } + } + popLocation(stack) + case _ => + // The other block is gone - error out + player.addChatMessage( + L("ae2stuff.wireless.tool.noexist").setColor(Color.RED) + ) + popLocation(stack) + } + } + true + } else { + player.addChatMessage( + L("ae2stuff.wireless.advtool.noconnectors").setColor(Color.RED) + ) + } + } + } + } + true + } + + override def addInformation( + stack: ItemStack, + player: EntityPlayer, + tips: util.List[_], + detailed: Boolean + ): Unit = { + val list = tips.asInstanceOf[util.List[String]] + if (getLocations(stack).tagCount() > 0) { + val next = getNextLocation(stack) + list.add( + Misc.toLocalF( + "ae2stuff.wireless.advtool.connector.next", + next.x, + next.y, + next.z + ) + ) + } + if (getMode(stack) == MODE_QUEUING) { + list.add(Misc.toLocal("ae2stuff.wireless.advtool.queueing")) + if (getLocations(stack).tagCount() == 0) { + list.add(Misc.toLocal("ae2stuff.wireless.advtool.queueing.empty")) + } else { + list.add(Misc.toLocal("ae2stuff.wireless.advtool.queueing.notempty")) + for (i <- 0 until getLocations(stack).tagCount()) { + val loc = BlockRef.fromNBT(getLocations(stack).getCompoundTagAt(i)) + list.add(loc.x + "," + loc.y + "," + loc.z) + } + } + } else if (getMode(stack) == MODE_BINDING) { + list.add(Misc.toLocal("ae2stuff.wireless.advtool.binding")) + if (getLocations(stack).tagCount() == 0) { + list.add(Misc.toLocal("ae2stuff.wireless.advtool.binding.empty")) + } else { + list.add(Misc.toLocal("ae2stuff.wireless.advtool.binding.notempty")) + for (i <- 0 until getLocations(stack).tagCount()) { + val loc = BlockRef.fromNBT(getLocations(stack).getCompoundTagAt(i)) + list.add(loc.x + "," + loc.y + "," + loc.z) + } + } + } + list.add(Misc.toLocal("ae2stuff.wireless.advtool.extra")); + } +} diff --git a/src/main/scala/net/bdew/ae2stuff/items/ItemWirelessKit.scala b/src/main/scala/net/bdew/ae2stuff/items/ItemWirelessKit.scala index 4819ee5..bedfc32 100644 --- a/src/main/scala/net/bdew/ae2stuff/items/ItemWirelessKit.scala +++ b/src/main/scala/net/bdew/ae2stuff/items/ItemWirelessKit.scala @@ -131,6 +131,7 @@ object ItemWirelessKit ) & ": " & e.getMessage).setColor(Color.RED) ) tile.doUnlink() + print("Failed to link wireless connector: " + e) } } clearLocation(stack) diff --git a/src/main/scala/net/bdew/ae2stuff/misc/AdvItemLocationStore.scala b/src/main/scala/net/bdew/ae2stuff/misc/AdvItemLocationStore.scala new file mode 100644 index 0000000..1d5683a --- /dev/null +++ b/src/main/scala/net/bdew/ae2stuff/misc/AdvItemLocationStore.scala @@ -0,0 +1,129 @@ +/* + * Copyright (c) bdew, 2014 - 2015 + * https://github.com/bdew/ae2stuff + * + * This mod is distributed under the terms of the Minecraft Mod Public + * License 1.0, or MMPL. Please check the contents of the license located in + * http://bdew.net/minecraft-mod-public-license/ + */ + +package net.bdew.ae2stuff.misc + +import net.bdew.lib.block.BlockRef +import net.bdew.lib.nbt.NBT +import net.minecraft.item.{Item, ItemStack} +import net.minecraft.nbt.{NBTBase, NBTTagCompound} + +trait AdvItemLocationStore extends Item { + + import net.bdew.ae2stuff.items.AdvWirelessKit.MODE_QUEUING + + private val COMPOUND_TAG = NBTBase.NBTTypes.indexOf("COMPOUND") + + def addLocation(stack: ItemStack, loc: BlockRef, dimension: Int): Boolean = { + if (!stack.hasTagCompound) stack.setTagCompound(new NBTTagCompound) + val tag = stack.getTagCompound + if (tag.hasKey("dim") && tag.getInteger("dim") != dimension) { + false + } + val locList = tag.getTagList("loc", COMPOUND_TAG) + for (i <- 0 until locList.tagCount()) { + val tag = locList.getCompoundTagAt(i) + val pos = BlockRef.fromNBT(tag) + if (pos == loc) { + return false + } + } + locList.appendTag(NBT.from(loc.writeToNBT _)) + tag.setTag("loc", locList) + tag.setInteger("dim", dimension) + true + } + + def getLocations(stack: ItemStack) = { + if (!stack.hasTagCompound) stack.setTagCompound(new NBTTagCompound) + val tag = stack.getTagCompound + if (tag.hasKey("loc")) { + val locList = tag.getTagList("loc", COMPOUND_TAG) + locList + } else { + tag.setTag("loc", new NBTTagCompound) + tag.getTagList("loc", COMPOUND_TAG) + } + } + + // location is going to be a queue of coordinates + + def hasLocation(stack: ItemStack): Boolean = { + if ( + stack.getItem == this && stack.hasTagCompound && stack.getTagCompound + .hasKey("loc") + ) { + // check if list is not empty + val loc = stack.getTagCompound.getTagList("loc", COMPOUND_TAG) + if (loc.tagCount() > 0) { + return true + } + } + false + } + + def getNextLocation(stack: ItemStack): BlockRef = + BlockRef.fromNBT( + stack.getTagCompound.getTagList("loc", COMPOUND_TAG).getCompoundTagAt(0) + ) + + def getDimension(stack: ItemStack): Int = + stack.getTagCompound.getInteger("dim") + + def setLocation(stack: ItemStack, loc: BlockRef, dimension: Int): Unit = { + if (!stack.hasTagCompound) stack.setTagCompound(new NBTTagCompound) + val tag = stack.getTagCompound + val locList = tag.getTagList("loc", COMPOUND_TAG) + locList.appendTag(NBT.from(loc.writeToNBT _)) + tag.setTag("loc", locList) + tag.setInteger("dim", dimension) + } + + def popLocation(stack: ItemStack): BlockRef = { + if (stack.hasTagCompound) { + val locList = stack.getTagCompound.getTagList("loc", COMPOUND_TAG) + if (locList.tagCount() > 0) { + val tag = locList.getCompoundTagAt(0) + locList.removeTag(0) + val pos = BlockRef.fromNBT(tag) + stack.getTagCompound.setTag("loc", locList) + return pos; + } + if (locList.tagCount() == 0) { + stack.getTagCompound.removeTag("loc") + stack.getTagCompound.removeTag("dim") + } + } + null + } + + def getMode(stack: ItemStack): Integer = { + if (!stack.hasTagCompound) stack.setTagCompound(new NBTTagCompound) + val tag = stack.getTagCompound + if (tag.hasKey("mode")) { + tag.getInteger("mode") + } else { + tag.setInteger("mode", MODE_QUEUING) + MODE_QUEUING + } + } + + def toggleMode(stack: ItemStack): Integer = { + if (!stack.hasTagCompound) stack.setTagCompound(new NBTTagCompound) + val tag = stack.getTagCompound + if (tag.hasKey("mode")) { + val mode = tag.getInteger("mode") + tag.setInteger("mode", (mode + 1) % 2) + tag.getInteger("mode") + } else { + tag.setInteger("mode", MODE_QUEUING) + MODE_QUEUING + } + } +} diff --git a/src/main/scala/net/bdew/ae2stuff/misc/ItemLocationStore.scala b/src/main/scala/net/bdew/ae2stuff/misc/ItemLocationStore.scala index f790f0e..4af6276 100644 --- a/src/main/scala/net/bdew/ae2stuff/misc/ItemLocationStore.scala +++ b/src/main/scala/net/bdew/ae2stuff/misc/ItemLocationStore.scala @@ -15,24 +15,24 @@ import net.minecraft.item.{Item, ItemStack} import net.minecraft.nbt.NBTTagCompound trait ItemLocationStore extends Item { - def hasLocation(stack: ItemStack) = + def hasLocation(stack: ItemStack): Boolean = stack.getItem == this && stack.hasTagCompound && stack.getTagCompound .hasKey("loc") - def getLocation(stack: ItemStack) = + def getLocation(stack: ItemStack): BlockRef = BlockRef.fromNBT(stack.getTagCompound.getCompoundTag("loc")) - def getDimension(stack: ItemStack) = + def getDimension(stack: ItemStack): Int = stack.getTagCompound.getInteger("dim") - def setLocation(stack: ItemStack, loc: BlockRef, dimension: Int) = { + def setLocation(stack: ItemStack, loc: BlockRef, dimension: Int): Unit = { if (!stack.hasTagCompound) stack.setTagCompound(new NBTTagCompound) val tag = stack.getTagCompound tag.setTag("loc", NBT.from(loc.writeToNBT _)) tag.setInteger("dim", dimension) } - def clearLocation(stack: ItemStack) = { + def clearLocation(stack: ItemStack): Unit = { if (stack.hasTagCompound) { stack.getTagCompound.removeTag("loc") stack.getTagCompound.removeTag("dim")