Added leash upgrade.

This commit is contained in:
Florian Nücke 2014-12-19 16:52:56 +01:00
parent 643c4b7c1b
commit d5ade3f12b
22 changed files with 337 additions and 32 deletions

BIN
assets/drone.tcn Normal file

Binary file not shown.

Binary file not shown.

View File

@ -111,6 +111,7 @@ item.oc.UpgradeExperience.name=Experience Upgrade
item.oc.UpgradeGenerator.name=Generator Upgrade
item.oc.UpgradeInventory.name=Inventory Upgrade
item.oc.UpgradeInventoryController.name=Inventory Controller Upgrade
item.oc.UpgradeLeash.name=Leash Upgrade
item.oc.UpgradeNavigation.name=Navigation Upgrade
item.oc.UpgradePiston.name=Piston Upgrade
item.oc.UpgradeSign.name=Sign I/O Upgrade
@ -285,6 +286,7 @@ oc:tooltip.UpgradeExperience=This upgrade allows robots to accumulate experience
oc:tooltip.UpgradeGenerator=Can be used to generate energy from fuel on the go. Burns items to generate energy over time, based on their fuel value.[nl] §fEfficiency§7: §a%s%%§7
oc:tooltip.UpgradeInventory=This upgrade provides inventory space to the robot. Without one of these, robots will not be able to store items internally.
oc:tooltip.UpgradeInventoryController=This upgrade allows the robot more control in how it interacts with external inventories, and allows it to swap its equipped tool with an item in its inventory.
oc:tooltip.UpgradeLeash=Allows some devices, such as drones, to bind Isaa- excuse me... *chatter* My apologies. I'm just being told this is actually used to put animals on a leash. Multiple animals, even. Odd.
oc:tooltip.UpgradeNavigation=Can be used to determine the position and orientation of the robot. The position is relative to the center of the map that was used to craft this upgrade.
oc:tooltip.UpgradePiston=This upgrade is very pushy. It allows moving blocks, similar to when using a piston. It does §lnot§7 move entities, however.
oc:tooltip.UpgradeSign=Allows reading text on and writing text to signs.
@ -323,6 +325,7 @@ item.oc.UpgradeExperience.usage=The §oExperience Upgrade§r is a very special u
item.oc.UpgradeGenerator.usage=The §oGenerator Upgrade§r allows robots to refuel on the go. Currently it only supports solid fuels, such as coal. It has an internal intentory that can store one item stack of fuel. Surplus fuel can be removed from the generator using the according API method. When removing a generator upgrade from a robot its contents will be dropped into the world.[nl][nl]The efficiency of generators is lower than that of usual generators of other mods, meaning it is usually more fuel efficient to power robots using a §oCharger§r.
item.oc.UpgradeInventory.usage=The §oInventory Upgrade§r provides inventory slots to robots. For each inventory upgrade a robot will gain an addition 16 inventory slots, up to a maximum of 64 slots in total. If no inventory upgrade is installed in a robot it will not be able to store or pick up items.
item.oc.UpgradeInventoryController.usage=The §oInventory Controller Upgrade§r provides extended inventory interaction to robots. It allows the robots to excplicitly target slots in external inventories when dropping or sucking items. It also allows robots to read detailed information about item stacks. Lastly it provides robots with a means to change their equipped tool without external help.[nl][nl]This upgrade can also be placed in §oAdapters§r, where it provides similar inspection methods for inventories adjacent to the adapter as it does to the robot. It does not allow the adapter to move items into or out of inventories, however. This feature is only available in robots.
item.oc.UpgradeLeash.usage=The §oLeash Upgrade§r allows putting animals on a leash, bound to the entity that hosts the device the component is used by, for example drones. Using this upgrade, multiple animals can be leashed at the same time, which makes this quite useful for moving herds.
item.oc.UpgradeNavigation.usage=The §oNavigation Upgrade§r provides location and orientation information to §oRobots§r and §oTablets§r it is installed in. The coordinates the upgrade provides are relative to the center of the map that was used to craft the upgrade, and the functional range is based on the size of that map.[nl][nl]Navigation upgrades can be re-crafted with a map to replace the map in the upgrade with another one. The old map will be returned.
item.oc.UpgradeTank.usage=The §oTank Upgrade§r allows robots to store fluids. Each tank can only hold a single type of fluids, and provides a volume of 16 buckets (16000mB). Robots can drain liquids from the world and from other fluid tanks, and can fill the fluids back into fluid tanks, and, when supported by the fluid, place them back into the world. There is no limit to the number of tanks that can be installed in a robot.
item.oc.UpgradeTankController.usage=The §oTank Controller Upgrade§r is to fluid tanks what the §oInventory Controller Upgrade§r is to normal inventories. It allows robots to query more detailed information about tanks in and next to the robot.[nl][nl]This upgrade can also be installed in §oAdapters§r, allowing computers connected to the adapter to query information about the tanks adjacent to the adapter.

