diff --git a/assets/opencomputers/lua/rom/bin/dig.lua b/assets/opencomputers/lua/rom/bin/dig.lua new file mode 100644 index 000000000..f681b4264 --- /dev/null +++ b/assets/opencomputers/lua/rom/bin/dig.lua @@ -0,0 +1,214 @@ +if not robot then + error("can only run on robots", 0) +end + +local args, options = shell.parse(...) +if #args < 1 then + print("Usage: dig [-s] ") + print(" -s: shutdown when done.") + return +end + +local size = tonumber(args[1]) +if not size then + error("invalid size", 0) +end + +local r = component.computer +local x, y, z, f = 0, 0, 0, 0 +local delta = {[0] = function() x = x + 1 end, [1] = function() y = y + 1 end, + [2] = function() x = x - 1 end, [3] = function() y = y - 1 end} + +local function turnRight() + robot.turnRight() + f = (f + 1) % 4 +end + +local function turnLeft() + robot.turnLeft() + f = (f - 1) % 4 +end + +local function turnTowards(side) + if f == side - 1 then + turnRight() + else + while f ~= side do + turnLeft() + end + end +end + +local checkedDrop -- forward declaration + +local function clearBlock(side, cannotRetry) + while r.suck(side) do + checkedDrop() + end + local result, reason = r.swing(side) + if result then + checkedDrop() + else + local _, what = r.detect(side) + if cannotRetry and what ~= "air" and what ~= "entity" then + return false + end + end + return true +end + +local function tryMove(side) + side = side or sides.forward + local tries = 10 + while not r.move(side) do + tries = tries - 1 + if not clearBlock(side, tries < 1) then + return false + end + end + if side == sides.down then + z = z + 1 + elseif side == sides.up then + z = z - 1 + else + delta[f]() + end + return true +end + +local function moveTo(tx, ty, tz, backwards) + local axes = { + function() + while z > tz do + tryMove(sides.up) + end + while z < tz do + tryMove(sides.down) + end + end, + function() + if y > ty then + turnTowards(3) + repeat tryMove() until y == ty + elseif y < ty then + turnTowards(1) + repeat tryMove() until y == ty + end + end, + function() + if x > tx then + turnTowards(2) + repeat tryMove() until x == tx + elseif x < tx then + turnTowards(0) + repeat tryMove() until x == tx + end + end + } + if backwards then + for axis = 3, 1, -1 do + axes[axis]() + end + else + for axis = 1, 3 do + axes[axis]() + end + end +end + +function checkedDrop(force) + local empty = 0 + for slot = 1, 16 do + if robot.count(slot) == 0 then + empty = empty + 1 + end + end + if empty == 0 or force and empty < 16 then + local ox, oy, oz, of = x, y, z, f + moveTo(0, 0, 0) + turnTowards(2) + for slot = 1, 16 do + if robot.count(slot) > 0 then + robot.select(slot) + repeat robot.drop() until robot.count(slot) == 0 + end + end + robot.select(1) + moveTo(ox, oy, oz, true) + turnTowards(of) + end +end + +local function step() + clearBlock(sides.down) + if not tryMove() then + return false + end + clearBlock(sides.up) + return true +end + +local function turn(i) + if i % 2 == 1 then + turnRight() + else + turnLeft() + end +end + +local function digLayer() + --[[ We move in zig-zag lines, clearing three layers at a time. This means we + have to differentiate at the end of the last line between even and odd + sizes on which way to face for the next layer: + For either size we rotate once to the right. For even sizes this will + cause the next layer to be dug out rotated by ninety degrees. For odd + ones the return path is symmetrical, meaning we just turn around. + + Examples for two layers: + + s--x--x e--x--x s--x--x--x x--x x--x + | | | | | | | + x--x--x -> x--x--x x--x--x--x x x x x + | | | -> | | | | + x--x--e x--x--s x--x--x--x x x x x + | | | | | + e--x--x--x s x--x e + + Legend: s = start, x = a position, e = end, - = a move + ]] + for i = 1, size do + for j = 1, size - 1 do + if not step() then + return false + end + end + if i < size then + -- End of a normal line, move the "cap". + turn(i) + if not step() then + return false + end + turn(i) + else + turnRight() + if size % 2 == 1 then + turnRight() + end + for i = 1, 3 do + if not tryMove(sides.down) then + return false + end + end + end + end + return true +end + +repeat until not digLayer() +moveTo(0, 0, 0) +turnTowards(0) +checkedDrop(true) + +if options.s then + os.shutdown() +end \ No newline at end of file diff --git a/assets/opencomputers/lua/rom/lib/robot.lua b/assets/opencomputers/lua/rom/lib/robot.lua index 88138390f..60b27c5a0 100644 --- a/assets/opencomputers/lua/rom/lib/robot.lua +++ b/assets/opencomputers/lua/rom/lib/robot.lua @@ -22,24 +22,24 @@ end ------------------------------------------------------------------------------- -- Inventory -function robot.select(index) - return component.computer.select(index) +function robot.select(slot) + return component.computer.select(slot) end -function robot.count() - return component.computer.count() +function robot.count(slot) + return component.computer.count(slot) end -function robot.space() - return component.computer.select() +function robot.space(slot) + return component.computer.space(slot) end -function robot.compareTo(index) - return component.computer.compareTo(index) +function robot.compareTo(slot) + return component.computer.compareTo(slot) end -function robot.transferTo(index, count) - return component.computer.transferTo(index, count) +function robot.transferTo(slot, count) + return component.computer.transferTo(slot, count) end ------------------------------------------------------------------------------- diff --git a/assets/opencomputers/lua/rom/lib/sides.lua b/assets/opencomputers/lua/rom/lib/sides.lua index 850b8b1b1..5749f58c5 100644 --- a/assets/opencomputers/lua/rom/lib/sides.lua +++ b/assets/opencomputers/lua/rom/lib/sides.lua @@ -25,7 +25,9 @@ local sides = { negz = 2, posz = 3, negx = 4, - posx = 5 + posx = 5, + + forward = 3 } ------------------------------------------------------------------------------- diff --git a/li/cil/oc/Recipes.scala b/li/cil/oc/Recipes.scala index 8b5b93eaf..d3e34af6a 100644 --- a/li/cil/oc/Recipes.scala +++ b/li/cil/oc/Recipes.scala @@ -16,7 +16,6 @@ object Recipes { val craftingTable = new ItemStack(Block.workbench) val diamond = new ItemStack(Item.diamond) val dispenser = new ItemStack(Block.dispenser) - val dropper = new ItemStack(Block.dropper) val emerald = new ItemStack(Item.emerald) val enderPearl = new ItemStack(Item.enderPearl) val glass = new ItemStack(Block.glass) @@ -461,11 +460,11 @@ object Recipes { 'b', pcb) addRecipe(Items.crafting.createItemStack(), - "idi", + "ipi", "cwc", "ibi", 'i', ironIngot, - 'd', dropper, + 'p', piston, 'c', chip1, 'w', craftingTable, 'b', pcb) diff --git a/li/cil/oc/api/network/RobotContext.java b/li/cil/oc/api/network/RobotContext.java index 3d46f1a31..6289d1247 100644 --- a/li/cil/oc/api/network/RobotContext.java +++ b/li/cil/oc/api/network/RobotContext.java @@ -18,6 +18,11 @@ public interface RobotContext extends Context { * 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. */ diff --git a/li/cil/oc/api/package-info.java b/li/cil/oc/api/package-info.java index 3a9922c64..5d3e6afc1 100644 --- a/li/cil/oc/api/package-info.java +++ b/li/cil/oc/api/package-info.java @@ -3,7 +3,7 @@ *

