diff --git a/src/main/java/li/cil/oc/api/machine/Machine.java b/src/main/java/li/cil/oc/api/machine/Machine.java index 19c2cdc63..310bee3e0 100644 --- a/src/main/java/li/cil/oc/api/machine/Machine.java +++ b/src/main/java/li/cil/oc/api/machine/Machine.java @@ -57,6 +57,22 @@ public interface Machine extends ManagedEnvironment, Context { */ int componentCount(); + /** + * Gets the amount of energy this machine consumes per tick when it is + * running. + * + * @return the energy consumed per tick by the machine. + */ + double getCostPerTick(); + + /** + * Sets the amount of energy this machine consumes per tick when it is + * running. + * + * @param value the energy consumed per tick by the machine. + */ + void setCostPerTick(double value); + /** * The address of the file system that holds the machine's file system for * temporary files (tmpfs). This may return null if either the @@ -203,11 +219,4 @@ public interface Machine extends ManagedEnvironment, Context { * @return whether the player was removed from the user list. */ boolean removeUser(String name); - - /** - * This is only here because of some sub-optimal design decisions for the - * internal robot implementation, it will go away. Do not use. - */ - @Deprecated - boolean isRobot(); } diff --git a/src/main/java/li/cil/oc/api/machine/Robot.java b/src/main/java/li/cil/oc/api/machine/Robot.java new file mode 100644 index 000000000..e14741058 --- /dev/null +++ b/src/main/java/li/cil/oc/api/machine/Robot.java @@ -0,0 +1,55 @@ +package li.cil.oc.api.machine; + +import net.minecraft.entity.player.EntityPlayer; + +/** + * This interface allows interaction with robots. + *

+ * It is intended to be used by components when installed in a robot. In that + * case, the robot in question is the tile entity passed to item driver when + * asked to create the component's environment. + */ +public interface Robot { + /** + * Returns the fake player used to represent the robot as an entity for + * certain actions that require one. + *

+ * This will automatically be positioned and rotated to represent the + * robot's current position and rotation in the world. Use this to trigger + * events involving the robot that require a player entity, and for + * interacting with the robots' inventory. + *

+ * Note that the inventory of each robot is structured such that the first + * four slots are the "equipment" slots, from left to right, i.e. slot one + * is the tool slot, slot two is the card slot, three the disk slot and + * slot four is for upgrades. The inventory proper starts after that. + * + * @return the fake player for the robot. + */ + EntityPlayer player(); + + /** + * Gets the index of the currently selected slot in the robot's inventory. + * + * @return the index of the currently selected slot. + */ + int selectedSlot(); + + /** + * Causes the currently installed upgrade to be saved and synchronized. + *

+ * If no upgrade is installed in the robot this does nothing. + *

+ * This is intended for upgrade components, to allow them to update their + * client side representation for rendering purposes. The component will be + * saved to its item's NBT tag compound, as it would be when the game is + * saved, and then re-sent to the client. Keep the number of calls to this + * function low, since each call causes a network packet to be sent. + *

+ * This is somewhat of a 'meh, it works' approach that I'm not really happy + * with and plan to replace with something cleaner. Don't use unless you + * absolutely really have to. + */ + @Deprecated + void saveUpgrade(); +} diff --git a/src/main/java/li/cil/oc/api/network/RobotContext.java b/src/main/java/li/cil/oc/api/network/RobotContext.java index 6e72bbee8..f25f76b36 100644 --- a/src/main/java/li/cil/oc/api/network/RobotContext.java +++ b/src/main/java/li/cil/oc/api/network/RobotContext.java @@ -1,7 +1,15 @@ package li.cil.oc.api.network; +import li.cil.oc.api.machine.Robot; import net.minecraft.entity.player.EntityPlayer; +/** + * This is no longer used nor provided to callbacks. The context in a callback + * will always be the one of a machine. To get access to a robot either use + * its tile entity where possible (which implements {@link Robot}) or use + * (Robot)((Machine)context).owner(). + */ +@Deprecated public interface RobotContext extends Context { /** * Gets the index of the currently selected slot in the robot's inventory. diff --git a/src/main/java/li/cil/oc/api/package-info.java b/src/main/java/li/cil/oc/api/package-info.java index 49cafe141..7467eaf89 100644 --- a/src/main/java/li/cil/oc/api/package-info.java +++ b/src/main/java/li/cil/oc/api/package-info.java @@ -37,5 +37,5 @@ @cpw.mods.fml.common.API( owner = "OpenComputers|Core", provides = "OpenComputersAPI", - apiVersion = "1.4.1") + apiVersion = "1.4.2") package li.cil.oc.api; \ No newline at end of file diff --git a/src/main/java/li/cil/oc/common/tileentity/Charger.scala b/src/main/java/li/cil/oc/common/tileentity/Charger.scala index 913d0862e..d226c5d13 100644 --- a/src/main/java/li/cil/oc/common/tileentity/Charger.scala +++ b/src/main/java/li/cil/oc/common/tileentity/Charger.scala @@ -34,7 +34,7 @@ class Charger extends Environment with RedstoneAware with Analyzable { val charge = Settings.get.chargeRate * chargeSpeed robots.collect { - case Some(proxy) => node.changeBuffer(proxy.robot.node.changeBuffer(charge + node.changeBuffer(-charge))) + case Some(proxy) => node.changeBuffer(proxy.robot.bot.node.changeBuffer(charge + node.changeBuffer(-charge))) } } else if (chargeSpeed > 0 && world.getWorldInfo.getWorldTotalTime % 10 == 0) { diff --git a/src/main/java/li/cil/oc/common/tileentity/Computer.scala b/src/main/java/li/cil/oc/common/tileentity/Computer.scala index 36499ee43..beb0b9d12 100644 --- a/src/main/java/li/cil/oc/common/tileentity/Computer.scala +++ b/src/main/java/li/cil/oc/common/tileentity/Computer.scala @@ -18,11 +18,11 @@ import stargatetech2.api.bus.IBusDevice // See AbstractBusAware as to why we have to define the IBusDevice here. @Optional.Interface(iface = "stargatetech2.api.bus.IBusDevice", modid = "StargateTech2") abstract class Computer(isRemote: Boolean) extends Environment with ComponentInventory with Rotatable with BundledRedstoneAware with AbstractBusAware with IBusDevice with Analyzable with Owner { - protected val _computer = if (isRemote) null else Machine.create(this) + private lazy val _computer = if (isRemote) null else Machine.create(this) def computer = _computer - override def node = if (isClient) null else computer.node + override def node = if (isServer) computer.node else null override lazy val isClient = computer == null diff --git a/src/main/java/li/cil/oc/common/tileentity/Robot.scala b/src/main/java/li/cil/oc/common/tileentity/Robot.scala index ffdca6ba8..2c2bd7c83 100644 --- a/src/main/java/li/cil/oc/common/tileentity/Robot.scala +++ b/src/main/java/li/cil/oc/common/tileentity/Robot.scala @@ -24,8 +24,11 @@ import net.minecraftforge.common.ForgeDirection // robot moves we only create a new proxy tile entity, hook the instance of this // class that was held by the old proxy to it and can then safely forget the // old proxy, which will be cleaned up by Minecraft like any other tile entity. -class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory with Buffer with PowerInformation with RobotContext { +class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory with Buffer with PowerInformation with api.machine.Robot { def this() = this(false) + if (isServer) { + computer.setCostPerTick(Settings.get.robotCost) + } var proxy: RobotProxy = _ @@ -51,13 +54,13 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w // ----------------------------------------------------------------------- // - override def node: ComponentConnector = if (isClient) null else computer.node.asInstanceOf[ComponentConnector] + override def node = if (isServer) computer.node else null override val _buffer = new common.component.Buffer(this) { override def maxResolution = (48, 14) } - override val _computer = if (isRemote) null else new robot.Robot(this) - val (gpu, keyboard) = if (isServer) { + val (bot, gpu, keyboard) = if (isServer) { + val bot = new robot.Robot(this) val gpu = new GraphicsCard.Tier1 { override val maxResolution = (48, 14) } @@ -66,9 +69,9 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w world.getBlockTileEntity(x, y, z) == proxy && p.getDistanceSq(x + 0.5, y + 0.5, z + 0.5) <= 64 } - (gpu, keyboard) + (bot, gpu, keyboard) } - else (null, null) + else (null, null, null) var owner = "OpenComputers" @@ -115,7 +118,7 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w // pow(xp(level) - base, 1/exp) / const = level level = math.min((Math.pow(xp - Settings.get.baseXpToLevel, 1 / Settings.get.exponentialXpGrowth) / Settings.get.constantXpGrowth).toInt, 30) if (isServer) { - node.setLocalBufferSize(Settings.get.bufferRobot + Settings.get.bufferPerLevel * level) + bot.node.setLocalBufferSize(Settings.get.bufferRobot + Settings.get.bufferPerLevel * level) } } @@ -209,7 +212,7 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w if (stack.hasTagCompound) { xp = stack.getTagCompound.getDouble(Settings.namespace + "xp") updateXpInfo() - node.changeBuffer(stack.getTagCompound.getInteger(Settings.namespace + "storedEnergy")) + bot.node.changeBuffer(stack.getTagCompound.getInteger(Settings.namespace + "storedEnergy")) } } @@ -270,9 +273,11 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w // ----------------------------------------------------------------------- // override def updateEntity() { - if (!addedToNetwork) { + if (isServer && !addedToNetwork) { addedToNetwork = true api.Network.joinNewNetwork(node) + // For upgrading from when the energy was stored by the machine's node. + node.asInstanceOf[Connector].setLocalBufferSize(0) } if (animationTicksLeft > 0) { animationTicksLeft -= 1 @@ -287,8 +292,8 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w super.updateEntity() if (isServer) { gpu.update() - globalBuffer = node.globalBuffer - globalBufferSize = node.globalBufferSize + globalBuffer = bot.node.globalBuffer + globalBufferSize = bot.node.globalBufferSize updatePowerInformation() if (xpChanged && world.getWorldInfo.getWorldTotalTime % 200 == 0) { xpChanged = false @@ -321,6 +326,7 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w buffer.load(nbt.getCompoundTag(Settings.namespace + "buffer")) gpu.load(nbt.getCompoundTag(Settings.namespace + "gpu")) keyboard.load(nbt.getCompoundTag(Settings.namespace + "keyboard")) + bot.load(nbt.getCompoundTag(Settings.namespace + "robot")) if (nbt.hasKey(Settings.namespace + "owner")) { owner = nbt.getString(Settings.namespace + "owner") } @@ -345,6 +351,7 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w nbt.setNewCompoundTag(Settings.namespace + "buffer", buffer.save) nbt.setNewCompoundTag(Settings.namespace + "gpu", gpu.save) nbt.setNewCompoundTag(Settings.namespace + "keyboard", keyboard.save) + nbt.setNewCompoundTag(Settings.namespace + "robot", bot.save) nbt.setString(Settings.namespace + "owner", owner) nbt.setDouble(Settings.namespace + "xp", xp) nbt.setInteger(Settings.namespace + "selectedSlot", selectedSlot) @@ -418,6 +425,7 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w override def onMachineConnect(node: Node) { super.onConnect(node) if (node == this.node) { + node.connect(bot.node) node.connect(buffer.node) node.connect(gpu.node) buffer.node.connect(keyboard.node) @@ -441,6 +449,7 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w node.remove() gpu.node.remove() keyboard.node.remove() + bot.node.remove() } } diff --git a/src/main/java/li/cil/oc/common/tileentity/RobotProxy.scala b/src/main/java/li/cil/oc/common/tileentity/RobotProxy.scala index 59a8e2574..21a236ec5 100644 --- a/src/main/java/li/cil/oc/common/tileentity/RobotProxy.scala +++ b/src/main/java/li/cil/oc/common/tileentity/RobotProxy.scala @@ -14,7 +14,7 @@ import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound import net.minecraftforge.common.ForgeDirection -class RobotProxy(val robot: Robot) extends Computer(robot.isClient) with ISidedInventory with Buffer with PowerInformation with RobotContext { +class RobotProxy(val robot: Robot) extends Computer(robot.isClient) with ISidedInventory with Buffer with PowerInformation with api.machine.Robot { def this() = this(new Robot(false)) // ----------------------------------------------------------------------- // @@ -23,8 +23,6 @@ class RobotProxy(val robot: Robot) extends Computer(robot.isClient) with ISidedI withComponent("robot", Visibility.Neighbors). create() - override protected val _computer = null - override def computer = robot.computer override def maxComponents = robot.maxComponents diff --git a/src/main/java/li/cil/oc/server/component/UpgradeCrafting.scala b/src/main/java/li/cil/oc/server/component/UpgradeCrafting.scala index 07e2841f0..793580741 100644 --- a/src/main/java/li/cil/oc/server/component/UpgradeCrafting.scala +++ b/src/main/java/li/cil/oc/server/component/UpgradeCrafting.scala @@ -2,25 +2,26 @@ package li.cil.oc.server.component import cpw.mods.fml.common.registry.GameRegistry import li.cil.oc.api.Network +import li.cil.oc.api.machine.Robot import li.cil.oc.api.network._ import net.minecraft.entity.player.EntityPlayer import net.minecraft.inventory.{Container, InventoryCrafting} import net.minecraft.item.ItemStack import net.minecraft.item.crafting.CraftingManager -import net.minecraft.tileentity.{TileEntity => MCTileEntity} +import net.minecraft.tileentity.TileEntity import net.minecraftforge.common.MinecraftForge import net.minecraftforge.event.entity.player.PlayerDestroyItemEvent import scala.collection.mutable -class UpgradeCrafting(val owner: MCTileEntity) extends ManagedComponent { +class UpgradeCrafting(val owner: TileEntity with Robot) extends ManagedComponent { val node = Network.newNode(this, Visibility.Network). withComponent("crafting"). create() @Callback(doc = """function([count:number]):number -- Tries to craft the specified number of items in the top left area of the inventory.""") - def craft(context: RobotContext, args: Arguments): Array[AnyRef] = { + def craft(context: Context, args: Arguments): Array[AnyRef] = { val count = if (args.count > 0) args.checkInteger(0) else Int.MaxValue - result(CraftingInventory.craft(context, count)) + result(CraftingInventory.craft(count)) } private object CraftingInventory extends InventoryCrafting(new Container { @@ -28,15 +29,15 @@ class UpgradeCrafting(val owner: MCTileEntity) extends ManagedComponent { }, 3, 3) { var amountPossible = 0 - def craft(context: RobotContext, wantedCount: Int): Boolean = { - load(context) + def craft(wantedCount: Int): Boolean = { + load() val manager = CraftingManager.getInstance val result = manager.findMatchingRecipe(CraftingInventory, owner.getWorldObj) if (result == null) return false val targetStackSize = if (result.isStackable) math.min(wantedCount, result.getMaxStackSize) else result.stackSize val timesCrafted = math.min(targetStackSize / result.stackSize, amountPossible) if (timesCrafted <= 0) return true - GameRegistry.onItemCrafted(context.player, result, this) + GameRegistry.onItemCrafted(owner.player, result, this) val surplus = mutable.ArrayBuffer.empty[ItemStack] for (slot <- 0 until getSizeInventory) { val stack = getStackInSlot(slot) @@ -46,7 +47,7 @@ class UpgradeCrafting(val owner: MCTileEntity) extends ManagedComponent { if (item.hasContainerItem) { val container = item.getContainerItemStack(stack) if (container.isItemStackDamageable && container.getItemDamage > container.getMaxDamage) { - MinecraftForge.EVENT_BUS.post(new PlayerDestroyItemEvent(context.player, container)) + MinecraftForge.EVENT_BUS.post(new PlayerDestroyItemEvent(owner.player, container)) } else if (container.getItem.doesContainerItemLeaveCraftingGrid(container) || getStackInSlot(slot) != null) { surplus += container @@ -58,9 +59,9 @@ class UpgradeCrafting(val owner: MCTileEntity) extends ManagedComponent { } } } - save(context) + save() result.stackSize *= timesCrafted - val inventory = context.player.inventory + val inventory = owner.player.inventory inventory.addItemStackToInventory(result) for (stack <- surplus) { inventory.addItemStackToInventory(stack) @@ -68,8 +69,8 @@ class UpgradeCrafting(val owner: MCTileEntity) extends ManagedComponent { true } - def load(context: RobotContext) { - val inventory = context.player.inventory + def load() { + val inventory = owner.player.inventory amountPossible = Int.MaxValue for (slot <- 0 until getSizeInventory) { val stack = inventory.getStackInSlot(toParentSlot(slot)) @@ -80,8 +81,8 @@ class UpgradeCrafting(val owner: MCTileEntity) extends ManagedComponent { } } - def save(context: RobotContext) { - val inventory = context.player.inventory + def save() { + val inventory = owner.player.inventory for (slot <- 0 until getSizeInventory) { inventory.setInventorySlotContents(toParentSlot(slot), getStackInSlot(slot)) } diff --git a/src/main/java/li/cil/oc/server/component/UpgradeGenerator.scala b/src/main/java/li/cil/oc/server/component/UpgradeGenerator.scala index b835c6696..1989a2b16 100644 --- a/src/main/java/li/cil/oc/server/component/UpgradeGenerator.scala +++ b/src/main/java/li/cil/oc/server/component/UpgradeGenerator.scala @@ -1,6 +1,7 @@ package li.cil.oc.server.component import li.cil.oc.api.Network +import li.cil.oc.api.machine.Robot import li.cil.oc.api.network._ import li.cil.oc.util.ExtendedNBT._ import li.cil.oc.{OpenComputers, api, Settings} @@ -9,7 +10,7 @@ import net.minecraft.item.ItemStack import net.minecraft.nbt.NBTTagCompound import net.minecraft.tileentity.{TileEntity, TileEntityFurnace} -class UpgradeGenerator(val owner: TileEntity) extends ManagedComponent { +class UpgradeGenerator(val owner: TileEntity with Robot) extends ManagedComponent { val node = Network.newNode(this, Visibility.Network). withComponent("generator", Visibility.Neighbors). withConnector(). @@ -25,10 +26,10 @@ class UpgradeGenerator(val owner: TileEntity) extends ManagedComponent { // ----------------------------------------------------------------------- // @Callback(doc = """function([count:number]):boolean -- Tries to insert fuel from the selected slot into the generator's queue.""") - def insert(context: RobotContext, args: Arguments): Array[AnyRef] = { + def insert(context: Context, args: Arguments): Array[AnyRef] = { val count = if (args.count > 0) args.checkInteger(0) else 64 - val player = context.player - val stack = player.inventory.getStackInSlot(context.selectedSlot) + val player = owner.player + val stack = player.inventory.getStackInSlot(owner.selectedSlot) if (stack == null) return result(Unit, "selected slot is empty") if (!TileEntityFurnace.isItemFuel(stack)) { return result(Unit, "selected slot does not contain fuel") @@ -49,7 +50,7 @@ class UpgradeGenerator(val owner: TileEntity) extends ManagedComponent { case _ => inventory = Some(stack.splitStack(math.min(stack.stackSize, count))) } - player.inventory.setInventorySlotContents(context.selectedSlot, stack) + player.inventory.setInventorySlotContents(owner.selectedSlot, stack) result(true) } @@ -62,12 +63,12 @@ class UpgradeGenerator(val owner: TileEntity) extends ManagedComponent { } @Callback(doc = """function([count:number]):boolean -- Tries to remove items from the generator's queue.""") - def remove(context: RobotContext, args: Arguments): Array[AnyRef] = { + def remove(context: Context, args: Arguments): Array[AnyRef] = { val count = if (args.count > 0) args.checkInteger(0) else Int.MaxValue inventory match { case Some(stack) => val removedStack = stack.splitStack(math.min(count, stack.stackSize)) - val success = context.player.inventory.addItemStackToInventory(removedStack) + val success = owner.player.inventory.addItemStackToInventory(removedStack) stack.stackSize += removedStack.stackSize if (success && stack.stackSize <= 0) { inventory = None @@ -101,10 +102,7 @@ class UpgradeGenerator(val owner: TileEntity) extends ManagedComponent { } } - private def updateClient() = owner match { - case robot: RobotContext => robot.saveUpgrade() - case _ => - } + private def updateClient() = owner.saveUpgrade() // ----------------------------------------------------------------------- // diff --git a/src/main/java/li/cil/oc/server/component/machine/LuaJLuaArchitecture.scala b/src/main/java/li/cil/oc/server/component/machine/LuaJLuaArchitecture.scala index 9d3e00678..556a5d2ba 100644 --- a/src/main/java/li/cil/oc/server/component/machine/LuaJLuaArchitecture.scala +++ b/src/main/java/li/cil/oc/server/component/machine/LuaJLuaArchitecture.scala @@ -248,7 +248,8 @@ class LuaJLuaArchitecture(machine: api.machine.Machine) extends LuaArchitecture( }) // Are we a robot? (No this is not a CAPTCHA.) - computer.set("isRobot", (_: Varargs) => LuaValue.valueOf(machine.isRobot)) + // TODO deprecate this + computer.set("isRobot", (_: Varargs) => LuaValue.valueOf(machine.components.contains("robot"))) computer.set("freeMemory", (_: Varargs) => LuaValue.valueOf(memory / 2)) diff --git a/src/main/java/li/cil/oc/server/component/machine/Machine.scala b/src/main/java/li/cil/oc/server/component/machine/Machine.scala index 75b823ea1..2d25c1511 100644 --- a/src/main/java/li/cil/oc/server/component/machine/Machine.scala +++ b/src/main/java/li/cil/oc/server/component/machine/Machine.scala @@ -24,7 +24,7 @@ import scala.collection.mutable class Machine(val owner: Owner, constructor: Constructor[_ <: Architecture]) extends ManagedComponent with machine.Machine with Runnable { val node = Network.newNode(this, Visibility.Network). withComponent("computer", Visibility.Neighbors). - withConnector(if (isRobot) Settings.get.bufferRobot + 30 * Settings.get.bufferPerLevel else Settings.get.bufferComputer). + withConnector(Settings.get.bufferComputer). create() val tmp = if (Settings.get.tmpSize > 0) { @@ -48,13 +48,13 @@ class Machine(val owner: Owner, constructor: Constructor[_ <: Architecture]) ext // ----------------------------------------------------------------------- // - private[component] var timeStarted = 0L // Game-world time [ms] for os.uptime(). + private var timeStarted = 0L // Game-world time [ms] for os.uptime(). var worldTime = 0L // Game-world time for os.time(). - private[component] var cpuTotal = 0L // Pseudo-real-world time [ns] for os.clock(). + private var cpuTotal = 0L // Pseudo-real-world time [ns] for os.clock(). - private[component] var cpuStart = 0L // Pseudo-real-world time [ns] for os.clock(). + private var cpuStart = 0L // Pseudo-real-world time [ns] for os.clock(). private var remainIdle = 0 // Ticks left to sleep before resuming. @@ -62,30 +62,32 @@ class Machine(val owner: Owner, constructor: Constructor[_ <: Architecture]) ext private var usersChanged = false // Send updated users list to clients? - private[component] var message: Option[String] = None // For error messages. + private var message: Option[String] = None // For error messages. + + private var cost = Settings.get.computerCost * Settings.get.tickFrequency // ----------------------------------------------------------------------- // - def lastError = message.orNull - override def components = scala.collection.convert.WrapAsJava.mapAsJavaMap(_components) - override def users = _users.synchronized(_users.toArray) - - override def tmpAddress = tmp.fold(null: String)(_.node.address) - - override def upTime() = (worldTime - timeStarted) / 20.0 - - override def cpuTime = (cpuTotal + (System.nanoTime() - cpuStart)) * 10e-10 - - def isRobot = false - - private val cost = (if (isRobot) Settings.get.robotCost else Settings.get.computerCost) * Settings.get.tickFrequency - def componentCount = _components.count { case (_, name) => name != "filesystem" } + addedComponents.count(_.name != "filesystem") - 1 // -1 = this computer + override def tmpAddress = tmp.fold(null: String)(_.node.address) + + def lastError = message.orNull + + override def setCostPerTick(value: Double) = cost = value * Settings.get.tickFrequency + + override def getCostPerTick = cost / Settings.get.tickFrequency + + override def users = _users.synchronized(_users.toArray) + + override def upTime() = (worldTime - timeStarted) / 20.0 + + override def cpuTime = (cpuTotal + (System.nanoTime() - cpuStart)) * 10e-10 + // ----------------------------------------------------------------------- // override def address = node.address diff --git a/src/main/java/li/cil/oc/server/component/machine/NativeLuaArchitecture.scala b/src/main/java/li/cil/oc/server/component/machine/NativeLuaArchitecture.scala index 1d85ea283..2fb9915be 100644 --- a/src/main/java/li/cil/oc/server/component/machine/NativeLuaArchitecture.scala +++ b/src/main/java/li/cil/oc/server/component/machine/NativeLuaArchitecture.scala @@ -295,8 +295,9 @@ class NativeLuaArchitecture(machine: api.machine.Machine) extends LuaArchitectur lua.setField(-2, "address") // Are we a robot? (No this is not a CAPTCHA.) + // TODO deprecate this lua.pushScalaFunction(lua => { - lua.pushBoolean(machine.isRobot) + lua.pushBoolean(machine.components.contains("robot")) 1 }) lua.setField(-2, "isRobot") diff --git a/src/main/java/li/cil/oc/server/component/robot/Player.scala b/src/main/java/li/cil/oc/server/component/robot/Player.scala index 28befe072..a60cc34cd 100644 --- a/src/main/java/li/cil/oc/server/component/robot/Player.scala +++ b/src/main/java/li/cil/oc/server/component/robot/Player.scala @@ -368,7 +368,7 @@ class Player(val robot: tileentity.Robot) extends EntityPlayer(robot.world, Sett override def addExhaustion(amount: Float) { if (Settings.get.robotExhaustionCost > 0) { - robot.node.changeBuffer(-Settings.get.robotExhaustionCost * amount) + robot.bot.node.changeBuffer(-Settings.get.robotExhaustionCost * amount) } robot.addXp(Settings.get.robotExhaustionXpRate * amount) } diff --git a/src/main/java/li/cil/oc/server/component/robot/Robot.scala b/src/main/java/li/cil/oc/server/component/robot/Robot.scala index ba4df297b..17db12887 100644 --- a/src/main/java/li/cil/oc/server/component/robot/Robot.scala +++ b/src/main/java/li/cil/oc/server/component/robot/Robot.scala @@ -3,7 +3,7 @@ package li.cil.oc.server.component.robot import li.cil.oc.api import li.cil.oc.api.network._ import li.cil.oc.common.tileentity -import li.cil.oc.server.component.machine.Machine +import li.cil.oc.server.component.ManagedComponent import li.cil.oc.server.{PacketSender => ServerPacketSender} import li.cil.oc.util.ExtendedNBT._ import li.cil.oc.{OpenComputers, Settings} @@ -19,8 +19,12 @@ import net.minecraftforge.common.ForgeDirection import net.minecraftforge.fluids.FluidRegistry import scala.collection.convert.WrapAsScala._ -// TODO rework this so as not to extend machine but be an extra component instead -class Robot(val robot: tileentity.Robot) extends Machine(robot, api.Machine.LuaArchitecture.getConstructor(classOf[api.machine.Machine])) with RobotContext { +class Robot(val robot: tileentity.Robot) extends ManagedComponent { + val node = api.Network.newNode(this, Visibility.Neighbors). + withComponent("robot"). + withConnector(Settings.get.bufferRobot + 30 * Settings.get.bufferPerLevel). + create() + def actualSlot(n: Int) = robot.actualSlot(n) def world = robot.world @@ -36,8 +40,6 @@ class Robot(val robot: tileentity.Robot) extends Machine(robot, api.Machine.LuaA val romRobot = Option(api.FileSystem.asManagedEnvironment(api.FileSystem. fromClass(OpenComputers.getClass, Settings.resourceDomain, "lua/component/robot"), "robot")) - override def isRobot = true - def selectedSlot = robot.selectedSlot def player = robot.player() @@ -501,7 +503,7 @@ class Robot(val robot: tileentity.Robot) extends Machine(robot, api.Machine.LuaA result(Unit, what) } else { - if (!robot.node.tryChangeBuffer(-Settings.get.robotMoveCost)) { + if (!node.tryChangeBuffer(-Settings.get.robotMoveCost)) { result(Unit, "not enough energy") } else if (robot.move(direction)) { @@ -510,7 +512,7 @@ class Robot(val robot: tileentity.Robot) extends Machine(robot, api.Machine.LuaA result(true) } else { - robot.node.changeBuffer(Settings.get.robotMoveCost) + node.changeBuffer(Settings.get.robotMoveCost) result(Unit, "impossible move") } } @@ -520,7 +522,7 @@ class Robot(val robot: tileentity.Robot) extends Machine(robot, api.Machine.LuaA @Callback def turn(context: Context, args: Arguments): Array[AnyRef] = { val clockwise = args.checkBoolean(0) - if (robot.node.tryChangeBuffer(-Settings.get.robotTurnCost)) { + if (node.tryChangeBuffer(-Settings.get.robotTurnCost)) { if (clockwise) robot.rotate(ForgeDirection.UP) else robot.rotate(ForgeDirection.DOWN) robot.animateTurn(clockwise, Settings.get.turnDelay) @@ -537,7 +539,10 @@ class Robot(val robot: tileentity.Robot) extends Machine(robot, api.Machine.LuaA override def onConnect(node: Node) { super.onConnect(node) if (node == this.node) { - romRobot.foreach(rom => node.connect(rom.node)) + romRobot.foreach(fs => { + fs.node.asInstanceOf[Component].setVisibility(Visibility.Network) + node.connect(fs.node) + }) } } @@ -550,7 +555,7 @@ class Robot(val robot: tileentity.Robot) extends Machine(robot, api.Machine.LuaA override def save(nbt: NBTTagCompound) { super.save(nbt) - romRobot.foreach(rom => nbt.setNewCompoundTag("romRobot", rom.save)) + romRobot.foreach(fs => nbt.setNewCompoundTag("romRobot", fs.save)) } // ----------------------------------------------------------------------- // diff --git a/src/main/java/li/cil/oc/server/driver/item/UpgradeCrafting.scala b/src/main/java/li/cil/oc/server/driver/item/UpgradeCrafting.scala index c07201912..55119e8de 100644 --- a/src/main/java/li/cil/oc/server/driver/item/UpgradeCrafting.scala +++ b/src/main/java/li/cil/oc/server/driver/item/UpgradeCrafting.scala @@ -2,14 +2,19 @@ package li.cil.oc.server.driver.item import li.cil.oc.Items import li.cil.oc.api.driver.Slot +import li.cil.oc.api.machine.Robot import li.cil.oc.server.component import net.minecraft.item.ItemStack -import net.minecraft.tileentity.{TileEntity => MCTileEntity} +import net.minecraft.tileentity.TileEntity object UpgradeCrafting extends Item { override def worksWith(stack: ItemStack) = isOneOf(stack, Items.upgradeCrafting) - override def createEnvironment(stack: ItemStack, container: MCTileEntity) = new component.UpgradeCrafting(container) + override def createEnvironment(stack: ItemStack, container: TileEntity) = + container match { + case robot: Robot => new component.UpgradeCrafting(robot) + case _ => null + } override def slot(stack: ItemStack) = Slot.Upgrade } diff --git a/src/main/java/li/cil/oc/server/network/Component.scala b/src/main/java/li/cil/oc/server/network/Component.scala index 3939889aa..4e0bb675a 100644 --- a/src/main/java/li/cil/oc/server/network/Component.scala +++ b/src/main/java/li/cil/oc/server/network/Component.scala @@ -4,6 +4,7 @@ import cpw.mods.fml.common.FMLCommonHandler import cpw.mods.fml.relauncher.Side import java.lang.reflect.{Modifier, Method, InvocationTargetException} import li.cil.oc.OpenComputers +import li.cil.oc.api.machine.Robot import li.cil.oc.api.network import li.cil.oc.api.network.{Node => ImmutableNode, _} import li.cil.oc.server.component.machine.Machine @@ -164,7 +165,7 @@ object Component { ms.filter(_.isAnnotationPresent(classOf[network.Callback])).foreach(m => if (m.getParameterTypes.size != 2 || - (m.getParameterTypes()(0) != classOf[Context] && m.getParameterTypes()(0) != classOf[RobotContext]) || + (m.getParameterTypes()(0) != classOf[Context] && m.getParameterTypes()(0) != classOf[Robot]) || m.getParameterTypes()(1) != classOf[Arguments]) { OpenComputers.log.severe("Invalid use of Callback annotation on %s.%s: invalid argument types or count.".format(m.getDeclaringClass.getName, m.getName)) } diff --git a/src/main/java/li/cil/oc/server/network/Connector.scala b/src/main/java/li/cil/oc/server/network/Connector.scala index a2abfbe7e..dfd94ccf0 100644 --- a/src/main/java/li/cil/oc/server/network/Connector.scala +++ b/src/main/java/li/cil/oc/server/network/Connector.scala @@ -113,7 +113,7 @@ trait Connector extends network.Connector with Node { override def load(nbt: NBTTagCompound) { super.load(nbt) - localBuffer = math.min(nbt.getDouble("buffer"), math.max(0, localBufferSize)) + localBuffer = nbt.getDouble("buffer") } override def save(nbt: NBTTagCompound) { diff --git a/src/main/resources/assets/opencomputers/lua/component/robot/lib/robot.lua b/src/main/resources/assets/opencomputers/lua/component/robot/lib/robot.lua index 16d66b1f5..7d760ad9d 100644 --- a/src/main/resources/assets/opencomputers/lua/component/robot/lib/robot.lua +++ b/src/main/resources/assets/opencomputers/lua/component/robot/lib/robot.lua @@ -1,185 +1,180 @@ local component = require("component") -local computer = require("computer") local sides = require("sides") -if not computer.isRobot() then - error("not a robot") -end - local robot = {} ------------------------------------------------------------------------------- -- General function robot.level() - return component.computer.level() + return component.robot.level() end ------------------------------------------------------------------------------- -- World function robot.detect() - return component.computer.detect(sides.front) + return component.robot.detect(sides.front) end function robot.detectUp() - return component.computer.detect(sides.up) + return component.robot.detect(sides.up) end function robot.detectDown() - return component.computer.detect(sides.down) + return component.robot.detect(sides.down) end ------------------------------------------------------------------------------- -- Inventory function robot.select(slot) - return component.computer.select(slot) + return component.robot.select(slot) end function robot.count(slot) - return component.computer.count(slot) + return component.robot.count(slot) end function robot.space(slot) - return component.computer.space(slot) + return component.robot.space(slot) end function robot.compareTo(slot) - return component.computer.compareTo(slot) + return component.robot.compareTo(slot) end function robot.transferTo(slot, count) - return component.computer.transferTo(slot, count) + return component.robot.transferTo(slot, count) end ------------------------------------------------------------------------------- -- Inventory + World function robot.compare() - return component.computer.compare(sides.front) + return component.robot.compare(sides.front) end function robot.compareUp() - return component.computer.compare(sides.up) + return component.robot.compare(sides.up) end function robot.compareDown() - return component.computer.compare(sides.down) + return component.robot.compare(sides.down) end function robot.drop(count) checkArg(1, count, "nil", "number") - return component.computer.drop(sides.front, count) + return component.robot.drop(sides.front, count) end function robot.dropUp(count) checkArg(1, count, "nil", "number") - return component.computer.drop(sides.up, count) + return component.robot.drop(sides.up, count) end function robot.dropDown(count) checkArg(1, count, "nil", "number") - return component.computer.drop(sides.down, count) + return component.robot.drop(sides.down, count) end function robot.place(side, sneaky) checkArg(1, side, "nil", "number") - return component.computer.place(sides.front, side, sneaky ~= nil and sneaky ~= false) + return component.robot.place(sides.front, side, sneaky ~= nil and sneaky ~= false) end function robot.placeUp(side, sneaky) checkArg(1, side, "nil", "number") - return component.computer.place(sides.up, side, sneaky ~= nil and sneaky ~= false) + return component.robot.place(sides.up, side, sneaky ~= nil and sneaky ~= false) end function robot.placeDown(side, sneaky) checkArg(1, side, "nil", "number") - return component.computer.place(sides.down, side, sneaky ~= nil and sneaky ~= false) + return component.robot.place(sides.down, side, sneaky ~= nil and sneaky ~= false) end function robot.suck(count) checkArg(1, count, "nil", "number") - return component.computer.suck(sides.front, count) + return component.robot.suck(sides.front, count) end function robot.suckUp(count) checkArg(1, count, "nil", "number") - return component.computer.suck(sides.up, count) + return component.robot.suck(sides.up, count) end function robot.suckDown(count) checkArg(1, count, "nil", "number") - return component.computer.suck(sides.down, count) + return component.robot.suck(sides.down, count) end ------------------------------------------------------------------------------- -- Tool function robot.durability() - return component.computer.durability() + return component.robot.durability() end function robot.swing(side, sneaky) checkArg(1, side, "nil", "number") - return component.computer.swing(sides.front, side, sneaky ~= nil and sneaky ~= false) + return component.robot.swing(sides.front, side, sneaky ~= nil and sneaky ~= false) end function robot.swingUp(side, sneaky) checkArg(1, side, "nil", "number") - return component.computer.swing(sides.up, side, sneaky ~= nil and sneaky ~= false) + return component.robot.swing(sides.up, side, sneaky ~= nil and sneaky ~= false) end function robot.swingDown(side, sneaky) checkArg(1, side, "nil", "number") - return component.computer.swing(sides.down, side, sneaky ~= nil and sneaky ~= false) + return component.robot.swing(sides.down, side, sneaky ~= nil and sneaky ~= false) end function robot.use(side, sneaky, duration) checkArg(1, side, "nil", "number") checkArg(3, duration, "nil", "number") - return component.computer.use(sides.front, side, sneaky ~= nil and sneaky ~= false, duration) + return component.robot.use(sides.front, side, sneaky ~= nil and sneaky ~= false, duration) end function robot.useUp(side, sneaky, duration) checkArg(1, side, "nil", "number") checkArg(3, duration, "nil", "number") - return component.computer.use(sides.up, side, sneaky ~= nil and sneaky ~= false, duration) + return component.robot.use(sides.up, side, sneaky ~= nil and sneaky ~= false, duration) end function robot.useDown(side, sneaky, duration) checkArg(1, side, "nil", "number") checkArg(3, duration, "nil", "number") - return component.computer.use(sides.down, side, sneaky ~= nil and sneaky ~= false, duration) + return component.robot.use(sides.down, side, sneaky ~= nil and sneaky ~= false, duration) end ------------------------------------------------------------------------------- -- Movement function robot.forward() - return component.computer.move(sides.front) + return component.robot.move(sides.front) end function robot.back() - return component.computer.move(sides.back) + return component.robot.move(sides.back) end function robot.up() - return component.computer.move(sides.up) + return component.robot.move(sides.up) end function robot.down() - return component.computer.move(sides.down) + return component.robot.move(sides.down) end function robot.turnLeft() - return component.computer.turn(false) + return component.robot.turn(false) end function robot.turnRight() - return component.computer.turn(true) + return component.robot.turn(true) end function robot.turnAround()