cleaned up the robot implementation, removing some ugly cross-references, inheritance and dependencies, will require to be rebooted if they already loaded the robot module

This commit is contained in:
Florian Nücke 2014-03-05 00:44:55 +01:00
parent 28a12d08b6
commit c00233023b
19 changed files with 213 additions and 125 deletions

View File

@ -57,6 +57,22 @@ public interface Machine extends ManagedEnvironment, Context {
*/ */
int componentCount(); 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 * The address of the file system that holds the machine's file system for
* temporary files (tmpfs). This may return <tt>null</tt> if either the * temporary files (tmpfs). This may return <tt>null</tt> if either the
@ -203,11 +219,4 @@ public interface Machine extends ManagedEnvironment, Context {
* @return whether the player was removed from the user list. * @return whether the player was removed from the user list.
*/ */
boolean removeUser(String name); 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();
} }

View File

@ -0,0 +1,55 @@
package li.cil.oc.api.machine;
import net.minecraft.entity.player.EntityPlayer;
/**
* This interface allows interaction with robots.
* <p/>
* 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.
* <p/>
* 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.
* <p/>
* 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.
* <p/>
* If no upgrade is installed in the robot this does nothing.
* <p/>
* 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.
* <p/>
* 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();
}

View File

@ -1,7 +1,15 @@
package li.cil.oc.api.network; package li.cil.oc.api.network;
import li.cil.oc.api.machine.Robot;
import net.minecraft.entity.player.EntityPlayer; 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
* <tt>(Robot)((Machine)context).owner()</tt>.
*/
@Deprecated
public interface RobotContext extends Context { public interface RobotContext extends Context {
/** /**
* Gets the index of the currently selected slot in the robot's inventory. * Gets the index of the currently selected slot in the robot's inventory.

View File

@ -37,5 +37,5 @@
@cpw.mods.fml.common.API( @cpw.mods.fml.common.API(
owner = "OpenComputers|Core", owner = "OpenComputers|Core",
provides = "OpenComputersAPI", provides = "OpenComputersAPI",
apiVersion = "1.4.1") apiVersion = "1.4.2")
package li.cil.oc.api; package li.cil.oc.api;

View File

@ -34,7 +34,7 @@ class Charger extends Environment with RedstoneAware with Analyzable {
val charge = Settings.get.chargeRate * chargeSpeed val charge = Settings.get.chargeRate * chargeSpeed
robots.collect { 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) { else if (chargeSpeed > 0 && world.getWorldInfo.getWorldTotalTime % 10 == 0) {

View File

@ -18,11 +18,11 @@ import stargatetech2.api.bus.IBusDevice
// See AbstractBusAware as to why we have to define the IBusDevice here. // See AbstractBusAware as to why we have to define the IBusDevice here.
@Optional.Interface(iface = "stargatetech2.api.bus.IBusDevice", modid = "StargateTech2") @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 { 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 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 override lazy val isClient = computer == null

View File

@ -24,8 +24,11 @@ import net.minecraftforge.common.ForgeDirection
// robot moves we only create a new proxy tile entity, hook the instance of this // 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 // 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. // 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) def this() = this(false)
if (isServer) {
computer.setCostPerTick(Settings.get.robotCost)
}
var proxy: RobotProxy = _ 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 val _buffer = new common.component.Buffer(this) {
override def maxResolution = (48, 14) override def maxResolution = (48, 14)
} }
override val _computer = if (isRemote) null else new robot.Robot(this) val (bot, gpu, keyboard) = if (isServer) {
val (gpu, keyboard) = if (isServer) { val bot = new robot.Robot(this)
val gpu = new GraphicsCard.Tier1 { val gpu = new GraphicsCard.Tier1 {
override val maxResolution = (48, 14) 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 && world.getBlockTileEntity(x, y, z) == proxy &&
p.getDistanceSq(x + 0.5, y + 0.5, z + 0.5) <= 64 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" 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 // 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) level = math.min((Math.pow(xp - Settings.get.baseXpToLevel, 1 / Settings.get.exponentialXpGrowth) / Settings.get.constantXpGrowth).toInt, 30)
if (isServer) { 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) { if (stack.hasTagCompound) {
xp = stack.getTagCompound.getDouble(Settings.namespace + "xp") xp = stack.getTagCompound.getDouble(Settings.namespace + "xp")
updateXpInfo() 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() { override def updateEntity() {
if (!addedToNetwork) { if (isServer && !addedToNetwork) {
addedToNetwork = true addedToNetwork = true
api.Network.joinNewNetwork(node) 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) { if (animationTicksLeft > 0) {
animationTicksLeft -= 1 animationTicksLeft -= 1
@ -287,8 +292,8 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w
super.updateEntity() super.updateEntity()
if (isServer) { if (isServer) {
gpu.update() gpu.update()
globalBuffer = node.globalBuffer globalBuffer = bot.node.globalBuffer
globalBufferSize = node.globalBufferSize globalBufferSize = bot.node.globalBufferSize
updatePowerInformation() updatePowerInformation()
if (xpChanged && world.getWorldInfo.getWorldTotalTime % 200 == 0) { if (xpChanged && world.getWorldInfo.getWorldTotalTime % 200 == 0) {
xpChanged = false xpChanged = false
@ -321,6 +326,7 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w
buffer.load(nbt.getCompoundTag(Settings.namespace + "buffer")) buffer.load(nbt.getCompoundTag(Settings.namespace + "buffer"))
gpu.load(nbt.getCompoundTag(Settings.namespace + "gpu")) gpu.load(nbt.getCompoundTag(Settings.namespace + "gpu"))
keyboard.load(nbt.getCompoundTag(Settings.namespace + "keyboard")) keyboard.load(nbt.getCompoundTag(Settings.namespace + "keyboard"))
bot.load(nbt.getCompoundTag(Settings.namespace + "robot"))
if (nbt.hasKey(Settings.namespace + "owner")) { if (nbt.hasKey(Settings.namespace + "owner")) {
owner = nbt.getString(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 + "buffer", buffer.save)
nbt.setNewCompoundTag(Settings.namespace + "gpu", gpu.save) nbt.setNewCompoundTag(Settings.namespace + "gpu", gpu.save)
nbt.setNewCompoundTag(Settings.namespace + "keyboard", keyboard.save) nbt.setNewCompoundTag(Settings.namespace + "keyboard", keyboard.save)
nbt.setNewCompoundTag(Settings.namespace + "robot", bot.save)
nbt.setString(Settings.namespace + "owner", owner) nbt.setString(Settings.namespace + "owner", owner)
nbt.setDouble(Settings.namespace + "xp", xp) nbt.setDouble(Settings.namespace + "xp", xp)
nbt.setInteger(Settings.namespace + "selectedSlot", selectedSlot) 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) { override def onMachineConnect(node: Node) {
super.onConnect(node) super.onConnect(node)
if (node == this.node) { if (node == this.node) {
node.connect(bot.node)
node.connect(buffer.node) node.connect(buffer.node)
node.connect(gpu.node) node.connect(gpu.node)
buffer.node.connect(keyboard.node) buffer.node.connect(keyboard.node)
@ -441,6 +449,7 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w
node.remove() node.remove()
gpu.node.remove() gpu.node.remove()
keyboard.node.remove() keyboard.node.remove()
bot.node.remove()
} }
} }

View File

@ -14,7 +14,7 @@ import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound import net.minecraft.nbt.NBTTagCompound
import net.minecraftforge.common.ForgeDirection 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)) 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). withComponent("robot", Visibility.Neighbors).
create() create()
override protected val _computer = null
override def computer = robot.computer override def computer = robot.computer
override def maxComponents = robot.maxComponents override def maxComponents = robot.maxComponents

View File

@ -2,25 +2,26 @@ package li.cil.oc.server.component
import cpw.mods.fml.common.registry.GameRegistry import cpw.mods.fml.common.registry.GameRegistry
import li.cil.oc.api.Network import li.cil.oc.api.Network
import li.cil.oc.api.machine.Robot
import li.cil.oc.api.network._ import li.cil.oc.api.network._
import net.minecraft.entity.player.EntityPlayer import net.minecraft.entity.player.EntityPlayer
import net.minecraft.inventory.{Container, InventoryCrafting} import net.minecraft.inventory.{Container, InventoryCrafting}
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraft.item.crafting.CraftingManager 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.common.MinecraftForge
import net.minecraftforge.event.entity.player.PlayerDestroyItemEvent import net.minecraftforge.event.entity.player.PlayerDestroyItemEvent
import scala.collection.mutable 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). val node = Network.newNode(this, Visibility.Network).
withComponent("crafting"). withComponent("crafting").
create() create()
@Callback(doc = """function([count:number]):number -- Tries to craft the specified number of items in the top left area of the inventory.""") @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 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 { private object CraftingInventory extends InventoryCrafting(new Container {
@ -28,15 +29,15 @@ class UpgradeCrafting(val owner: MCTileEntity) extends ManagedComponent {
}, 3, 3) { }, 3, 3) {
var amountPossible = 0 var amountPossible = 0
def craft(context: RobotContext, wantedCount: Int): Boolean = { def craft(wantedCount: Int): Boolean = {
load(context) load()
val manager = CraftingManager.getInstance val manager = CraftingManager.getInstance
val result = manager.findMatchingRecipe(CraftingInventory, owner.getWorldObj) val result = manager.findMatchingRecipe(CraftingInventory, owner.getWorldObj)
if (result == null) return false if (result == null) return false
val targetStackSize = if (result.isStackable) math.min(wantedCount, result.getMaxStackSize) else result.stackSize val targetStackSize = if (result.isStackable) math.min(wantedCount, result.getMaxStackSize) else result.stackSize
val timesCrafted = math.min(targetStackSize / result.stackSize, amountPossible) val timesCrafted = math.min(targetStackSize / result.stackSize, amountPossible)
if (timesCrafted <= 0) return true if (timesCrafted <= 0) return true
GameRegistry.onItemCrafted(context.player, result, this) GameRegistry.onItemCrafted(owner.player, result, this)
val surplus = mutable.ArrayBuffer.empty[ItemStack] val surplus = mutable.ArrayBuffer.empty[ItemStack]
for (slot <- 0 until getSizeInventory) { for (slot <- 0 until getSizeInventory) {
val stack = getStackInSlot(slot) val stack = getStackInSlot(slot)
@ -46,7 +47,7 @@ class UpgradeCrafting(val owner: MCTileEntity) extends ManagedComponent {
if (item.hasContainerItem) { if (item.hasContainerItem) {
val container = item.getContainerItemStack(stack) val container = item.getContainerItemStack(stack)
if (container.isItemStackDamageable && container.getItemDamage > container.getMaxDamage) { 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) { else if (container.getItem.doesContainerItemLeaveCraftingGrid(container) || getStackInSlot(slot) != null) {
surplus += container surplus += container
@ -58,9 +59,9 @@ class UpgradeCrafting(val owner: MCTileEntity) extends ManagedComponent {
} }
} }
} }
save(context) save()
result.stackSize *= timesCrafted result.stackSize *= timesCrafted
val inventory = context.player.inventory val inventory = owner.player.inventory
inventory.addItemStackToInventory(result) inventory.addItemStackToInventory(result)
for (stack <- surplus) { for (stack <- surplus) {
inventory.addItemStackToInventory(stack) inventory.addItemStackToInventory(stack)
@ -68,8 +69,8 @@ class UpgradeCrafting(val owner: MCTileEntity) extends ManagedComponent {
true true
} }
def load(context: RobotContext) { def load() {
val inventory = context.player.inventory val inventory = owner.player.inventory
amountPossible = Int.MaxValue amountPossible = Int.MaxValue
for (slot <- 0 until getSizeInventory) { for (slot <- 0 until getSizeInventory) {
val stack = inventory.getStackInSlot(toParentSlot(slot)) val stack = inventory.getStackInSlot(toParentSlot(slot))
@ -80,8 +81,8 @@ class UpgradeCrafting(val owner: MCTileEntity) extends ManagedComponent {
} }
} }
def save(context: RobotContext) { def save() {
val inventory = context.player.inventory val inventory = owner.player.inventory
for (slot <- 0 until getSizeInventory) { for (slot <- 0 until getSizeInventory) {
inventory.setInventorySlotContents(toParentSlot(slot), getStackInSlot(slot)) inventory.setInventorySlotContents(toParentSlot(slot), getStackInSlot(slot))
} }

View File

@ -1,6 +1,7 @@
package li.cil.oc.server.component package li.cil.oc.server.component
import li.cil.oc.api.Network import li.cil.oc.api.Network
import li.cil.oc.api.machine.Robot
import li.cil.oc.api.network._ import li.cil.oc.api.network._
import li.cil.oc.util.ExtendedNBT._ import li.cil.oc.util.ExtendedNBT._
import li.cil.oc.{OpenComputers, api, Settings} import li.cil.oc.{OpenComputers, api, Settings}
@ -9,7 +10,7 @@ import net.minecraft.item.ItemStack
import net.minecraft.nbt.NBTTagCompound import net.minecraft.nbt.NBTTagCompound
import net.minecraft.tileentity.{TileEntity, TileEntityFurnace} 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). val node = Network.newNode(this, Visibility.Network).
withComponent("generator", Visibility.Neighbors). withComponent("generator", Visibility.Neighbors).
withConnector(). 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.""") @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 count = if (args.count > 0) args.checkInteger(0) else 64
val player = context.player val player = owner.player
val stack = player.inventory.getStackInSlot(context.selectedSlot) val stack = player.inventory.getStackInSlot(owner.selectedSlot)
if (stack == null) return result(Unit, "selected slot is empty") if (stack == null) return result(Unit, "selected slot is empty")
if (!TileEntityFurnace.isItemFuel(stack)) { if (!TileEntityFurnace.isItemFuel(stack)) {
return result(Unit, "selected slot does not contain fuel") return result(Unit, "selected slot does not contain fuel")
@ -49,7 +50,7 @@ class UpgradeGenerator(val owner: TileEntity) extends ManagedComponent {
case _ => case _ =>
inventory = Some(stack.splitStack(math.min(stack.stackSize, count))) inventory = Some(stack.splitStack(math.min(stack.stackSize, count)))
} }
player.inventory.setInventorySlotContents(context.selectedSlot, stack) player.inventory.setInventorySlotContents(owner.selectedSlot, stack)
result(true) 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.""") @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 val count = if (args.count > 0) args.checkInteger(0) else Int.MaxValue
inventory match { inventory match {
case Some(stack) => case Some(stack) =>
val removedStack = stack.splitStack(math.min(count, stack.stackSize)) 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 stack.stackSize += removedStack.stackSize
if (success && stack.stackSize <= 0) { if (success && stack.stackSize <= 0) {
inventory = None inventory = None
@ -101,10 +102,7 @@ class UpgradeGenerator(val owner: TileEntity) extends ManagedComponent {
} }
} }
private def updateClient() = owner match { private def updateClient() = owner.saveUpgrade()
case robot: RobotContext => robot.saveUpgrade()
case _ =>
}
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //

View File

@ -248,7 +248,8 @@ class LuaJLuaArchitecture(machine: api.machine.Machine) extends LuaArchitecture(
}) })
// Are we a robot? (No this is not a CAPTCHA.) // 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)) computer.set("freeMemory", (_: Varargs) => LuaValue.valueOf(memory / 2))

View File

@ -24,7 +24,7 @@ import scala.collection.mutable
class Machine(val owner: Owner, constructor: Constructor[_ <: Architecture]) extends ManagedComponent with machine.Machine with Runnable { class Machine(val owner: Owner, constructor: Constructor[_ <: Architecture]) extends ManagedComponent with machine.Machine with Runnable {
val node = Network.newNode(this, Visibility.Network). val node = Network.newNode(this, Visibility.Network).
withComponent("computer", Visibility.Neighbors). withComponent("computer", Visibility.Neighbors).
withConnector(if (isRobot) Settings.get.bufferRobot + 30 * Settings.get.bufferPerLevel else Settings.get.bufferComputer). withConnector(Settings.get.bufferComputer).
create() create()
val tmp = if (Settings.get.tmpSize > 0) { 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(). 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. 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 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 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 { def componentCount = _components.count {
case (_, name) => name != "filesystem" case (_, name) => name != "filesystem"
} + addedComponents.count(_.name != "filesystem") - 1 // -1 = this computer } + 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 override def address = node.address

View File

@ -295,8 +295,9 @@ class NativeLuaArchitecture(machine: api.machine.Machine) extends LuaArchitectur
lua.setField(-2, "address") lua.setField(-2, "address")
// Are we a robot? (No this is not a CAPTCHA.) // Are we a robot? (No this is not a CAPTCHA.)
// TODO deprecate this
lua.pushScalaFunction(lua => { lua.pushScalaFunction(lua => {
lua.pushBoolean(machine.isRobot) lua.pushBoolean(machine.components.contains("robot"))
1 1
}) })
lua.setField(-2, "isRobot") lua.setField(-2, "isRobot")

View File

@ -368,7 +368,7 @@ class Player(val robot: tileentity.Robot) extends EntityPlayer(robot.world, Sett
override def addExhaustion(amount: Float) { override def addExhaustion(amount: Float) {
if (Settings.get.robotExhaustionCost > 0) { 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) robot.addXp(Settings.get.robotExhaustionXpRate * amount)
} }

View File

@ -3,7 +3,7 @@ package li.cil.oc.server.component.robot
import li.cil.oc.api import li.cil.oc.api
import li.cil.oc.api.network._ import li.cil.oc.api.network._
import li.cil.oc.common.tileentity 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.server.{PacketSender => ServerPacketSender}
import li.cil.oc.util.ExtendedNBT._ import li.cil.oc.util.ExtendedNBT._
import li.cil.oc.{OpenComputers, Settings} import li.cil.oc.{OpenComputers, Settings}
@ -19,8 +19,12 @@ import net.minecraftforge.common.ForgeDirection
import net.minecraftforge.fluids.FluidRegistry import net.minecraftforge.fluids.FluidRegistry
import scala.collection.convert.WrapAsScala._ 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 ManagedComponent {
class Robot(val robot: tileentity.Robot) extends Machine(robot, api.Machine.LuaArchitecture.getConstructor(classOf[api.machine.Machine])) with RobotContext { 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 actualSlot(n: Int) = robot.actualSlot(n)
def world = robot.world 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. val romRobot = Option(api.FileSystem.asManagedEnvironment(api.FileSystem.
fromClass(OpenComputers.getClass, Settings.resourceDomain, "lua/component/robot"), "robot")) fromClass(OpenComputers.getClass, Settings.resourceDomain, "lua/component/robot"), "robot"))
override def isRobot = true
def selectedSlot = robot.selectedSlot def selectedSlot = robot.selectedSlot
def player = robot.player() def player = robot.player()
@ -501,7 +503,7 @@ class Robot(val robot: tileentity.Robot) extends Machine(robot, api.Machine.LuaA
result(Unit, what) result(Unit, what)
} }
else { else {
if (!robot.node.tryChangeBuffer(-Settings.get.robotMoveCost)) { if (!node.tryChangeBuffer(-Settings.get.robotMoveCost)) {
result(Unit, "not enough energy") result(Unit, "not enough energy")
} }
else if (robot.move(direction)) { else if (robot.move(direction)) {
@ -510,7 +512,7 @@ class Robot(val robot: tileentity.Robot) extends Machine(robot, api.Machine.LuaA
result(true) result(true)
} }
else { else {
robot.node.changeBuffer(Settings.get.robotMoveCost) node.changeBuffer(Settings.get.robotMoveCost)
result(Unit, "impossible move") result(Unit, "impossible move")
} }
} }
@ -520,7 +522,7 @@ class Robot(val robot: tileentity.Robot) extends Machine(robot, api.Machine.LuaA
@Callback @Callback
def turn(context: Context, args: Arguments): Array[AnyRef] = { def turn(context: Context, args: Arguments): Array[AnyRef] = {
val clockwise = args.checkBoolean(0) val clockwise = args.checkBoolean(0)
if (robot.node.tryChangeBuffer(-Settings.get.robotTurnCost)) { if (node.tryChangeBuffer(-Settings.get.robotTurnCost)) {
if (clockwise) robot.rotate(ForgeDirection.UP) if (clockwise) robot.rotate(ForgeDirection.UP)
else robot.rotate(ForgeDirection.DOWN) else robot.rotate(ForgeDirection.DOWN)
robot.animateTurn(clockwise, Settings.get.turnDelay) 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) { override def onConnect(node: Node) {
super.onConnect(node) super.onConnect(node)
if (node == this.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) { override def save(nbt: NBTTagCompound) {
super.save(nbt) super.save(nbt)
romRobot.foreach(rom => nbt.setNewCompoundTag("romRobot", rom.save)) romRobot.foreach(fs => nbt.setNewCompoundTag("romRobot", fs.save))
} }
// ----------------------------------------------------------------------- // // ----------------------------------------------------------------------- //

View File

@ -2,14 +2,19 @@ package li.cil.oc.server.driver.item
import li.cil.oc.Items import li.cil.oc.Items
import li.cil.oc.api.driver.Slot import li.cil.oc.api.driver.Slot
import li.cil.oc.api.machine.Robot
import li.cil.oc.server.component import li.cil.oc.server.component
import net.minecraft.item.ItemStack import net.minecraft.item.ItemStack
import net.minecraft.tileentity.{TileEntity => MCTileEntity} import net.minecraft.tileentity.TileEntity
object UpgradeCrafting extends Item { object UpgradeCrafting extends Item {
override def worksWith(stack: ItemStack) = isOneOf(stack, Items.upgradeCrafting) 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 override def slot(stack: ItemStack) = Slot.Upgrade
} }

View File

@ -4,6 +4,7 @@ import cpw.mods.fml.common.FMLCommonHandler
import cpw.mods.fml.relauncher.Side import cpw.mods.fml.relauncher.Side
import java.lang.reflect.{Modifier, Method, InvocationTargetException} import java.lang.reflect.{Modifier, Method, InvocationTargetException}
import li.cil.oc.OpenComputers import li.cil.oc.OpenComputers
import li.cil.oc.api.machine.Robot
import li.cil.oc.api.network import li.cil.oc.api.network
import li.cil.oc.api.network.{Node => ImmutableNode, _} import li.cil.oc.api.network.{Node => ImmutableNode, _}
import li.cil.oc.server.component.machine.Machine import li.cil.oc.server.component.machine.Machine
@ -164,7 +165,7 @@ object Component {
ms.filter(_.isAnnotationPresent(classOf[network.Callback])).foreach(m => ms.filter(_.isAnnotationPresent(classOf[network.Callback])).foreach(m =>
if (m.getParameterTypes.size != 2 || 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]) { 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)) OpenComputers.log.severe("Invalid use of Callback annotation on %s.%s: invalid argument types or count.".format(m.getDeclaringClass.getName, m.getName))
} }

View File

@ -113,7 +113,7 @@ trait Connector extends network.Connector with Node {
override def load(nbt: NBTTagCompound) { override def load(nbt: NBTTagCompound) {
super.load(nbt) super.load(nbt)
localBuffer = math.min(nbt.getDouble("buffer"), math.max(0, localBufferSize)) localBuffer = nbt.getDouble("buffer")
} }
override def save(nbt: NBTTagCompound) { override def save(nbt: NBTTagCompound) {

View File

@ -1,185 +1,180 @@
local component = require("component") local component = require("component")
local computer = require("computer")
local sides = require("sides") local sides = require("sides")
if not computer.isRobot() then
error("not a robot")
end
local robot = {} local robot = {}
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-- General -- General
function robot.level() function robot.level()
return component.computer.level() return component.robot.level()
end end
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-- World -- World
function robot.detect() function robot.detect()
return component.computer.detect(sides.front) return component.robot.detect(sides.front)
end end
function robot.detectUp() function robot.detectUp()
return component.computer.detect(sides.up) return component.robot.detect(sides.up)
end end
function robot.detectDown() function robot.detectDown()
return component.computer.detect(sides.down) return component.robot.detect(sides.down)
end end
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-- Inventory -- Inventory
function robot.select(slot) function robot.select(slot)
return component.computer.select(slot) return component.robot.select(slot)
end end
function robot.count(slot) function robot.count(slot)
return component.computer.count(slot) return component.robot.count(slot)
end end
function robot.space(slot) function robot.space(slot)
return component.computer.space(slot) return component.robot.space(slot)
end end
function robot.compareTo(slot) function robot.compareTo(slot)
return component.computer.compareTo(slot) return component.robot.compareTo(slot)
end end
function robot.transferTo(slot, count) function robot.transferTo(slot, count)
return component.computer.transferTo(slot, count) return component.robot.transferTo(slot, count)
end end
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-- Inventory + World -- Inventory + World
function robot.compare() function robot.compare()
return component.computer.compare(sides.front) return component.robot.compare(sides.front)
end end
function robot.compareUp() function robot.compareUp()
return component.computer.compare(sides.up) return component.robot.compare(sides.up)
end end
function robot.compareDown() function robot.compareDown()
return component.computer.compare(sides.down) return component.robot.compare(sides.down)
end end
function robot.drop(count) function robot.drop(count)
checkArg(1, count, "nil", "number") checkArg(1, count, "nil", "number")
return component.computer.drop(sides.front, count) return component.robot.drop(sides.front, count)
end end
function robot.dropUp(count) function robot.dropUp(count)
checkArg(1, count, "nil", "number") checkArg(1, count, "nil", "number")
return component.computer.drop(sides.up, count) return component.robot.drop(sides.up, count)
end end
function robot.dropDown(count) function robot.dropDown(count)
checkArg(1, count, "nil", "number") checkArg(1, count, "nil", "number")
return component.computer.drop(sides.down, count) return component.robot.drop(sides.down, count)
end end
function robot.place(side, sneaky) function robot.place(side, sneaky)
checkArg(1, side, "nil", "number") 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 end
function robot.placeUp(side, sneaky) function robot.placeUp(side, sneaky)
checkArg(1, side, "nil", "number") 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 end
function robot.placeDown(side, sneaky) function robot.placeDown(side, sneaky)
checkArg(1, side, "nil", "number") 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 end
function robot.suck(count) function robot.suck(count)
checkArg(1, count, "nil", "number") checkArg(1, count, "nil", "number")
return component.computer.suck(sides.front, count) return component.robot.suck(sides.front, count)
end end
function robot.suckUp(count) function robot.suckUp(count)
checkArg(1, count, "nil", "number") checkArg(1, count, "nil", "number")
return component.computer.suck(sides.up, count) return component.robot.suck(sides.up, count)
end end
function robot.suckDown(count) function robot.suckDown(count)
checkArg(1, count, "nil", "number") checkArg(1, count, "nil", "number")
return component.computer.suck(sides.down, count) return component.robot.suck(sides.down, count)
end end
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-- Tool -- Tool
function robot.durability() function robot.durability()
return component.computer.durability() return component.robot.durability()
end end
function robot.swing(side, sneaky) function robot.swing(side, sneaky)
checkArg(1, side, "nil", "number") 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 end
function robot.swingUp(side, sneaky) function robot.swingUp(side, sneaky)
checkArg(1, side, "nil", "number") 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 end
function robot.swingDown(side, sneaky) function robot.swingDown(side, sneaky)
checkArg(1, side, "nil", "number") 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 end
function robot.use(side, sneaky, duration) function robot.use(side, sneaky, duration)
checkArg(1, side, "nil", "number") checkArg(1, side, "nil", "number")
checkArg(3, duration, "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 end
function robot.useUp(side, sneaky, duration) function robot.useUp(side, sneaky, duration)
checkArg(1, side, "nil", "number") checkArg(1, side, "nil", "number")
checkArg(3, duration, "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 end
function robot.useDown(side, sneaky, duration) function robot.useDown(side, sneaky, duration)
checkArg(1, side, "nil", "number") checkArg(1, side, "nil", "number")
checkArg(3, duration, "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 end
------------------------------------------------------------------------------- -------------------------------------------------------------------------------
-- Movement -- Movement
function robot.forward() function robot.forward()
return component.computer.move(sides.front) return component.robot.move(sides.front)
end end
function robot.back() function robot.back()
return component.computer.move(sides.back) return component.robot.move(sides.back)
end end
function robot.up() function robot.up()
return component.computer.move(sides.up) return component.robot.move(sides.up)
end end
function robot.down() function robot.down()
return component.computer.move(sides.down) return component.robot.move(sides.down)
end end
function robot.turnLeft() function robot.turnLeft()
return component.computer.turn(false) return component.robot.turn(false)
end end
function robot.turnRight() function robot.turnRight()
return component.computer.turn(true) return component.robot.turn(true)
end end
function robot.turnAround() function robot.turnAround()