From 14f47fd6374175eb657b8305bc5667d8b403818d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Thu, 5 Dec 2013 23:23:13 +0100 Subject: [PATCH] clearing robot afterimages in a scheduled block update, which should be a bit more stable... should. minecraft. whatever; catching error in analyzer if node has no address; added setting to allow robots to ignore cobwebs, the most stupid invention ever (hardness of four without tools? seriously?), defaults to on; fixed threading issue with setBlockBoundsBasedOnState, hopefully resolving robot suicides --- li/cil/oc/Settings.scala | 1 + li/cil/oc/common/block/Delegator.scala | 11 +++++++++-- li/cil/oc/common/block/RobotAfterimage.scala | 7 +++++++ li/cil/oc/common/item/Analyzer.scala | 4 +++- li/cil/oc/common/tileentity/Robot.scala | 18 ++++++++---------- li/cil/oc/server/component/robot/Player.scala | 8 ++++++-- reference.conf | 10 ++++++++++ 7 files changed, 44 insertions(+), 15 deletions(-) diff --git a/li/cil/oc/Settings.scala b/li/cil/oc/Settings.scala index 483ea6d34..01dd4c3a6 100644 --- a/li/cil/oc/Settings.scala +++ b/li/cil/oc/Settings.scala @@ -48,6 +48,7 @@ class Settings(config: Config) { val allowActivateBlocks = config.getBoolean("robot.allowActivateBlocks") val allowUseItemsWithDuration = config.getBoolean("robot.allowUseItemsWithDuration") val canAttackPlayers = config.getBoolean("robot.canAttackPlayers") + val screwCobwebs = config.getBoolean("robot.notAfraidOfSpiders") val swingRange = config.getDouble("robot.swingRange") val useAndPlaceRange = config.getDouble("robot.useAndPlaceRange") val itemDamageRate = config.getDouble("robot.itemDamageRate") max 0 min 1 diff --git a/li/cil/oc/common/block/Delegator.scala b/li/cil/oc/common/block/Delegator.scala index 584349ff4..379db686c 100644 --- a/li/cil/oc/common/block/Delegator.scala +++ b/li/cil/oc/common/block/Delegator.scala @@ -154,7 +154,13 @@ class Delegator[Child <: Delegate](id: Int) extends Block(id, Material.iron) { override def setBlockBoundsBasedOnState(world: IBlockAccess, x: Int, y: Int, z: Int) = subBlock(world, x, y, z) match { - case Some(subBlock) => subBlock.updateBounds(world, x, y, z) + // This function can mess things up badly in single player if not + // synchronized because it sets fields in an instance stored in the + // static block list... which is used by both server and client thread. + // The other place where this is locked is in collisionRayTrace below, + // which seems to be the only built-in function that *logically* depends + // on the state bounds (rest is rendering which is unimportant). + case Some(subBlock) => subBlock.synchronized(subBlock.updateBounds(world, x, y, z)) case _ => } @@ -166,7 +172,8 @@ class Delegator[Child <: Delegate](id: Int) extends Block(id, Material.iron) { override def collisionRayTrace(world: World, x: Int, y: Int, z: Int, origin: Vec3, direction: Vec3) = subBlock(world, x, y, z) match { - case Some(subBlock) => subBlock.intersect(world, x, y, z, origin, direction) + // See setBlockBoundsBasedOnState for info on the lock. + case Some(subBlock) => subBlock.synchronized(subBlock.intersect(world, x, y, z, origin, direction)) case _ => super.collisionRayTrace(world, x, y, z, origin, direction) } diff --git a/li/cil/oc/common/block/RobotAfterimage.scala b/li/cil/oc/common/block/RobotAfterimage.scala index 48606ba5d..5824db7fb 100644 --- a/li/cil/oc/common/block/RobotAfterimage.scala +++ b/li/cil/oc/common/block/RobotAfterimage.scala @@ -50,6 +50,13 @@ class RobotAfterimage(val parent: SpecialDelegator) extends SpecialDelegate { // ----------------------------------------------------------------------- // + override def update(world: World, x: Int, y: Int, z: Int) { + parent.subBlock(world, x, y, z) match { + case Some(_: RobotAfterimage) => world.setBlockToAir(x, y, z) + case _ => + } + } + override def removedByEntity(world: World, x: Int, y: Int, z: Int, player: EntityPlayer) = { super.removedFromWorld(world, x, y, z, blockId) findMovingRobot(world, x, y, z) match { diff --git a/li/cil/oc/common/item/Analyzer.scala b/li/cil/oc/common/item/Analyzer.scala index 21f9122c0..8c9d3e548 100644 --- a/li/cil/oc/common/item/Analyzer.scala +++ b/li/cil/oc/common/item/Analyzer.scala @@ -52,7 +52,9 @@ class Analyzer(val parent: Delegator) extends Delegate { case _ => } val address = node.address() - stats.setString(Settings.namespace + "gui.Analyzer.Address", address) + if (address != null && !address.isEmpty) { + stats.setString(Settings.namespace + "gui.Analyzer.Address", address) + } PacketSender.sendAnalyze(stats, address, player.asInstanceOf[Player]) } diff --git a/li/cil/oc/common/tileentity/Robot.scala b/li/cil/oc/common/tileentity/Robot.scala index 2bd462f3f..d04552667 100644 --- a/li/cil/oc/common/tileentity/Robot.scala +++ b/li/cil/oc/common/tileentity/Robot.scala @@ -138,8 +138,10 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w Blocks.robotAfterimage.setBlock(world, ox, oy, oz, 1) assert(Delegator.subBlock(world, ox, oy, oz).exists(_ == Blocks.robotAfterimage)) // Here instead of Lua callback so that it gets called on client, too. - animateMove(ox, oy, oz, Settings.get.moveDelay) + val moveTicks = (Settings.get.moveDelay * 20).toInt max 1 + setAnimateMove(ox, oy, oz, moveTicks) if (isServer) { + world.scheduleBlockUpdate(ox, oy, oz, Blocks.robotAfterimage.parent.blockID, moveTicks - 1) ServerPacketSender.sendRobotMove(this, ox, oy, oz, direction) checkRedstoneInputChanged() } @@ -190,9 +192,6 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w def isAnimatingTurn = animationTicksLeft > 0 && turnAxis != 0 - def animateMove(fromX: Int, fromY: Int, fromZ: Int, duration: Double) = - setAnimateMove(fromX, fromY, fromZ, (duration * 20).toInt) - def animateSwing(duration: Double) = { setAnimateSwing((duration * 20).toInt) ServerPacketSender.sendRobotAnimateSwing(this) @@ -248,12 +247,11 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w if (animationTicksLeft > 0) { animationTicksLeft -= 1 if (animationTicksLeft == 0) { - if (Blocks.blockSpecial.subBlock(world, moveFromX, moveFromY, moveFromZ).exists(_ == Blocks.robotAfterimage)) { - world.setBlock(moveFromX, moveFromY, moveFromZ, 0, 0, 1) - } - moveFromX = x - moveFromY = y - moveFromZ = z + moveFromX = Int.MaxValue + moveFromY = Int.MaxValue + moveFromZ = Int.MaxValue + swingingTool = false + turnAxis = 0 } } super.updateEntity() diff --git a/li/cil/oc/server/component/robot/Player.scala b/li/cil/oc/server/component/robot/Player.scala index 5f2f1defe..52b9fe965 100644 --- a/li/cil/oc/server/component/robot/Player.scala +++ b/li/cil/oc/server/component/robot/Player.scala @@ -222,7 +222,9 @@ class Player(val robot: Robot) extends EntityPlayer(robot.world, Settings.get.na return 0 } - if (!ForgeHooks.canHarvestBlock(block, this, metadata)) { + val cobwebOverride = block == Block.web && Settings.get.screwCobwebs + + if (!ForgeHooks.canHarvestBlock(block, this, metadata) && !cobwebOverride) { return 0 } @@ -235,7 +237,9 @@ class Player(val robot: Robot) extends EntityPlayer(robot.world, Settings.get.na val hardness = block.getBlockHardness(world, x, y, z) val strength = getCurrentPlayerStrVsBlock(block, false, metadata) - val breakTime = hardness * 1.5 / strength + val breakTime = + if (cobwebOverride) Settings.get.swingDelay + else hardness * 1.5 / strength if (stack != null) { val oldDamage = stack.getItemDamage diff --git a/reference.conf b/reference.conf index 5d94c128a..044fa2d58 100644 --- a/reference.conf +++ b/reference.conf @@ -149,6 +149,16 @@ opencomputers { # in the game. canAttackPlayers: false + # Determines whether robots are a pretty cool guy. Ususally cobwebs are + # the bane of anything using a tool other than a sword or shears. This is + # an utter pain in the part you sit on, because it makes robots meant to + # dig holes utterly useless: the poor things couldn't break cobwebs in + # mining shafts with their golden pick axes. So, if this setting is true, + # we check for cobweb and allow robots to break 'em anyway, no matter + # their current tool. After all, the hardness value of cobweb can only + # rationally explained by Steve's fear of spiders, anyway. + notAfraidOfSpiders: true + # The 'range' of robots when swinging an equipped tool (left click). This # is the distance to the center of block the robot swings the tool in to # the side the tool is swung towards. I.e. for the collision check, which