* There are several parts to this API: *

- *
The {@link Driver} API
+ *
The {@link li.cil.oc.api.Driver} API
*
* This API is used to provide glue code to the mod that allows it to interact * with foreign objects. You need a driver if you wish to connect some object @@ -17,13 +17,13 @@ * {@link li.cil.oc.api.network.Environment}. For items that should be installed * in a computer, however, you will always have to provide a driver. *
- *
The {@link FileSystem} API
+ *
The {@link li.cil.oc.api.FileSystem} API
*
* This API provides facilities that make it easier to create file systems that * can be interacted with from Lua programs via the file system driver that * comes with the mod. *
- *
The {@link Network} API
+ *
The {@link li.cil.oc.api.Network} API
*
* This API provides interfaces that allow interacting with the internal network * and creating nodes, components and power connectors for said network. If you diff --git a/li/cil/oc/common/tileentity/Inventory.scala b/li/cil/oc/common/tileentity/Inventory.scala index f261563db..b139c663d 100644 --- a/li/cil/oc/common/tileentity/Inventory.scala +++ b/li/cil/oc/common/tileentity/Inventory.scala @@ -119,11 +119,10 @@ trait Inventory extends TileEntity with IInventory with Persistable { items.zipWithIndex collect { case (Some(stack), slot) => (stack, slot) } map { - case (stack, slot) => { + case (stack, slot) => val slotNbt = new NBTTagCompound() slotNbt.setByte("slot", slot.toByte) slotNbt.setNewCompoundTag("item", stack.writeToNBT) - } }) } diff --git a/li/cil/oc/server/component/Computer.scala b/li/cil/oc/server/component/Computer.scala index e316358c3..5b6121632 100644 --- a/li/cil/oc/server/component/Computer.scala +++ b/li/cil/oc/server/component/Computer.scala @@ -260,9 +260,8 @@ class Computer(val owner: tileentity.Computer) extends ManagedComponent with Con node.sendToReachable("computer.stopped") start() // Resume from pauses based on sleep or signal underflow. - case Computer.State.Sleeping if lastUpdate >= sleepUntil || !signals.isEmpty => { + case Computer.State.Sleeping if lastUpdate >= sleepUntil || !signals.isEmpty => switchTo(Computer.State.Yielded) - } // Resume in case we paused because the game was paused. case Computer.State.Paused => if (remainingPause > 0) { @@ -274,7 +273,7 @@ class Computer(val owner: tileentity.Computer) extends ManagedComponent with Con switchTo(state.top) // Trigger execution if necessary. } // Perform a synchronized call (message sending). - case Computer.State.SynchronizedCall => { + case Computer.State.SynchronizedCall => // These three asserts are all guaranteed by run(). assert(lua.getTop == 2) assert(lua.isThread(1)) @@ -317,7 +316,6 @@ class Computer(val owner: tileentity.Computer) extends ManagedComponent with Con OpenComputers.log.log(Level.WARNING, "Faulty Lua implementation for synchronized calls.", e) crash("protocol error") } - } case _ => // Nothing special to do, just avoid match errors. }) @@ -496,10 +494,9 @@ class Computer(val owner: tileentity.Computer) extends ManagedComponent with Con // Delay execution for a second to allow the world around us to settle. pause(Settings.get.startupDelay) } catch { - case e: LuaRuntimeException => { + case e: LuaRuntimeException => OpenComputers.log.warning("Could not unpersist computer.\n" + e.toString + "\tat " + e.getLuaStackTrace.mkString("\n\tat ")) state.push(Computer.State.Stopping) - } } } else close() // Clean up in case we got a weird state stack. @@ -571,10 +568,9 @@ class Computer(val owner: tileentity.Computer) extends ManagedComponent with Con nbt.setInteger("remainingPause", remainingPause) message.foreach(nbt.setString("message", _)) } catch { - case e: LuaRuntimeException => { + case e: LuaRuntimeException => OpenComputers.log.warning("Could not persist computer.\n" + e.toString + "\tat " + e.getLuaStackTrace.mkString("\n\tat ")) nbt.removeTag("state") - } } // Limit memory again. @@ -639,16 +635,14 @@ class Computer(val owner: tileentity.Computer) extends ManagedComponent with Con lua.newTable() var count = 0 value.foreach { - case (x, index) => { - x match { - case (entry: ScalaNumber) => - pushResult(lua, entry.underlying()) - case (entry) => - pushResult(lua, entry.asInstanceOf[AnyRef]) - } + case (x, index) => x match { + case (entry: ScalaNumber) => + pushResult(lua, entry.underlying()) + case (entry) => + pushResult(lua, entry.asInstanceOf[AnyRef]) + } lua.rawSet(-2, index + 1) count = count + 1 - } } lua.pushString("n") lua.pushInteger(count) @@ -1045,10 +1039,9 @@ class Computer(val owner: tileentity.Computer) extends ManagedComponent with Con return true } catch { - case ex: Throwable => { + case ex: Throwable => OpenComputers.log.log(Level.WARNING, "Failed initializing computer.", ex) close() - } } false } diff --git a/li/cil/oc/server/component/Filesystem.scala b/li/cil/oc/server/component/Filesystem.scala index c0f2c8fb6..a809c8e39 100644 --- a/li/cil/oc/server/component/Filesystem.scala +++ b/li/cil/oc/server/component/Filesystem.scala @@ -196,13 +196,12 @@ class FileSystem(val fileSystem: api.fs.FileSystem, var label: Label) extends Ma message.data match { case Array() if message.name == "computer.stopped" || message.name == "computer.started" => owners.get(message.source.address) match { - case Some(set) => { + case Some(set) => set.foreach(handle => Option(fileSystem.getHandle(handle)) match { case Some(file) => file.close() case _ => // Invalid handle... huh. }) set.clear() - } case _ => // Computer had no open files. } case _ => diff --git a/li/cil/oc/server/component/GraphicsCard.scala b/li/cil/oc/server/component/GraphicsCard.scala index 55f5ba0c5..df022aa8e 100644 --- a/li/cil/oc/server/component/GraphicsCard.scala +++ b/li/cil/oc/server/component/GraphicsCard.scala @@ -50,7 +50,7 @@ abstract class GraphicsCard extends ManagedComponent { val address = args.checkString(0) node.network.node(address) match { case null => Array(Unit, "invalid address") - case node: Node if node.host.isInstanceOf[Buffer] => { + case node: Node if node.host.isInstanceOf[Buffer] => screenAddress = Option(address) screenInstance = Some(node.host.asInstanceOf[Buffer]) screen(s => { @@ -62,7 +62,6 @@ abstract class GraphicsCard extends ManagedComponent { s.background = 0x000000 result(true) }) - } case _ => Array(Unit, "not a screen") } } diff --git a/li/cil/oc/server/component/Robot.scala b/li/cil/oc/server/component/Robot.scala index f8c63de7e..cfbefd98e 100644 --- a/li/cil/oc/server/component/Robot.scala +++ b/li/cil/oc/server/component/Robot.scala @@ -10,7 +10,7 @@ import net.minecraft.entity.item.EntityItem import net.minecraft.entity.{EntityLivingBase, Entity} import net.minecraft.inventory.{IInventory, ISidedInventory} import net.minecraft.item.{ItemStack, ItemBlock} -import net.minecraft.util.{Vec3, MovingObjectPosition, EnumMovingObjectType} +import net.minecraft.util.{MovingObjectPosition, EnumMovingObjectType} import net.minecraftforge.common.ForgeDirection import net.minecraftforge.fluids.FluidRegistry import scala.Some @@ -50,19 +50,27 @@ class Robot(val robot: tileentity.Robot) extends Computer(robot) with RobotConte result(selectedSlot - actualSlot(0) + 1) } - @LuaCallback("count") - def count(context: Context, args: Arguments): Array[AnyRef] = - result(stackInSlot(selectedSlot) match { + @LuaCallback(value = "count", direct = true) + def count(context: Context, args: Arguments): Array[AnyRef] = { + val slot = + if (args.count > 0 && args.checkAny(0) != null) checkSlot(args, 0) + else selectedSlot + result(stackInSlot(slot) match { case Some(stack) => stack.stackSize case _ => 0 }) + } - @LuaCallback("space") - def space(context: Context, args: Arguments): Array[AnyRef] = - result(stackInSlot(selectedSlot) match { - case Some(stack) => robot.getInventoryStackLimit - stack.stackSize + @LuaCallback(value = "space", direct = true) + def space(context: Context, args: Arguments): Array[AnyRef] = { + val slot = + if (args.count > 0 && args.checkAny(0) != null) checkSlot(args, 0) + else selectedSlot + result(stackInSlot(slot) match { + case Some(stack) => (robot.getInventoryStackLimit min stack.getMaxStackSize) - stack.stackSize case _ => robot.getInventoryStackLimit }) + } @LuaCallback("compareTo") def compareTo(context: Context, args: Arguments): Array[AnyRef] = { @@ -480,23 +488,25 @@ class Robot(val robot: tileentity.Robot) extends Computer(robot) with RobotConte // ----------------------------------------------------------------------- // private def blockContent(side: ForgeDirection) = { - val (bx, by, bz) = (x + side.offsetX, y + side.offsetY, z + side.offsetZ) - val id = world.getBlockId(bx, by, bz) - val block = Block.blocksList(id) - if (id == 0 || block == null || block.isAirBlock(world, bx, by, bz)) { - player.closestEntity[Entity]() match { - case Some(entity) => (true, "entity") - case _ => (false, "air") - } - } - else if (FluidRegistry.lookupFluidForBlock(block) != null || block.isInstanceOf[BlockFluid]) { - (false, "liquid") - } - else if (block.isBlockReplaceable(world, bx, by, bz)) { - (false, "replaceable") - } - else { - (true, "solid") + player.closestEntity[EntityLivingBase](side) match { + case Some(entity) => + (true, "entity") + case _ => + val (bx, by, bz) = (x + side.offsetX, y + side.offsetY, z + side.offsetZ) + val id = world.getBlockId(bx, by, bz) + val block = Block.blocksList(id) + if (id == 0 || block == null || block.isAirBlock(world, bx, by, bz)) { + (false, "air") + } + else if (FluidRegistry.lookupFluidForBlock(block) != null || block.isInstanceOf[BlockFluid]) { + (false, "liquid") + } + else if (block.isBlockReplaceable(world, bx, by, bz)) { + (false, "replaceable") + } + else { + (true, "solid") + } } } diff --git a/li/cil/oc/server/network/Network.scala b/li/cil/oc/server/network/Network.scala index 50af5509c..eee34e731 100644 --- a/li/cil/oc/server/network/Network.scala +++ b/li/cil/oc/server/network/Network.scala @@ -72,21 +72,20 @@ private class Network private(private val data: mutable.Map[String, Network.Vert def oldNodeB = node(nodeB) oldNodeA.edges.find(_.isBetween(oldNodeA, oldNodeB)) match { - case Some(edge) => { + case Some(edge) => handleSplit(edge.remove()) if (edge.left.data.reachability == Visibility.Neighbors) edge.right.data.onDisconnect(edge.left.data) if (edge.right.data.reachability == Visibility.Neighbors) edge.left.data.onDisconnect(edge.right.data) true - } case _ => false // That connection doesn't exists. } } def remove(node: MutableNode) = { data.remove(node.address) match { - case Some(entry) => { + case Some(entry) => node.network = null val subGraphs = entry.remove() val targets = Iterable(node) ++ (entry.data.reachability match { @@ -97,7 +96,6 @@ private class Network private(private val data: mutable.Map[String, Network.Vert handleSplit(subGraphs) targets.foreach(_.asInstanceOf[MutableNode].onDisconnect(node)) true - } case _ => false } } diff --git a/li/cil/oc/util/LuaStateFactory.scala b/li/cil/oc/util/LuaStateFactory.scala index 2c3f0deb3..17513d946 100644 --- a/li/cil/oc/util/LuaStateFactory.scala +++ b/li/cil/oc/util/LuaStateFactory.scala @@ -165,17 +165,15 @@ object LuaStateFactory { state.pushScalaFunction(lua => { lua.getTop match { case 0 => lua.pushNumber(random.nextDouble()) - case 1 => { + case 1 => val u = lua.checkInteger(1) lua.checkArg(1, 1 < u, "interval is empty") lua.pushInteger(1 + random.nextInt(u)) - } - case 2 => { + case 2 => val l = lua.checkInteger(1) val u = lua.checkInteger(2) lua.checkArg(1, l < u, "interval is empty") lua.pushInteger(l + random.nextInt(u - (l - 1))) - } case _ => throw new IllegalArgumentException("wrong number of arguments") } 1 @@ -256,11 +254,10 @@ object LuaStateFactory { Some(state) } catch { - case ex: Throwable => { + case ex: Throwable => ex.printStackTrace() state.close() return None - } } } } \ No newline at end of file diff --git a/li/cil/oc/util/TextBuffer.scala b/li/cil/oc/util/TextBuffer.scala index 4f5e955f1..1fa783023 100644 --- a/li/cil/oc/util/TextBuffer.scala +++ b/li/cil/oc/util/TextBuffer.scala @@ -152,11 +152,10 @@ class TextBuffer(var width: Int, var height: Int, initialDepth: PackedColor.Dept val ol = buffer(oy) val oc = color(oy) for (nx <- dx0 to dx1 by sx) nx - tx match { - case ox if ox >= 0 && ox < width => { + case ox if ox >= 0 && ox < width => changed = changed || (nl(nx) != ol(ox)) || (nc(nx) != oc(ox)) nl(nx) = ol(ox) nc(nx) = oc(ox) - } case _ => /* Got no source column. */ } case _ => /* Got no source row. */ diff --git a/reference.conf b/reference.conf index 9be85c7fc..8a2044a8f 100644 --- a/reference.conf +++ b/reference.conf @@ -223,11 +223,11 @@ opencomputers { # The time in seconds to pause execution after an item was # successfully dropped from a robot's inventory. - drop: 0.1 + drop: 0.25 # The time in seconds to pause execution after a robot successfully # picked up an item after triggering a suck command. - suck: 0.1 + suck: 0.25 } }