View File

@ -9,7 +9,7 @@ analyzer {
droneCase {
input: [[{block="minecraft:end_stone"}, compass, {block="minecraft:end_stone"}]
["oc:circuitChip2", "oc:microcontrollerCase", "oc:circuitChip2"]
[{block="minecraft:end_stone"}, "oc:componentBus3", {block="minecraft:end_stone"}]]
[{block="minecraft:end_stone"}, "oc:componentBus2", {block="minecraft:end_stone"}]]
}
microcontrollerCase {
input: [[nuggetIron, "oc:circuitChip1", nuggetIron]
@ -210,6 +210,11 @@ inventoryControllerUpgrade {
[dispenser, "oc:circuitChip2", craftingPiston]
[ingotGold, "oc:materialCircuitBoardPrinted", ingotGold]]
}
leashUpgrade {
input: [[ingotIron, lead, ingotIron]
[lead, "oc:materialCU", lead]
[ingotIron, lead, ingotIron]]
}
navigationUpgrade {
input: [[ingotGold, compass, ingotGold]
["oc:circuitChip2", {item=map, subID=any}, "oc:circuitChip2"]

Binary file not shown.

After

Width:  |  Height:  |  Size: 349 B

View File

@ -25,6 +25,7 @@ class ClassTransformer extends IClassTransformer {
if (name == "li.cil.oc.common.tileentity.traits.Computer" || name == "li.cil.oc.common.tileentity.Rack") {
transformedClass = ensureStargateTechCompatibility(transformedClass)
}
if (transformedClass != null
&& !name.startsWith("net.minecraft.")
&& !name.startsWith("net.minecraftforge.")
@ -123,6 +124,75 @@ class ClassTransformer extends IClassTransformer {
}
}
}
// Inject some code into the EntityLiving classes recreateLeash method to allow
// proper loading of leashes tied to entities using the leash upgrade. This is
// necessary because entities only save the entity they are leashed to if that
// entity is an EntityLivingBase - which drones, for example, are not, for good
// reason. We work around this by re-leashing them in the load method of the
// leash upgrade. The leashed entity would then still unleash itself and, more
// problematically drop a leash item. To avoid this, we extend the
// if (this.isLeashed && this.field_110170_bx != null)
// check to read
// if (this.isLeashed && this.field_110170_bx != null && this.leashedToEntity == null)
// which should not interfere with any existing logic, but avoid leashing
// restored manually in the load phase to not be broken again.
if (transformedClass != null && name == "net.minecraft.entity.EntityLiving") {
insertInto(transformedClass, "recreateLeash", instructions => 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 ||

View File

@ -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

View File

@ -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")
}
}

View File

@ -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)
}

View File

@ -0,0 +1,3 @@
package li.cil.oc.common.item
class UpgradeLeash(val parent: Delegator) extends Delegate with ItemTier

View File

@ -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)
// ----------------------------------------------------------------------- //

View File

@ -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)
}

View File

@ -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))
}

View File

@ -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
}

View File

@ -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]
}

View File

@ -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")

View File

@ -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))) {

View File

@ -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

View File

@ -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))
}
}

View File

@ -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

View File

@ -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) = {

View File

@ -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)
}