From d5ade3f12b432383cfb6199d685e3e90af6eb761 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Fri, 19 Dec 2014 16:52:56 +0100 Subject: [PATCH] Added leash upgrade. --- assets/drone.tcn | Bin 0 -> 1743 bytes assets/items.psd | Bin 557564 -> 559846 bytes .../assets/opencomputers/lang/en_US.lang | 3 + .../opencomputers/recipes/default.recipes | 7 +- .../textures/items/UpgradeLeash.png | Bin 0 -> 349 bytes .../cil/oc/common/asm/ClassTransformer.scala | 88 +++++++++++++++ .../scala/li/cil/oc/common/entity/Drone.scala | 4 +- .../scala/li/cil/oc/common/init/Items.scala | 2 + .../li/cil/oc/common/item/Delegator.scala | 4 +- .../li/cil/oc/common/item/UpgradeLeash.scala | 3 + .../li/cil/oc/common/tileentity/Robot.scala | 4 +- .../common/tileentity/traits/Inventory.scala | 6 +- .../integration/appeng/DriverController.scala | 2 +- .../DriverBlockEnvironments.scala | 6 +- .../opencomputers/DriverUpgradeLeash.scala | 27 +++++ .../opencomputers/ModOpenComputers.scala | 75 ++++++++++++- .../li/cil/oc/server/component/Drone.scala | 5 +- .../UpgradeInventoryController.scala | 3 +- .../oc/server/component/UpgradeLeash.scala | 102 ++++++++++++++++++ .../component/UpgradeTankController.scala | 3 +- .../server/component/traits/WorldAware.scala | 7 +- .../scala/li/cil/oc/util/BlockPosition.scala | 18 ++-- 22 files changed, 337 insertions(+), 32 deletions(-) create mode 100644 assets/drone.tcn create mode 100644 src/main/resources/assets/opencomputers/textures/items/UpgradeLeash.png create mode 100644 src/main/scala/li/cil/oc/common/item/UpgradeLeash.scala create mode 100644 src/main/scala/li/cil/oc/integration/opencomputers/DriverUpgradeLeash.scala create mode 100644 src/main/scala/li/cil/oc/server/component/UpgradeLeash.scala diff --git a/assets/drone.tcn b/assets/drone.tcn new file mode 100644 index 0000000000000000000000000000000000000000..0aeb4cfdf51cf057995d63833e1158bf61a1cf38 GIT binary patch literal 1743 zcmbW2dpOg39LIm{Ceh?tPRf#NvO{gv6k;hXmqaL+iJ`)zDRPOiq=rl`Axf5XF_lrB zTp~_PDU8Gzn)_vCVKh7IoagB|r{_6;ob&lU-|zeRKF{~_`tSAmI^e(%B>(_c0;glr zEirw5TV_E30M!QoX+RSQBKi^nk>Npss{n-L5df?J)&c#hWUJiu?^gVrQ%60BxrR#7 z1?A${@J8PDTWRh^rOx+FNvzJ3Idj9cwu4D{-@KT~u2$^?g~x$ouPlzarD;r8{l2yb zGe5qUO5Bw1kB@?SI%M9+?o0FEKhv)YGxfNP8G3)tHKzV7;ac1o4K6kQo1I4B&WFzH zE@!v9zb0+zEo_!=BsXLv-*`go=cH)BG#)z1%_$(JjNeR567(h2UQ zT~UySo>uq(f?RlD(zf%?n)po{&qNf+zuIi31_@A5)6u;Ytgu@&14`ACD ztW*?sdpF(gw$ePzX|b-h%b?;%pS7<^h7Bk|(+&42UI#_kDd^Z))P-3TX_-$^)Ho93LWYyrMDVZ6|2bL%-Ig0rTo0 zXAE8_L%XMbs=ks^b5oACA59_z-zwD`q3(=h7E?s18!8BmPsd&}ucl5lzb7ZVnddG! z^%(T7)$UwUl~pP`TOPYpptBFlVqW}!WE}h4qx{?b?p>Kzrfj=loJksy;}Bx5X#3Js zceFVSF<&Mt&;(bB){P3KZgUf)U#jF#qRSkNKoN-qZ^Vr1WVckk|C0~~W(MtpIbxlF zMAe(T@v}Qn=$%9Bea~*gGOrozo-A|CL!#?P@vC42#5Q^i~hMFsu)zmbUd)^h0zw?N$h6@siSC)+z{fnbl z!vA=|UkITv3@~F~|~VYnR;9cVV+XJ{Ypuw$EP2=#huDn2{C z2T$yS!wb12N)*M}HFB7~9%;iRxo0x~4n|L-Qv z@BPc9pL0T%e`bV78$6E3bH55gq(N=)y$@<%%4!xH&j*1WXy1F*?BF(;3R@7B(ef^1{q0N%g)y@8DC=!ds9y}dtEZpH&=`S+N_Dc8wcy3I3 zT$~ZRy}_txuruT8L`351aHoS|Z~I4Id}|DxW{8)K^L1tiBlZXiRYPynW z^3Wc$#-!PEh6lYL4=#QRo{YH3ud(%LHHnOLdv-!iBQjdn-b-O1_-rEfT;90U zyckZ0H;qj&(7y<)?L!T|F&Z?!5V8BxQy7suaG|B6iC3}8OH}x<%7GHh)3;_MXOg93 zl&;V7q=78q;P_nX;T+^scUPnLRptx5O|a$UgLYoVR7_qGI*_IS8A;e4#y7gl+O{

^n8HtIm&ffmE@VT7%MZOZ3H_r-YEiWOg#h1LBD(9Xb@R1>Sma|i&<8fowP0BfLj4F0RDaO|2gb`9RKMX g_!<4P6+fteDH!9{TJBp%46U~B4jFb|` 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 ZL)%rsK>PE?5 instructions.toArray.sliding(3, 1).exists { + case Array(varNode: VarInsnNode, fieldNode: FieldInsnNode, jumpNode: JumpInsnNode) + if varNode.getOpcode == Opcodes.ALOAD && varNode.`var` == 0 && + fieldNode.getOpcode == Opcodes.GETFIELD && fieldNode.name == "field_110170_bx" && + jumpNode.getOpcode == Opcodes.IFNULL => + val toInject = new InsnList() + toInject.add(new VarInsnNode(Opcodes.ALOAD, 0)) + toInject.add(new FieldInsnNode(Opcodes.GETFIELD, "net/minecraft/entity/EntityLiving", "leashedToEntity", "Lnet/minecraft/entity/Entity;")) + toInject.add(new JumpInsnNode(Opcodes.IFNONNULL, jumpNode.label)) + instructions.insert(jumpNode, toInject) + true + case _ => + false + }) match { + case Some(data) => transformedClass = data + case _ => + } + } + + // Little change to the renderer used to render leashes to center it on drones. + // This injects the code + // if (entity instanceof Drone) { + // d5 = 0.0; + // d6 = 0.0; + // d7 = -0.75; + // } + // before the `instanceof EntityHanging` check in func_110827_b. + if (transformedClass != null && name == "net.minecraft.client.renderer.entity.RenderLiving") { + insertInto(transformedClass, "func_110827_b", instructions => instructions.toArray.sliding(3, 1).exists { + case Array(varNode: VarInsnNode, typeNode: TypeInsnNode, jumpNode: JumpInsnNode) + if varNode.getOpcode == Opcodes.ALOAD && varNode.`var` == 10 && + typeNode.getOpcode == Opcodes.INSTANCEOF && typeNode.desc == "net/minecraft/entity/EntityHanging" && + jumpNode.getOpcode == Opcodes.IFEQ => + val toInject = new InsnList() + toInject.add(new VarInsnNode(Opcodes.ALOAD, 10)) + toInject.add(new TypeInsnNode(Opcodes.INSTANCEOF, "li/cil/oc/common/entity/Drone")) + val skip = new LabelNode() + toInject.add(new JumpInsnNode(Opcodes.IFEQ, skip)) + toInject.add(new LdcInsnNode(double2Double(0.0))) + toInject.add(new VarInsnNode(Opcodes.DSTORE, 16)) + toInject.add(new LdcInsnNode(double2Double(0.0))) + toInject.add(new VarInsnNode(Opcodes.DSTORE, 18)) + toInject.add(new LdcInsnNode(double2Double(-0.75))) + toInject.add(new VarInsnNode(Opcodes.DSTORE, 20)) + toInject.add(skip) + instructions.insertBefore(varNode, toInject) + true + case _ => + false + }) match { + case Some(data) => transformedClass = data + case _ => + } + } + transformedClass } catch { @@ -132,6 +202,24 @@ class ClassTransformer extends IClassTransformer { } } + private def insertInto(classData: Array[Byte], method: String, inserter: (InsnList) => Boolean): Option[Array[Byte]] = { + val classNode = newClassNode(classData) + classNode.methods.find(_.name == method) match { + case Some(methodNode) => + if (inserter(methodNode.instructions)) { + log.warn(s"Successfully patched ${classNode.name}.$method.") + Option(writeClass(classNode, ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES)) + } + else { + log.warn(s"Failed patching ${classNode.name}.$method}, injection point not found.") + None + } + case _ => + log.warn(s"Failed patching ${classNode.name}.$method, method not found.") + None + } + } + private def classExists(name: String) = { loader.getClassBytes(name) != null || loader.getClassBytes(FMLDeobfuscatingRemapper.INSTANCE.unmap(name)) != null || diff --git a/src/main/scala/li/cil/oc/common/entity/Drone.scala b/src/main/scala/li/cil/oc/common/entity/Drone.scala index c606521b1..e150b2ff1 100644 --- a/src/main/scala/li/cil/oc/common/entity/Drone.scala +++ b/src/main/scala/li/cil/oc/common/entity/Drone.scala @@ -254,7 +254,7 @@ class Drone(val world: World) extends Entity(world) with MachineHost with intern val entity = new EntityItem(world, posX, posY, posZ, stack) entity.delayBeforeCanPickup = 15 world.spawnEntityInWorld(entity) - InventoryUtils.dropAllSlots(BlockPosition(this), inventory) + InventoryUtils.dropAllSlots(BlockPosition(this: Entity), inventory) } } @@ -357,7 +357,7 @@ class Drone(val world: World) extends Entity(world) with MachineHost with intern motionZ *= drag } else { - val groundDrag = worldObj.getBlock(BlockPosition(this).offset(ForgeDirection.DOWN)).slipperiness * drag + val groundDrag = worldObj.getBlock(BlockPosition(this: Entity).offset(ForgeDirection.DOWN)).slipperiness * drag motionX *= groundDrag motionY *= drag motionZ *= groundDrag diff --git a/src/main/scala/li/cil/oc/common/init/Items.scala b/src/main/scala/li/cil/oc/common/init/Items.scala index 93b39a122..f34e9f796 100644 --- a/src/main/scala/li/cil/oc/common/init/Items.scala +++ b/src/main/scala/li/cil/oc/common/init/Items.scala @@ -11,6 +11,7 @@ import li.cil.oc.common.Tier import li.cil.oc.common.block.SimpleBlock import li.cil.oc.common.item import li.cil.oc.common.item.SimpleItem +import li.cil.oc.common.item.UpgradeLeash import li.cil.oc.common.recipe.Recipes import li.cil.oc.integration.Mods import li.cil.oc.util.Color @@ -312,5 +313,6 @@ object Items extends ItemAPI { // 1.4.3 Recipes.addMultiItem(new item.DroneCase(multi), "droneCase", "oc:droneCase") registerItem(new item.Drone(multi), "drone") + Recipes.addMultiItem(new UpgradeLeash(multi), "leashUpgrade", "oc:leashUpgrade") } } diff --git a/src/main/scala/li/cil/oc/common/item/Delegator.scala b/src/main/scala/li/cil/oc/common/item/Delegator.scala index bd30f6e1b..e67c7ef08 100644 --- a/src/main/scala/li/cil/oc/common/item/Delegator.scala +++ b/src/main/scala/li/cil/oc/common/item/Delegator.scala @@ -106,13 +106,13 @@ class Delegator extends Item { override def onItemUseFirst(stack: ItemStack, player: EntityPlayer, world: World, x: Int, y: Int, z: Int, side: Int, hitX: Float, hitY: Float, hitZ: Float): Boolean = subItem(stack) match { - case Some(subItem) => subItem.onItemUseFirst(stack, player, BlockPosition(x, y, z, Option(world)), side, hitX, hitY, hitZ) + case Some(subItem) => subItem.onItemUseFirst(stack, player, BlockPosition(x, y, z, world), side, hitX, hitY, hitZ) case _ => super.onItemUseFirst(stack, player, world, x, y, z, side, hitX, hitY, hitZ) } override def onItemUse(stack: ItemStack, player: EntityPlayer, world: World, x: Int, y: Int, z: Int, side: Int, hitX: Float, hitY: Float, hitZ: Float): Boolean = subItem(stack) match { - case Some(subItem) => subItem.onItemUse(stack, player, BlockPosition(x, y, z, Option(world)), side, hitX, hitY, hitZ) + case Some(subItem) => subItem.onItemUse(stack, player, BlockPosition(x, y, z, world), side, hitX, hitY, hitZ) case _ => super.onItemUse(stack, player, world, x, y, z, side, hitX, hitY, hitZ) } diff --git a/src/main/scala/li/cil/oc/common/item/UpgradeLeash.scala b/src/main/scala/li/cil/oc/common/item/UpgradeLeash.scala new file mode 100644 index 000000000..c7c85f762 --- /dev/null +++ b/src/main/scala/li/cil/oc/common/item/UpgradeLeash.scala @@ -0,0 +1,3 @@ +package li.cil.oc.common.item + +class UpgradeLeash(val parent: Delegator) extends Delegate with ItemTier diff --git a/src/main/scala/li/cil/oc/common/tileentity/Robot.scala b/src/main/scala/li/cil/oc/common/tileentity/Robot.scala index 171ed4f75..7384576b2 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/Robot.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/Robot.scala @@ -728,10 +728,10 @@ class Robot extends traits.Computer with traits.PowerInformation with IFluidHand // ----------------------------------------------------------------------- // override def dropSlot(slot: Int, count: Int, direction: Option[ForgeDirection]) = - InventoryUtils.dropSlot(BlockPosition(x, y, z, Option(world)), dynamicInventory, slot, count, direction) + InventoryUtils.dropSlot(BlockPosition(x, y, z, world), dynamicInventory, slot, count, direction) override def dropAllSlots() = - InventoryUtils.dropAllSlots(BlockPosition(x, y, z, Option(world)), dynamicInventory) + InventoryUtils.dropAllSlots(BlockPosition(x, y, z, world), dynamicInventory) // ----------------------------------------------------------------------- // diff --git a/src/main/scala/li/cil/oc/common/tileentity/traits/Inventory.scala b/src/main/scala/li/cil/oc/common/tileentity/traits/Inventory.scala index e23daff08..81495f114 100644 --- a/src/main/scala/li/cil/oc/common/tileentity/traits/Inventory.scala +++ b/src/main/scala/li/cil/oc/common/tileentity/traits/Inventory.scala @@ -31,11 +31,11 @@ trait Inventory extends TileEntity with inventory.Inventory { // ----------------------------------------------------------------------- // def dropSlot(slot: Int, count: Int = getInventoryStackLimit, direction: Option[ForgeDirection] = None) = - InventoryUtils.dropSlot(BlockPosition(x, y, z, Option(world)), this, slot, count, direction) + InventoryUtils.dropSlot(BlockPosition(x, y, z, world), this, slot, count, direction) def dropAllSlots() = - InventoryUtils.dropAllSlots(BlockPosition(x, y, z, Option(world)), this) + InventoryUtils.dropAllSlots(BlockPosition(x, y, z, world), this) def spawnStackInWorld(stack: ItemStack, direction: Option[ForgeDirection] = None) = - InventoryUtils.spawnStackInWorld(BlockPosition(x, y, z, Option(world)), stack, direction) + InventoryUtils.spawnStackInWorld(BlockPosition(x, y, z, world), stack, direction) } diff --git a/src/main/scala/li/cil/oc/integration/appeng/DriverController.scala b/src/main/scala/li/cil/oc/integration/appeng/DriverController.scala index 361b6ed06..061136c76 100644 --- a/src/main/scala/li/cil/oc/integration/appeng/DriverController.scala +++ b/src/main/scala/li/cil/oc/integration/appeng/DriverController.scala @@ -181,7 +181,7 @@ object DriverController extends DriverTileEntity with EnvironmentAware { } }) } - links ++= nbt.getTagList("links", NBT.TAG_LIST).map( + links ++= nbt.getTagList("links", NBT.TAG_COMPOUND).map( (nbt: NBTTagCompound) => Api.instance.storage.loadCraftingLink(nbt, this)) } diff --git a/src/main/scala/li/cil/oc/integration/opencomputers/DriverBlockEnvironments.scala b/src/main/scala/li/cil/oc/integration/opencomputers/DriverBlockEnvironments.scala index 119a496f6..44add398a 100644 --- a/src/main/scala/li/cil/oc/integration/opencomputers/DriverBlockEnvironments.scala +++ b/src/main/scala/li/cil/oc/integration/opencomputers/DriverBlockEnvironments.scala @@ -4,6 +4,7 @@ import li.cil.oc.api import li.cil.oc.api.driver import li.cil.oc.api.driver.EnvironmentAware import li.cil.oc.api.network.Environment +import li.cil.oc.api.network.ManagedEnvironment import li.cil.oc.common import li.cil.oc.common.tileentity import li.cil.oc.integration.util.BundledRedstone @@ -29,11 +30,14 @@ object DriverBlockEnvironments extends driver.Block with EnvironmentAware { case block: ItemBlock if block.field_150939_a != null => if (isOneOf(block.field_150939_a, "accessPoint")) classOf[tileentity.AccessPoint] else if (isOneOf(block.field_150939_a, "assembler")) classOf[tileentity.Assembler] - else if (isOneOf(block.field_150939_a, "case1", "case2", "case3", "caseCreative")) classOf[Machine] + else if (isOneOf(block.field_150939_a, "case1", "case2", "case3", "caseCreative", "microcontroller")) classOf[Machine] else if (isOneOf(block.field_150939_a, "hologram1", "hologram2")) classOf[tileentity.Hologram] else if (isOneOf(block.field_150939_a, "motionSensor")) classOf[tileentity.MotionSensor] else if (isOneOf(block.field_150939_a, "redstone")) if (BundledRedstone.isAvailable) classOf[component.Redstone.Bundled] else classOf[component.Redstone.Simple] + else if (isOneOf(block.field_150939_a, "screen1")) classOf[common.component.TextBuffer].asInstanceOf[Class[_ <: Environment]] else if (isOneOf(block.field_150939_a, "screen2", "screen3")) classOf[common.component.Screen] + else if (isOneOf(block.field_150939_a, "robot")) classOf[component.robot.Robot].asInstanceOf[Class[_ <: Environment]] + else if (isOneOf(block.field_150939_a, "drone")) classOf[component.Drone].asInstanceOf[Class[_ <: Environment]] else null case _ => null } diff --git a/src/main/scala/li/cil/oc/integration/opencomputers/DriverUpgradeLeash.scala b/src/main/scala/li/cil/oc/integration/opencomputers/DriverUpgradeLeash.scala new file mode 100644 index 000000000..15154b02a --- /dev/null +++ b/src/main/scala/li/cil/oc/integration/opencomputers/DriverUpgradeLeash.scala @@ -0,0 +1,27 @@ +package li.cil.oc.integration.opencomputers + +import li.cil.oc.api +import li.cil.oc.api.driver.EnvironmentAware +import li.cil.oc.api.driver.EnvironmentHost +import li.cil.oc.api.driver.item.HostAware +import li.cil.oc.common.Slot +import li.cil.oc.common.Tier +import li.cil.oc.server.component +import net.minecraft.entity.Entity +import net.minecraft.item.ItemStack + +object DriverUpgradeLeash extends Item with HostAware with EnvironmentAware { + override def worksWith(stack: ItemStack) = + isOneOf(stack, api.Items.get("leashUpgrade")) + + override def createEnvironment(stack: ItemStack, host: EnvironmentHost) = host match { + case entity: Entity => new component.UpgradeLeash(entity) + case _ => null + } + + override def slot(stack: ItemStack) = Slot.Upgrade + + override def tier(stack: ItemStack) = Tier.One + + override def providedEnvironment(stack: ItemStack) = classOf[component.UpgradeLeash] +} diff --git a/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala b/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala index f0b0786d1..51869927d 100644 --- a/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala +++ b/src/main/scala/li/cil/oc/integration/opencomputers/ModOpenComputers.scala @@ -95,6 +95,7 @@ object ModOpenComputers extends ModProxy { api.Driver.add(DriverUpgradeGenerator) api.Driver.add(DriverUpgradeInventory) api.Driver.add(DriverUpgradeInventoryController) + api.Driver.add(DriverUpgradeLeash) api.Driver.add(DriverUpgradeNavigation) api.Driver.add(DriverUpgradePiston) api.Driver.add(DriverUpgradeSign) @@ -103,10 +104,76 @@ object ModOpenComputers extends ModProxy { api.Driver.add(DriverUpgradeTankController) api.Driver.add(DriverUpgradeTractorBeam) - blacklistHost(classOf[internal.Adapter], "geolyzer", "keyboard", "screen1", "angelUpgrade", "batteryUpgrade1", "batteryUpgrade2", "batteryUpgrade3", "chunkloaderUpgrade", "craftingUpgrade", "experienceUpgrade", "generatorUpgrade", "inventoryUpgrade", "navigationUpgrade", "pistonUpgrade", "solarGeneratorUpgrade", "tankUpgrade", "tractorBeamUpgrade") - blacklistHost(classOf[internal.Microcontroller], "graphicsCard1", "graphicsCard2", "graphicsCard3", "keyboard", "screen1", "angelUpgrade", "chunkloaderUpgrade", "craftingUpgrade", "databaseUpgrade1", "databaseUpgrade2", "databaseUpgrade3", "experienceUpgrade", "generatorUpgrade", "inventoryUpgrade", "inventoryControllerUpgrade", "navigationUpgrade", "tankUpgrade", "tankControllerUpgrade", "tractorBeamUpgrade") - blacklistHost(classOf[internal.Drone], "graphicsCard1", "graphicsCard2", "graphicsCard3", "keyboard", "lanCard", "redstoneCard1", "screen1", "angelUpgrade", "craftingUpgrade", "experienceUpgrade") - blacklistHost(classOf[internal.Tablet], "lanCard", "redstoneCard1", "screen1", "angelUpgrade", "chunkloaderUpgrade", "craftingUpgrade", "databaseUpgrade1", "databaseUpgrade2", "databaseUpgrade3", "experienceUpgrade", "generatorUpgrade", "inventoryUpgrade", "inventoryControllerUpgrade", "tankUpgrade", "tankControllerUpgrade") + blacklistHost(classOf[internal.Adapter], + "geolyzer", + "keyboard", + "screen1", + "angelUpgrade", + "batteryUpgrade1", + "batteryUpgrade2", + "batteryUpgrade3", + "chunkloaderUpgrade", + "craftingUpgrade", + "experienceUpgrade", + "generatorUpgrade", + "inventoryUpgrade", + "navigationUpgrade", + "pistonUpgrade", + "solarGeneratorUpgrade", + "tankUpgrade", + "tractorBeamUpgrade", + "leashUpgrade") + blacklistHost(classOf[internal.Drone], + "graphicsCard1", + "graphicsCard2", + "graphicsCard3", + "keyboard", + "lanCard", + "redstoneCard1", + "screen1", + "angelUpgrade", + "craftingUpgrade", + "experienceUpgrade") + blacklistHost(classOf[internal.Microcontroller], + "graphicsCard1", + "graphicsCard2", + "graphicsCard3", + "keyboard", + "screen1", + "angelUpgrade", + "chunkloaderUpgrade", + "craftingUpgrade", + "databaseUpgrade1", + "databaseUpgrade2", + "databaseUpgrade3", + "experienceUpgrade", + "generatorUpgrade", + "inventoryUpgrade", + "inventoryControllerUpgrade", + "navigationUpgrade", + "tankUpgrade", + "tankControllerUpgrade", + "tractorBeamUpgrade", + "leashUpgrade") + blacklistHost(classOf[internal.Robot], + "leashUpgrade") + blacklistHost(classOf[internal.Tablet], + "lanCard", + "redstoneCard1", + "screen1", + "angelUpgrade", + "chunkloaderUpgrade", + "craftingUpgrade", + "databaseUpgrade1", + "databaseUpgrade2", + "databaseUpgrade3", + "experienceUpgrade", + "generatorUpgrade", + "inventoryUpgrade", + "inventoryControllerUpgrade", + "tankUpgrade", + "tankControllerUpgrade", + "leashUpgrade") if (!WirelessRedstone.isAvailable) { blacklistHost(classOf[internal.Drone], "redstoneCard2") diff --git a/src/main/scala/li/cil/oc/server/component/Drone.scala b/src/main/scala/li/cil/oc/server/component/Drone.scala index c77a8153e..b7d6b96be 100644 --- a/src/main/scala/li/cil/oc/server/component/Drone.scala +++ b/src/main/scala/li/cil/oc/server/component/Drone.scala @@ -11,6 +11,7 @@ import li.cil.oc.common.entity import li.cil.oc.util.BlockPosition import li.cil.oc.util.ExtendedArguments._ import li.cil.oc.util.InventoryUtils +import net.minecraft.entity.Entity import net.minecraft.entity.item.EntityItem import net.minecraftforge.common.util.ForgeDirection @@ -20,7 +21,7 @@ class Drone(val host: entity.Drone) extends prefab.ManagedEnvironment with trait withConnector(Settings.get.bufferDrone). create() - override protected def position = BlockPosition(host) + override protected def position = BlockPosition(host: Entity) override def inventory = host.inventory @@ -37,7 +38,7 @@ class Drone(val host: entity.Drone) extends prefab.ManagedEnvironment with trait override protected def checkSideForAction(args: Arguments, n: Int) = args.checkSide(n, ForgeDirection.VALID_DIRECTIONS: _*) - override protected def suckableItems(side: ForgeDirection) = entitiesInBlock(BlockPosition(host)) ++ super.suckableItems(side) + override protected def suckableItems(side: ForgeDirection) = entitiesInBlock(position) ++ super.suckableItems(side) override protected def onSuckCollect(entity: EntityItem) = { if (InventoryUtils.insertIntoInventory(entity.getEntityItem, inventory, slots = Option(insertionSlots))) { diff --git a/src/main/scala/li/cil/oc/server/component/UpgradeInventoryController.scala b/src/main/scala/li/cil/oc/server/component/UpgradeInventoryController.scala index 8a112f95a..191534e52 100644 --- a/src/main/scala/li/cil/oc/server/component/UpgradeInventoryController.scala +++ b/src/main/scala/li/cil/oc/server/component/UpgradeInventoryController.scala @@ -11,6 +11,7 @@ import li.cil.oc.common.entity import li.cil.oc.common.tileentity import li.cil.oc.util.BlockPosition import li.cil.oc.util.ExtendedArguments._ +import net.minecraft.entity.Entity import net.minecraftforge.common.util.ForgeDirection object UpgradeInventoryController { @@ -34,7 +35,7 @@ object UpgradeInventoryController { // ----------------------------------------------------------------------- // - override protected def position = BlockPosition(host) + override protected def position = BlockPosition(host: Entity) override def inventory = host.inventory diff --git a/src/main/scala/li/cil/oc/server/component/UpgradeLeash.scala b/src/main/scala/li/cil/oc/server/component/UpgradeLeash.scala new file mode 100644 index 000000000..c93e354cf --- /dev/null +++ b/src/main/scala/li/cil/oc/server/component/UpgradeLeash.scala @@ -0,0 +1,102 @@ +package li.cil.oc.server.component + +import java.util.UUID + +import li.cil.oc.OpenComputers +import li.cil.oc.api.Network +import li.cil.oc.api.machine.Arguments +import li.cil.oc.api.machine.Callback +import li.cil.oc.api.machine.Context +import li.cil.oc.api.network.Node +import li.cil.oc.api.network.Visibility +import li.cil.oc.api.prefab +import li.cil.oc.common.EventHandler +import li.cil.oc.util.BlockPosition +import li.cil.oc.util.ExtendedArguments._ +import li.cil.oc.util.ExtendedNBT._ +import net.minecraft.entity.Entity +import net.minecraft.entity.EntityLiving +import net.minecraft.nbt.NBTTagCompound +import net.minecraft.nbt.NBTTagString +import net.minecraft.network.play.server.S1BPacketEntityAttach +import net.minecraft.world.WorldServer +import net.minecraftforge.common.util.Constants.NBT +import net.minecraftforge.common.util.ForgeDirection + +import scala.collection.mutable + +class UpgradeLeash(val host: Entity) extends prefab.ManagedEnvironment with traits.WorldAware { + override val node = Network.newNode(this, Visibility.Network). + withComponent("leash"). + create() + + val leashedEntities = mutable.Set.empty[UUID] + + override protected def position = BlockPosition(host) + + @Callback(doc = """function(side:number):boolean -- Tries to put an entity on the specified side of the device onto a leash.""") + def leash(context: Context, args: Arguments): Array[AnyRef] = { + if (leashedEntities.size >= 8) return result(Unit, "too many leashed entities") + val side = args.checkSide(0, ForgeDirection.VALID_DIRECTIONS: _*) + val nearBounds = position.bounds + val farBounds = nearBounds.offset(side.offsetX * 2.0, side.offsetY * 2.0, side.offsetZ * 2.0) + val bounds = nearBounds.func_111270_a(farBounds) + entitiesInBounds[EntityLiving](bounds).find(_.allowLeashing()) match { + case Some(entity) => + entity.setLeashedToEntity(host, true) + leashedEntities += entity.getUniqueID + context.pause(0.1) + result(true) + case _ => result(Unit, "no unleashed entity") + } + } + + @Callback(doc = """function() -- Unleashes all currently leashed entities.""") + def unleash(context: Context, args: Arguments): Array[AnyRef] = { + unleashAll() + null + } + + override def onDisconnect(node: Node) { + super.onDisconnect(node) + if (node == this.node) { + unleashAll() + } + } + + private def unleashAll() { + entitiesInBounds[EntityLiving](position.bounds.expand(5, 5, 5)).foreach(entity => { + if (leashedEntities.contains(entity.getUniqueID) && entity.getLeashedToEntity == host) { + entity.clearLeashed(true, false) + } + }) + leashedEntities.clear() + } + + override def load(nbt: NBTTagCompound) { + super.load(nbt) + leashedEntities ++= nbt.getTagList("leashedEntities", NBT.TAG_STRING). + map((s: NBTTagString) => UUID.fromString(s.func_150285_a_())) + // Re-acquire leashed entities. Need to do this manually because leashed + // entities only remember their leashee if it's an EntityLivingBase... + EventHandler.schedule(() => { + val foundEntities = mutable.Set.empty[UUID] + entitiesInBounds[EntityLiving](position.bounds.expand(5, 5, 5)).foreach(entity => { + if (leashedEntities.contains(entity.getUniqueID)) { + entity.setLeashedToEntity(host, true) + foundEntities += entity.getUniqueID + } + }) + val missing = leashedEntities.diff(foundEntities) + if (missing.size > 0) { + OpenComputers.log.info(s"Could not find ${missing.size} leashed entities after loading!") + leashedEntities --= missing + } + }) + } + + override def save(nbt: NBTTagCompound) { + super.save(nbt) + nbt.setNewTagList("leashedEntities", leashedEntities.map(_.toString)) + } +} diff --git a/src/main/scala/li/cil/oc/server/component/UpgradeTankController.scala b/src/main/scala/li/cil/oc/server/component/UpgradeTankController.scala index 5b0e97a07..7aa1a0ad2 100644 --- a/src/main/scala/li/cil/oc/server/component/UpgradeTankController.scala +++ b/src/main/scala/li/cil/oc/server/component/UpgradeTankController.scala @@ -9,6 +9,7 @@ import li.cil.oc.common.entity import li.cil.oc.common.tileentity import li.cil.oc.util.BlockPosition import li.cil.oc.util.ExtendedArguments._ +import net.minecraft.entity.Entity import net.minecraftforge.common.util.ForgeDirection object UpgradeTankController { @@ -30,7 +31,7 @@ object UpgradeTankController { withComponent("tank_controller", Visibility.Neighbors). create() - override protected def position = BlockPosition(host) + override protected def position = BlockPosition(host: Entity) override def inventory = host.inventory diff --git a/src/main/scala/li/cil/oc/server/component/traits/WorldAware.scala b/src/main/scala/li/cil/oc/server/component/traits/WorldAware.scala index 326ebf8e2..4ca0af843 100644 --- a/src/main/scala/li/cil/oc/server/component/traits/WorldAware.scala +++ b/src/main/scala/li/cil/oc/server/component/traits/WorldAware.scala @@ -7,6 +7,7 @@ import li.cil.oc.util.ExtendedWorld._ import net.minecraft.entity.Entity import net.minecraft.entity.EntityLivingBase import net.minecraft.entity.item.EntityMinecart +import net.minecraft.util.AxisAlignedBB import net.minecraft.world.WorldServer import net.minecraftforge.common.MinecraftForge import net.minecraftforge.common.util.FakePlayer @@ -32,8 +33,12 @@ trait WorldAware { player } + protected def entitiesInBounds[Type <: Entity : ClassTag](bounds: AxisAlignedBB) = { + world.getEntitiesWithinAABB(classTag[Type].runtimeClass, bounds).map(_.asInstanceOf[Type]) + } + protected def entitiesInBlock[Type <: Entity : ClassTag](blockPos: BlockPosition) = { - world.getEntitiesWithinAABB(classTag[Type].runtimeClass, blockPos.bounds).map(_.asInstanceOf[Type]) + entitiesInBounds[Type](blockPos.bounds) } protected def entitiesOnSide[Type <: Entity : ClassTag](side: ForgeDirection) = { diff --git a/src/main/scala/li/cil/oc/util/BlockPosition.scala b/src/main/scala/li/cil/oc/util/BlockPosition.scala index 363fb3edb..212264096 100644 --- a/src/main/scala/li/cil/oc/util/BlockPosition.scala +++ b/src/main/scala/li/cil/oc/util/BlockPosition.scala @@ -4,14 +4,14 @@ import appeng.api.util.DimensionalCoord import cpw.mods.fml.common.Optional import li.cil.oc.api.driver.EnvironmentHost import li.cil.oc.integration.Mods -import net.minecraft.tileentity.TileEntity +import net.minecraft.entity.Entity import net.minecraft.util.AxisAlignedBB import net.minecraft.util.ChunkCoordinates import net.minecraft.util.Vec3 import net.minecraft.world.World import net.minecraftforge.common.util.ForgeDirection -case class BlockPosition(x: Int, y: Int, z: Int, world: Option[World]) { +class BlockPosition(val x: Int, val y: Int, val z: Int, val world: Option[World]) { def this(x: Double, y: Double, z: Double, world: Option[World] = None) = this( math.floor(x).toInt, math.floor(y).toInt, @@ -19,13 +19,7 @@ case class BlockPosition(x: Int, y: Int, z: Int, world: Option[World]) { world ) - def this(host: EnvironmentHost) = this( - host.xPosition, - host.yPosition, - host.zPosition, - Option(host.world)) - - def offset(direction: ForgeDirection) = BlockPosition( + def offset(direction: ForgeDirection) = new BlockPosition( x + direction.offsetX, y + direction.offsetY, z + direction.offsetZ, @@ -55,8 +49,10 @@ object BlockPosition { def apply(x: Double, y: Double, z: Double) = new BlockPosition(x, y, z, None) - def apply(host: EnvironmentHost) = new BlockPosition(host) + def apply(host: EnvironmentHost): BlockPosition = BlockPosition(host.xPosition, host.yPosition, host.zPosition, host.world) + + def apply(entity: Entity): BlockPosition = BlockPosition(entity.posX, entity.posY, entity.posZ, entity.worldObj) @Optional.Method(modid = Mods.IDs.AppliedEnergistics2) - def apply(coord: DimensionalCoord) = new BlockPosition(coord.x, coord.y, coord.z, Option(coord.getWorld)) + def apply(coord: DimensionalCoord): BlockPosition = BlockPosition(coord.x, coord.y, coord.z, coord.getWorld) }