From 0d620a6ccf9b79592d6e5cba24b973b7dececd35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Thu, 26 Dec 2013 16:24:45 +0100 Subject: [PATCH 1/9] immediately printing error message to chat log of the player that tried to start the computer if it happens during startup; also printing message if there's no ram; immediately checking power when starting computer (otherwise it'd be first checked in the next update) --- li/cil/oc/server/PacketHandler.scala | 11 +++++++++- li/cil/oc/server/component/Computer.scala | 25 ++++++++++++++++++----- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/li/cil/oc/server/PacketHandler.scala b/li/cil/oc/server/PacketHandler.scala index d887d2fa7..340c2a25f 100644 --- a/li/cil/oc/server/PacketHandler.scala +++ b/li/cil/oc/server/PacketHandler.scala @@ -28,7 +28,16 @@ class PacketHandler extends CommonPacketHandler { case Some(t) => p.player match { case player: EntityPlayer if t.computer.canInteract(player.getCommandSenderName) => if (p.readBoolean()) { - if (!t.computer.isPaused) t.computer.start() + if (!t.computer.isPaused) { + t.computer.start() + t.computer.lastError match { + case Some(message) => p.player match { + case player: EntityPlayer => player.addChatMessage(message) + case _ => + } + case _ => + } + } } else t.computer.stop() case _ => diff --git a/li/cil/oc/server/component/Computer.scala b/li/cil/oc/server/component/Computer.scala index c819e246a..716836462 100644 --- a/li/cil/oc/server/component/Computer.scala +++ b/li/cil/oc/server/component/Computer.scala @@ -107,11 +107,25 @@ class Computer(val owner: tileentity.Computer) extends ManagedComponent with Con def isPaused = state.synchronized(state.top == Computer.State.Paused && remainingPause > 0) def start() = state.synchronized(state.top match { - case Computer.State.Stopped if owner.installedMemory > 0 && init() => - switchTo(Computer.State.Starting) - timeStarted = owner.world.getWorldTime - node.sendToReachable("computer.started") - true + case Computer.State.Stopped => + if (owner.installedMemory > 0) { + if (node.globalBuffer > cost) { + init() && { + switchTo(Computer.State.Starting) + timeStarted = owner.world.getWorldTime + node.sendToReachable("computer.started") + true + } + } + else { + message = Some("not enough energy") + false + } + } + else { + message = Some("no memory installed") + false + } case Computer.State.Paused if remainingPause > 0 => remainingPause = 0 true @@ -687,6 +701,7 @@ class Computer(val owner: tileentity.Computer) extends ManagedComponent with Con LuaStateFactory.createState() match { case None => lua = null + message = Some("native libraries not available") return false case Some(value) => lua = value } From 934e57901756828893b7681253f335f846a0a382 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Thu, 26 Dec 2013 17:01:05 +0100 Subject: [PATCH 2/9] added safety check to not trigger a new move while moving. shouldn't really happen, due to the execution delay / pause being applied when moving, but to be on the safe side... --- li/cil/oc/common/block/RobotProxy.scala | 6 +++-- li/cil/oc/server/component/Robot.scala | 29 +++++++++++++++---------- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/li/cil/oc/common/block/RobotProxy.scala b/li/cil/oc/common/block/RobotProxy.scala index 811a8ae98..0e2b6aa10 100644 --- a/li/cil/oc/common/block/RobotProxy.scala +++ b/li/cil/oc/common/block/RobotProxy.scala @@ -85,8 +85,10 @@ class RobotProxy(val parent: SpecialDelegator) extends RedstoneAware with Specia override def intersect(world: World, x: Int, y: Int, z: Int, origin: Vec3, direction: Vec3) = { val bounds = parent.getCollisionBoundingBoxFromPool(world, x, y, z) - if (bounds.isVecInside(origin)) null - else super.intersect(world, x, y, z, origin, direction) + world.getBlockTileEntity(x, y, z) match { + case proxy: tileentity.RobotProxy if proxy.robot.animationTicksLeft <= 0 && bounds.isVecInside(origin) => null + case _ => super.intersect(world, x, y, z, origin, direction) + } } override def updateBounds(world: IBlockAccess, x: Int, y: Int, z: Int) { diff --git a/li/cil/oc/server/component/Robot.scala b/li/cil/oc/server/component/Robot.scala index b307c7f2b..7dfbb523c 100644 --- a/li/cil/oc/server/component/Robot.scala +++ b/li/cil/oc/server/component/Robot.scala @@ -482,21 +482,28 @@ class Robot(val robot: tileentity.Robot) extends Computer(robot) with RobotConte @LuaCallback("move") def move(context: Context, args: Arguments): Array[AnyRef] = { val direction = checkSideForMovement(args, 0) - val (something, what) = blockContent(direction) - if (something) { - result(false, what) + if (robot.isAnimatingMove) { + // This shouldn't really happen due to delays being enforced, but just to + // be on the safe side... + result(false, "already moving") } else { - if (!robot.computer.node.tryChangeBuffer(-Settings.get.robotMoveCost)) { - result(false, "not enough energy") - } - else if (robot.move(direction)) { - context.pause(Settings.get.moveDelay) - result(true) + val (something, what) = blockContent(direction) + if (something) { + result(false, what) } else { - robot.computer.node.changeBuffer(Settings.get.robotMoveCost) - result(false, "impossible move") + if (!robot.computer.node.tryChangeBuffer(-Settings.get.robotMoveCost)) { + result(false, "not enough energy") + } + else if (robot.move(direction)) { + context.pause(Settings.get.moveDelay) + result(true) + } + else { + robot.computer.node.changeBuffer(Settings.get.robotMoveCost) + result(false, "impossible move") + } } } } From ccc2d6e27600361689e0ec7c8a9fcd8d8bcd0524 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Thu, 26 Dec 2013 17:40:59 +0100 Subject: [PATCH 3/9] also checking vanilla redstone wire in neighboring blocks even if doesn't connect directly (basically what BlockRedstoneLogic does) --- li/cil/oc/common/tileentity/RedstoneAware.scala | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/li/cil/oc/common/tileentity/RedstoneAware.scala b/li/cil/oc/common/tileentity/RedstoneAware.scala index a9f4ef825..1bc3cfe03 100644 --- a/li/cil/oc/common/tileentity/RedstoneAware.scala +++ b/li/cil/oc/common/tileentity/RedstoneAware.scala @@ -8,6 +8,7 @@ import li.cil.oc.api.network import li.cil.oc.server.{PacketSender => ServerPacketSender} import li.cil.oc.util.Persistable import mods.immibis.redlogic.api.wiring._ +import net.minecraft.block.Block import net.minecraft.nbt.NBTTagCompound import net.minecraftforge.common.ForgeDirection @@ -101,16 +102,12 @@ trait RedstoneAware extends RotationAware with network.Environment with Persista // ----------------------------------------------------------------------- // protected def computeInput(side: ForgeDirection) = { - val vanilla = world.getIndirectPowerLevelTo( - x + side.offsetX, - y + side.offsetY, - z + side.offsetZ, - side.ordinal()) + val (sx, sy, sz) = (x + side.offsetX, y + side.offsetY, z + side.offsetZ) + // See BlockRedstoneLogic.getInputStrength() for reference. + val vanilla = math.max(world.getIndirectPowerLevelTo(sx, sy, sz, side.ordinal()), + if (world.getBlockId(sx, sy, sz) == Block.redstoneWire.blockID) world.getBlockMetadata(sx, sy, sz) else 0) val redLogic = if (Loader.isModLoaded("RedLogic")) { - world.getBlockTileEntity( - x + side.offsetX, - y + side.offsetY, - z + side.offsetZ) match { + world.getBlockTileEntity(sx, sy, sz) match { case emitter: IRedstoneEmitter => var strength = 0 for (i <- -1 to 5) { From fb6f0a8866d060f059142f615153c8995385a51f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Thu, 26 Dec 2013 17:48:43 +0100 Subject: [PATCH 4/9] moved scheduling of robot afterimage removal into added callback of afterimage block, to be on the safe(r) side --- li/cil/oc/common/block/RobotAfterimage.scala | 4 ++++ li/cil/oc/common/tileentity/Robot.scala | 1 - 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/li/cil/oc/common/block/RobotAfterimage.scala b/li/cil/oc/common/block/RobotAfterimage.scala index 655434bf0..1e55a8ea9 100644 --- a/li/cil/oc/common/block/RobotAfterimage.scala +++ b/li/cil/oc/common/block/RobotAfterimage.scala @@ -50,6 +50,10 @@ class RobotAfterimage(val parent: SpecialDelegator) extends SpecialDelegate { // ----------------------------------------------------------------------- // + override def addedToWorld(world: World, x: Int, y: Int, z: Int) { + world.scheduleBlockUpdate(x, y, z, parent.blockID, math.max((Settings.get.moveDelay * 20).toInt, 1) - 1) + } + 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) diff --git a/li/cil/oc/common/tileentity/Robot.scala b/li/cil/oc/common/tileentity/Robot.scala index ac199972c..1b8060a3a 100644 --- a/li/cil/oc/common/tileentity/Robot.scala +++ b/li/cil/oc/common/tileentity/Robot.scala @@ -157,7 +157,6 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w val moveTicks = math.max((Settings.get.moveDelay * 20).toInt, 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() } From 55524c4a780adbaff8de22f3a0adb8ff79df8aae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Fri, 27 Dec 2013 00:18:22 +0100 Subject: [PATCH 5/9] catching error when creating lua state due to missing libraries in factory and logging it right there, to allow printing error to chat the first time, too; different name the lib is saved to the tmp folder to reduce the chance of collisions; explicit message for windows users reminding them to install the vc2012 runtimes on library load errors --- li/cil/oc/util/LuaStateFactory.scala | 279 ++++++++++++++------------- 1 file changed, 149 insertions(+), 130 deletions(-) diff --git a/li/cil/oc/util/LuaStateFactory.scala b/li/cil/oc/util/LuaStateFactory.scala index 934d638ce..9cbbe5865 100644 --- a/li/cil/oc/util/LuaStateFactory.scala +++ b/li/cil/oc/util/LuaStateFactory.scala @@ -5,6 +5,7 @@ import com.naef.jnlua.{LuaState, NativeSupport} import java.io.File import java.io.FileOutputStream import java.nio.channels.Channels +import java.util.logging.Level import li.cil.oc.server.component.Computer import li.cil.oc.util.ExtendedLuaState._ import li.cil.oc.{OpenComputers, Settings} @@ -27,6 +28,8 @@ object LuaStateFactory { /** Set to true in initialization code below if available. */ private var haveNativeLibrary = false + private var isWindows = false + private var _is64Bit = false def is64Bit = _is64Bit @@ -76,6 +79,7 @@ object LuaStateFactory { break() } } + isWindows = extension == ".dll" val libPath = "/assets/" + Settings.resourceDomain + "/lib/" val tmpPath = { @@ -92,7 +96,7 @@ object LuaStateFactory { } // Found file with proper extension. Create a temporary file. - val file = new File(tmpPath + library) + val file = new File(tmpPath + "OpenComputersMod-" + library) // Try to delete an old instance of the library, in case we have an update // and deleteOnExit fails (which it regularly does on Windows it seems). try { @@ -145,145 +149,160 @@ object LuaStateFactory { def createState(): Option[LuaState] = { if (!haveNativeLibrary) return None - val state = new LuaState(Int.MaxValue) try { - // Load all libraries. - state.openLib(LuaState.Library.BASE) - state.openLib(LuaState.Library.BIT32) - state.openLib(LuaState.Library.COROUTINE) - state.openLib(LuaState.Library.DEBUG) - state.openLib(LuaState.Library.ERIS) - state.openLib(LuaState.Library.MATH) - state.openLib(LuaState.Library.STRING) - state.openLib(LuaState.Library.TABLE) - state.pop(8) + val state = new LuaState(Int.MaxValue) + try { + // Load all libraries. + state.openLib(LuaState.Library.BASE) + state.openLib(LuaState.Library.BIT32) + state.openLib(LuaState.Library.COROUTINE) + state.openLib(LuaState.Library.DEBUG) + state.openLib(LuaState.Library.ERIS) + state.openLib(LuaState.Library.MATH) + state.openLib(LuaState.Library.STRING) + state.openLib(LuaState.Library.TABLE) + state.pop(8) - // Prepare table for os stuff. - state.newTable() - state.setGlobal("os") + // Prepare table for os stuff. + state.newTable() + state.setGlobal("os") - // Kill compat entries. - state.pushNil() - state.setGlobal("unpack") - state.pushNil() - state.setGlobal("loadstring") - state.getGlobal("math") - state.pushNil() - state.setField(-2, "log10") - state.pop(1) - state.getGlobal("table") - state.pushNil() - state.setField(-2, "maxn") - state.pop(1) + // Kill compat entries. + state.pushNil() + state.setGlobal("unpack") + state.pushNil() + state.setGlobal("loadstring") + state.getGlobal("math") + state.pushNil() + state.setField(-2, "log10") + state.pop(1) + state.getGlobal("table") + state.pushNil() + state.setField(-2, "maxn") + state.pop(1) - // Remove some other functions we don't need and are dangerous. - state.pushNil() - state.setGlobal("dofile") - state.pushNil() - state.setGlobal("loadfile") + // Remove some other functions we don't need and are dangerous. + state.pushNil() + state.setGlobal("dofile") + state.pushNil() + state.setGlobal("loadfile") - state.getGlobal("math") + state.getGlobal("math") - // We give each Lua state it's own randomizer, since otherwise they'd - // use the good old rand() from C. Which can be terrible, and isn't - // necessarily thread-safe. - val random = new Random - state.pushScalaFunction(lua => { - lua.getTop match { - case 0 => lua.pushNumber(random.nextDouble()) - case 1 => - val u = lua.checkInteger(1) - lua.checkArg(1, 1 < u, "interval is empty") - lua.pushInteger(1 + random.nextInt(u)) - 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 - }) - state.setField(-2, "random") - - state.pushScalaFunction(lua => { - random.setSeed(lua.checkInteger(1)) - 0 - }) - state.setField(-2, "randomseed") - - // Pop the math table. - state.pop(1) - - // Provide some better Unicode support. - state.newTable() - - // TODO find (probably not necessary?) - - // TODO format (probably not necessary?) - - // TODO gmatch (probably not necessary?) - - // TODO gsub (probably not necessary?) - - // TODO match (probably not necessary?) - - state.pushScalaFunction(lua => { - lua.pushString(lua.checkString(1).toLowerCase) - 1 - }) - state.setField(-2, "lower") - - state.pushScalaFunction(lua => { - lua.pushString(lua.checkString(1).toUpperCase) - 1 - }) - state.setField(-2, "upper") - - state.pushScalaFunction(lua => { - lua.pushString(String.valueOf((1 to lua.getTop).map(lua.checkInteger).map(_.toChar).toArray)) - 1 - }) - state.setField(-2, "char") - - state.pushScalaFunction(lua => { - lua.pushInteger(lua.checkString(1).length) - 1 - }) - state.setField(-2, "len") - - state.pushScalaFunction(lua => { - lua.pushString(lua.checkString(1).reverse) - 1 - }) - state.setField(-2, "reverse") - - state.pushScalaFunction(lua => { - val string = lua.checkString(1) - val start = math.max(0, lua.checkInteger(2) match { - case i if i < 0 => string.length + i - case i => i - 1 + // We give each Lua state it's own randomizer, since otherwise they'd + // use the good old rand() from C. Which can be terrible, and isn't + // necessarily thread-safe. + val random = new Random + state.pushScalaFunction(lua => { + lua.getTop match { + case 0 => lua.pushNumber(random.nextDouble()) + case 1 => + val u = lua.checkInteger(1) + lua.checkArg(1, 1 < u, "interval is empty") + lua.pushInteger(1 + random.nextInt(u)) + 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 }) - val end = - if (lua.getTop > 2) math.min(string.length, lua.checkInteger(3) match { - case i if i < 0 => string.length + i + 1 - case i => i + state.setField(-2, "random") + + state.pushScalaFunction(lua => { + random.setSeed(lua.checkInteger(1)) + 0 + }) + state.setField(-2, "randomseed") + + // Pop the math table. + state.pop(1) + + // Provide some better Unicode support. + state.newTable() + + // TODO find (probably not necessary?) + + // TODO format (probably not necessary?) + + // TODO gmatch (probably not necessary?) + + // TODO gsub (probably not necessary?) + + // TODO match (probably not necessary?) + + state.pushScalaFunction(lua => { + lua.pushString(lua.checkString(1).toLowerCase) + 1 + }) + state.setField(-2, "lower") + + state.pushScalaFunction(lua => { + lua.pushString(lua.checkString(1).toUpperCase) + 1 + }) + state.setField(-2, "upper") + + state.pushScalaFunction(lua => { + lua.pushString(String.valueOf((1 to lua.getTop).map(lua.checkInteger).map(_.toChar).toArray)) + 1 + }) + state.setField(-2, "char") + + state.pushScalaFunction(lua => { + lua.pushInteger(lua.checkString(1).length) + 1 + }) + state.setField(-2, "len") + + state.pushScalaFunction(lua => { + lua.pushString(lua.checkString(1).reverse) + 1 + }) + state.setField(-2, "reverse") + + state.pushScalaFunction(lua => { + val string = lua.checkString(1) + val start = math.max(0, lua.checkInteger(2) match { + case i if i < 0 => string.length + i + case i => i - 1 }) - else string.length - if (end <= start) lua.pushString("") - else lua.pushString(string.substring(start, end)) - 1 - }) - state.setField(-2, "sub") + val end = + if (lua.getTop > 2) math.min(string.length, lua.checkInteger(3) match { + case i if i < 0 => string.length + i + 1 + case i => i + }) + else string.length + if (end <= start) lua.pushString("") + else lua.pushString(string.substring(start, end)) + 1 + }) + state.setField(-2, "sub") - state.setGlobal("unicode") + state.setGlobal("unicode") - Some(state) - } catch { - case ex: Throwable => - ex.printStackTrace() - state.close() - return None + return Some(state) + } + catch { + case t: Throwable => + OpenComputers.log.log(Level.WARNING, "Failed creating Lua state.", t) + state.close() + } } + catch { + case _: UnsatisfiedLinkError => + OpenComputers.log.severe("Failed loading the native libraries.") + if (isWindows) { + OpenComputers.log.severe( + "Please ensure you have the Visual C++ 2012 Runtime installed " + + "(when on 64 Bit, both the 32 bit and 64 bit version of the " + + "runtime).") + } + case t: Throwable => + OpenComputers.log.log(Level.WARNING, "Failed creating Lua state.", t) + } + None } } \ No newline at end of file From ca52ec37a68fba67b2f34392be097f5cc2c320fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Fri, 27 Dec 2013 17:50:05 +0100 Subject: [PATCH 6/9] option for clients to select whether text on screens should be anti-aliased or not --- .../textures/font/chars_aliased.png | Bin 0 -> 3155 bytes li/cil/oc/Settings.scala | 1 + .../client/renderer/MonospaceFontRenderer.scala | 6 +++++- li/cil/oc/server/component/Computer.scala | 4 ++-- reference.conf | 4 ++++ 5 files changed, 12 insertions(+), 3 deletions(-) create mode 100644 assets/opencomputers/textures/font/chars_aliased.png diff --git a/assets/opencomputers/textures/font/chars_aliased.png b/assets/opencomputers/textures/font/chars_aliased.png new file mode 100644 index 0000000000000000000000000000000000000000..10574315b0d9bc934f7629beefe860d517263aa3 GIT binary patch literal 3155 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 literal 0 HcmV?d00001 diff --git a/li/cil/oc/Settings.scala b/li/cil/oc/Settings.scala index cbb2c0cbf..bd3072bc6 100644 --- a/li/cil/oc/Settings.scala +++ b/li/cil/oc/Settings.scala @@ -21,6 +21,7 @@ class Settings(config: Config) { val screenTextFadeStartDistance = config.getDouble("client.screenTextFadeStartDistance") val maxScreenTextRenderDistance = config.getDouble("client.maxScreenTextRenderDistance") val textLinearFiltering = config.getBoolean("client.textLinearFiltering") + val textAntiAlias = config.getBoolean("client.textAntiAlias") val rTreeDebugRenderer = false // *Not* to be configurable via config file. // ----------------------------------------------------------------------- // diff --git a/li/cil/oc/client/renderer/MonospaceFontRenderer.scala b/li/cil/oc/client/renderer/MonospaceFontRenderer.scala index fe04ea64e..32ad3448e 100644 --- a/li/cil/oc/client/renderer/MonospaceFontRenderer.scala +++ b/li/cil/oc/client/renderer/MonospaceFontRenderer.scala @@ -11,6 +11,7 @@ import scala.io.Source object MonospaceFontRenderer { val font = new ResourceLocation(Settings.resourceDomain, "textures/font/chars.png") + val fontAliased = new ResourceLocation(Settings.resourceDomain, "textures/font/chars_aliased.png") private val chars = Source.fromInputStream(MonospaceFontRenderer.getClass.getResourceAsStream("/assets/" + Settings.resourceDomain + "/textures/font/chars.txt"))("UTF-8").mkString @@ -71,7 +72,10 @@ object MonospaceFontRenderer { def drawString(x: Int, y: Int, value: Array[Char], color: Array[Short], depth: PackedColor.Depth.Value) = { if (color.length != value.length) throw new IllegalArgumentException("Color count must match char count.") - textureManager.bindTexture(MonospaceFontRenderer.font) + if (Settings.get.textAntiAlias) + textureManager.bindTexture(MonospaceFontRenderer.font) + else + textureManager.bindTexture(MonospaceFontRenderer.fontAliased) GL11.glPushMatrix() GL11.glPushAttrib(GL11.GL_COLOR_BUFFER_BIT | GL11.GL_DEPTH_BUFFER_BIT | GL11.GL_TEXTURE_BIT) GL11.glTranslatef(x, y, 0) diff --git a/li/cil/oc/server/component/Computer.scala b/li/cil/oc/server/component/Computer.scala index 716836462..148335cf2 100644 --- a/li/cil/oc/server/component/Computer.scala +++ b/li/cil/oc/server/component/Computer.scala @@ -1351,7 +1351,7 @@ class Computer(val owner: tileentity.Computer) extends ManagedComponent with Con catch { case e: LuaRuntimeException => OpenComputers.log.warning("Kernel crashed. This is a bug!\n" + e.toString + "\tat " + e.getLuaStackTrace.mkString("\n\tat ")) - crash("kernel panic") + crash("kernel panic: this is a bug, check your log file and report it") case e: LuaGcMetamethodException => if (e.getMessage != null) crash("kernel panic:\n" + e.getMessage) else crash("kernel panic:\nerror in garbage collection metamethod") @@ -1361,7 +1361,7 @@ class Computer(val owner: tileentity.Computer) extends ManagedComponent with Con crash("not enough memory") case e: Throwable => OpenComputers.log.log(Level.WARNING, "Unexpected error in kernel. This is a bug!\n", e) - crash("kernel panic") + crash("kernel panic: this is a bug, check your log file and report it") } } } diff --git a/reference.conf b/reference.conf index 957cda471..c3b173510 100644 --- a/reference.conf +++ b/reference.conf @@ -43,6 +43,10 @@ opencomputers { # anymore (for example for box drawing characters. Look it up on # Wikipedia.) textLinearFiltering: false + + # If you prefer the text on the screens to be aliased (you know, *not* + # anti-aliased / smoothed) turn this option off. + textAntiAlias: true } # Computer related settings, concerns server performance and security. From e96a1677200a90ec75b4ff886cb9611d0bbd6042 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Fri, 27 Dec 2013 18:50:01 +0100 Subject: [PATCH 7/9] bumping version to 1.0.5 for release --- li/cil/oc/OpenComputers.scala | 2 +- mcmod.info | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/li/cil/oc/OpenComputers.scala b/li/cil/oc/OpenComputers.scala index 09f0a444b..73c7eb0f3 100644 --- a/li/cil/oc/OpenComputers.scala +++ b/li/cil/oc/OpenComputers.scala @@ -13,7 +13,7 @@ import li.cil.oc.client.{PacketHandler => ClientPacketHandler} import li.cil.oc.common.Proxy import li.cil.oc.server.{PacketHandler => ServerPacketHandler} -@Mod(modid = "OpenComputers", name = "OpenComputers", version = "1.0.4", +@Mod(modid = "OpenComputers", name = "OpenComputers", version = "1.0.5", dependencies = "required-after:Forge@[9.11.1.940,);after:BuildCraft|Energy;after:ComputerCraft;after:IC2;after:MineFactoryReloaded;after:RedLogic;after:ThermalExpansion", modLanguage = "scala") @NetworkMod(clientSideRequired = true, serverSideRequired = false, diff --git a/mcmod.info b/mcmod.info index cb7d72513..a95aa92b4 100644 --- a/mcmod.info +++ b/mcmod.info @@ -2,7 +2,7 @@ { "modid": "OpenComputers", "name": "OpenComputers", - "version": "1.0.4", + "version": "1.0.5", "credits" : "Inspired by a couple of other mods, most notably ComputerCraft.", "authors": ["Florian 'Sangar' Nücke", "Johannes 'Lord Joda' Lohrer"], "description": "This mod adds modular computers and robots that can be programmed in Lua.", From 13124a76be9b3372b06bae802c7d8a9dcdb375ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sat, 28 Dec 2013 12:46:37 +0100 Subject: [PATCH 8/9] fixes ignorePower setting being ignored when turning on computers --- li/cil/oc/OpenComputers.scala | 2 +- li/cil/oc/server/component/Computer.scala | 2 +- li/cil/oc/util/LuaStateFactory.scala | 6 ++++++ mcmod.info | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/li/cil/oc/OpenComputers.scala b/li/cil/oc/OpenComputers.scala index 73c7eb0f3..03671c9f9 100644 --- a/li/cil/oc/OpenComputers.scala +++ b/li/cil/oc/OpenComputers.scala @@ -13,7 +13,7 @@ import li.cil.oc.client.{PacketHandler => ClientPacketHandler} import li.cil.oc.common.Proxy import li.cil.oc.server.{PacketHandler => ServerPacketHandler} -@Mod(modid = "OpenComputers", name = "OpenComputers", version = "1.0.5", +@Mod(modid = "OpenComputers", name = "OpenComputers", version = "1.0.5a", dependencies = "required-after:Forge@[9.11.1.940,);after:BuildCraft|Energy;after:ComputerCraft;after:IC2;after:MineFactoryReloaded;after:RedLogic;after:ThermalExpansion", modLanguage = "scala") @NetworkMod(clientSideRequired = true, serverSideRequired = false, diff --git a/li/cil/oc/server/component/Computer.scala b/li/cil/oc/server/component/Computer.scala index 148335cf2..160373f68 100644 --- a/li/cil/oc/server/component/Computer.scala +++ b/li/cil/oc/server/component/Computer.scala @@ -109,7 +109,7 @@ class Computer(val owner: tileentity.Computer) extends ManagedComponent with Con def start() = state.synchronized(state.top match { case Computer.State.Stopped => if (owner.installedMemory > 0) { - if (node.globalBuffer > cost) { + if (Settings.get.ignorePower || node.globalBuffer > cost) { init() && { switchTo(Computer.State.Starting) timeStarted = owner.world.getWorldTime diff --git a/li/cil/oc/util/LuaStateFactory.scala b/li/cil/oc/util/LuaStateFactory.scala index 9cbbe5865..47e0febf0 100644 --- a/li/cil/oc/util/LuaStateFactory.scala +++ b/li/cil/oc/util/LuaStateFactory.scala @@ -12,6 +12,7 @@ import li.cil.oc.{OpenComputers, Settings} import org.lwjgl.LWJGLUtil import scala.util.Random import scala.util.control.Breaks._ +import org.apache.commons.lang3.SystemUtils /** * Factory singleton used to spawn new LuaState instances. @@ -82,6 +83,11 @@ object LuaStateFactory { isWindows = extension == ".dll" val libPath = "/assets/" + Settings.resourceDomain + "/lib/" + if (isWindows && SystemUtils.IS_OS_WINDOWS_XP) { + OpenComputers.log.warning("Sorry, but Windows XP isn't supported. I very much recommend upgrading your Windows, anyway, since Microsoft will stop supporting it in April 2014.") + break() + } + val tmpPath = { val path = System.getProperty("java.io.tmpdir") if (path.endsWith("/") || path.endsWith("\\")) path diff --git a/mcmod.info b/mcmod.info index a95aa92b4..1b522b049 100644 --- a/mcmod.info +++ b/mcmod.info @@ -2,7 +2,7 @@ { "modid": "OpenComputers", "name": "OpenComputers", - "version": "1.0.5", + "version": "1.0.5a", "credits" : "Inspired by a couple of other mods, most notably ComputerCraft.", "authors": ["Florian 'Sangar' Nücke", "Johannes 'Lord Joda' Lohrer"], "description": "This mod adds modular computers and robots that can be programmed in Lua.", From 11a7c9242fc11dda7a4a2d561c6fe36251ed3094 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20N=C3=BCcke?= Date: Sat, 28 Dec 2013 14:13:51 +0100 Subject: [PATCH 9/9] added a bunch of validation and checks when restoring data from nbt, closes #30 --- .../tileentity/BundledRedstoneAware.scala | 12 +++++++--- li/cil/oc/common/tileentity/Case.scala | 4 +++- li/cil/oc/common/tileentity/Charger.scala | 2 +- li/cil/oc/common/tileentity/Environment.scala | 8 +++++-- li/cil/oc/common/tileentity/Inventory.scala | 2 +- .../oc/common/tileentity/RedstoneAware.scala | 6 +++-- li/cil/oc/common/tileentity/Robot.scala | 4 ++-- li/cil/oc/common/tileentity/Rotatable.scala | 2 ++ li/cil/oc/common/tileentity/Screen.scala | 2 +- li/cil/oc/server/component/GraphicsCard.scala | 5 +++- .../component/WirelessNetworkCard.scala | 2 +- li/cil/oc/util/ExtendedNBT.scala | 4 +++- li/cil/oc/util/TextBuffer.scala | 23 +++++++++++++------ 13 files changed, 53 insertions(+), 23 deletions(-) diff --git a/li/cil/oc/common/tileentity/BundledRedstoneAware.scala b/li/cil/oc/common/tileentity/BundledRedstoneAware.scala index 85de6fda1..0d8321bb3 100644 --- a/li/cil/oc/common/tileentity/BundledRedstoneAware.scala +++ b/li/cil/oc/common/tileentity/BundledRedstoneAware.scala @@ -86,14 +86,20 @@ trait BundledRedstoneAware extends RedstoneAware with IBundledEmitter with IBund super.load(nbt) nbt.getTagList(Settings.namespace + "rs.bundledInput").iterator[NBTTagIntArray].zipWithIndex.foreach { - case (input, side) => input.intArray.copyToArray(_bundledInput(side)) + case (input, side) if side < _bundledInput.length => + val safeLength = input.intArray.length min _bundledInput(side).length + input.intArray.copyToArray(_bundledInput(side), 0, safeLength) } nbt.getTagList(Settings.namespace + "rs.bundledOutput").iterator[NBTTagIntArray].zipWithIndex.foreach { - case (input, side) => input.intArray.copyToArray(_bundledOutput(side)) + case (input, side) if side < _bundledOutput.length => + val safeLength = input.intArray.length min _bundledOutput(side).length + input.intArray.copyToArray(_bundledOutput(side), 0, safeLength) } nbt.getTagList(Settings.namespace + "rs.rednetInput").iterator[NBTTagIntArray].zipWithIndex.foreach { - case (input, side) => input.intArray.copyToArray(_rednetInput(side)) + case (input, side) if side < _rednetInput.length => + val safeLength = input.intArray.length min _rednetInput(side).length + input.intArray.copyToArray(_rednetInput(side), 0, safeLength) } } diff --git a/li/cil/oc/common/tileentity/Case.scala b/li/cil/oc/common/tileentity/Case.scala index 75fa295c1..8646518a7 100644 --- a/li/cil/oc/common/tileentity/Case.scala +++ b/li/cil/oc/common/tileentity/Case.scala @@ -13,7 +13,7 @@ class Case(var tier: Int, isRemote: Boolean) extends Computer(isRemote) { // ----------------------------------------------------------------------- // override def readFromNBT(nbt: NBTTagCompound) { - tier = nbt.getByte(Settings.namespace + "tier") + tier = nbt.getByte(Settings.namespace + "tier") max 0 min 2 super.readFromNBT(nbt) } @@ -30,6 +30,7 @@ class Case(var tier: Int, isRemote: Boolean) extends Computer(isRemote) { case 0 => 4 case 1 => 6 case 2 => 8 + case _ => 0 } override def isUseableByPlayer(player: EntityPlayer) = @@ -62,5 +63,6 @@ class Case(var tier: Int, isRemote: Boolean) extends Computer(isRemote) { case (7, Some(driver)) => driver.slot(stack) == Slot.Disk case _ => false // Invalid slot. } + case _ => false } } \ No newline at end of file diff --git a/li/cil/oc/common/tileentity/Charger.scala b/li/cil/oc/common/tileentity/Charger.scala index 7bef0479e..d1a49e27e 100644 --- a/li/cil/oc/common/tileentity/Charger.scala +++ b/li/cil/oc/common/tileentity/Charger.scala @@ -55,7 +55,7 @@ class Charger extends Environment with RedstoneAware with Analyzable { override def load(nbt: NBTTagCompound) { super.load(nbt) - chargeSpeed = nbt.getDouble("chargeSpeed") + chargeSpeed = nbt.getDouble("chargeSpeed") max 0 min 1 invertSignal = nbt.getBoolean("invertSignal") } diff --git a/li/cil/oc/common/tileentity/Environment.scala b/li/cil/oc/common/tileentity/Environment.scala index 06cdc5779..bd8ea125d 100644 --- a/li/cil/oc/common/tileentity/Environment.scala +++ b/li/cil/oc/common/tileentity/Environment.scala @@ -61,13 +61,17 @@ abstract class Environment extends net.minecraft.tileentity.TileEntity with Tile override def readFromNBT(nbt: NBTTagCompound) { super.readFromNBT(nbt) load(nbt) - if (node != null && node.host == this) node.load(nbt.getCompoundTag(Settings.namespace + "node")) + if (node != null && node.host == this) { + node.load(nbt.getCompoundTag(Settings.namespace + "node")) + } } override def writeToNBT(nbt: NBTTagCompound) { super.writeToNBT(nbt) save(nbt) - if (node != null && node.host == this) nbt.setNewCompoundTag(Settings.namespace + "node", node.save) + if (node != null && node.host == this) { + nbt.setNewCompoundTag(Settings.namespace + "node", node.save) + } } // ----------------------------------------------------------------------- // diff --git a/li/cil/oc/common/tileentity/Inventory.scala b/li/cil/oc/common/tileentity/Inventory.scala index b139c663d..c07d6fcd6 100644 --- a/li/cil/oc/common/tileentity/Inventory.scala +++ b/li/cil/oc/common/tileentity/Inventory.scala @@ -107,7 +107,7 @@ trait Inventory extends TileEntity with IInventory with Persistable { nbt.getTagList(Settings.namespace + "items").foreach[NBTTagCompound](slotNbt => { val slot = slotNbt.getByte("slot") if (slot >= 0 && slot < items.length) { - items(slot) = Some(ItemStack.loadItemStackFromNBT(slotNbt.getCompoundTag("item"))) + items(slot) = Option(ItemStack.loadItemStackFromNBT(slotNbt.getCompoundTag("item"))) } }) } diff --git a/li/cil/oc/common/tileentity/RedstoneAware.scala b/li/cil/oc/common/tileentity/RedstoneAware.scala index 1bc3cfe03..aaad9bba5 100644 --- a/li/cil/oc/common/tileentity/RedstoneAware.scala +++ b/li/cil/oc/common/tileentity/RedstoneAware.scala @@ -75,8 +75,10 @@ trait RedstoneAware extends RotationAware with network.Environment with Persista override def load(nbt: NBTTagCompound) = { super.load(nbt) - nbt.getIntArray(Settings.namespace + "rs.input").copyToArray(_input) - nbt.getIntArray(Settings.namespace + "rs.output").copyToArray(_output) + val input = nbt.getIntArray(Settings.namespace + "rs.input") + input.copyToArray(_input, 0, input.length min _input.length) + val output = nbt.getIntArray(Settings.namespace + "rs.output") + output.copyToArray(_output, 0, output.length min _output.length) } override def save(nbt: NBTTagCompound) = { diff --git a/li/cil/oc/common/tileentity/Robot.scala b/li/cil/oc/common/tileentity/Robot.scala index 1b8060a3a..88544b646 100644 --- a/li/cil/oc/common/tileentity/Robot.scala +++ b/li/cil/oc/common/tileentity/Robot.scala @@ -312,9 +312,9 @@ class Robot(isRemote: Boolean) extends Computer(isRemote) with ISidedInventory w if (nbt.hasKey(Settings.namespace + "owner")) { owner = nbt.getString(Settings.namespace + "owner") } - xp = nbt.getDouble(Settings.namespace + "xp") + xp = nbt.getDouble(Settings.namespace + "xp") max 0 updateXpInfo() - selectedSlot = nbt.getInteger(Settings.namespace + "selectedSlot") + selectedSlot = nbt.getInteger(Settings.namespace + "selectedSlot") max actualSlot(0) min (getSizeInventory - 1) animationTicksTotal = nbt.getInteger(Settings.namespace + "animationTicksTotal") animationTicksLeft = nbt.getInteger(Settings.namespace + "animationTicksLeft") if (animationTicksLeft > 0) { diff --git a/li/cil/oc/common/tileentity/Rotatable.scala b/li/cil/oc/common/tileentity/Rotatable.scala index 70314e41d..96763f190 100644 --- a/li/cil/oc/common/tileentity/Rotatable.scala +++ b/li/cil/oc/common/tileentity/Rotatable.scala @@ -165,7 +165,9 @@ trait Rotatable extends RotationAware with Persistable { override def load(nbt: NBTTagCompound) = { super.load(nbt) _pitch = ForgeDirection.getOrientation(nbt.getInteger(Settings.namespace + "pitch")) + if (_pitch == ForgeDirection.UNKNOWN) _pitch = ForgeDirection.NORTH _yaw = ForgeDirection.getOrientation(nbt.getInteger(Settings.namespace + "yaw")) + if (_yaw == ForgeDirection.UNKNOWN) _yaw = ForgeDirection.SOUTH updateTranslation() } diff --git a/li/cil/oc/common/tileentity/Screen.scala b/li/cil/oc/common/tileentity/Screen.scala index 37e6c03df..c26d2c77f 100644 --- a/li/cil/oc/common/tileentity/Screen.scala +++ b/li/cil/oc/common/tileentity/Screen.scala @@ -244,7 +244,7 @@ class Screen(var tier: Int) extends Buffer with SidedEnvironment with Rotatable // ----------------------------------------------------------------------- // override def readFromNBT(nbt: NBTTagCompound) { - tier = nbt.getByte(Settings.namespace + "tier") + tier = nbt.getByte(Settings.namespace + "tier") max 0 min 2 super.readFromNBT(nbt) } diff --git a/li/cil/oc/server/component/GraphicsCard.scala b/li/cil/oc/server/component/GraphicsCard.scala index 54b295e37..2b9a340c0 100644 --- a/li/cil/oc/server/component/GraphicsCard.scala +++ b/li/cil/oc/server/component/GraphicsCard.scala @@ -216,7 +216,10 @@ abstract class GraphicsCard extends ManagedComponent { super.load(nbt) if (nbt.hasKey("screen")) { - screenAddress = Some(nbt.getString("screen")) + nbt.getString("screen") match { + case screen: String if !screen.isEmpty => screenAddress = Some(screen) + case _ => screenAddress = None + } screenInstance = None } } diff --git a/li/cil/oc/server/component/WirelessNetworkCard.scala b/li/cil/oc/server/component/WirelessNetworkCard.scala index d0c2f5b91..57f5445d2 100644 --- a/li/cil/oc/server/component/WirelessNetworkCard.scala +++ b/li/cil/oc/server/component/WirelessNetworkCard.scala @@ -187,7 +187,7 @@ class WirelessNetworkCard(val owner: TileEntity) extends NetworkCard { override def load(nbt: NBTTagCompound) { super.load(nbt) - strength = nbt.getDouble("strength") + strength = nbt.getDouble("strength") max 0 min Settings.get.maxWirelessRange } override def save(nbt: NBTTagCompound) { diff --git a/li/cil/oc/util/ExtendedNBT.scala b/li/cil/oc/util/ExtendedNBT.scala index 4497bc947..8b09c5524 100644 --- a/li/cil/oc/util/ExtendedNBT.scala +++ b/li/cil/oc/util/ExtendedNBT.scala @@ -78,7 +78,9 @@ object ExtendedNBT { def append(values: NBTBase*): Unit = append(values) - def iterator[Tag <: NBTBase] = (0 until nbt.tagCount).map(nbt.tagAt).map(_.asInstanceOf[Tag]) + def iterator[Tag <: NBTBase] = (0 until nbt.tagCount).map(nbt.tagAt).collect { + case tag: Tag => tag + } def foreach[Tag <: NBTBase](f: (Tag) => Unit) = iterator[Tag].foreach(f) diff --git a/li/cil/oc/util/TextBuffer.scala b/li/cil/oc/util/TextBuffer.scala index ec84f3c71..d33d7c08e 100644 --- a/li/cil/oc/util/TextBuffer.scala +++ b/li/cil/oc/util/TextBuffer.scala @@ -1,5 +1,6 @@ package li.cil.oc.util +import li.cil.oc.Settings import net.minecraft.nbt._ /** @@ -137,7 +138,7 @@ class TextBuffer(var width: Int, var height: Int, initialDepth: PackedColor.Dept case dx if tx > 0 => dx case dx => dx.swap } - val (dy0, dy1) = (math.max(row + ty + h - 1, math.min(0, height - 1)), math.max(row + ty, math.min(0, height))) match { + val (dy0, dy1) = (math.max(row + ty + h - 1, math.min(0, height - 1)), math.max(row + ty, math.min(0, height))) match { case dy if ty > 0 => dy case dy => dy.swap } @@ -165,17 +166,19 @@ class TextBuffer(var width: Int, var height: Int, initialDepth: PackedColor.Dept } override def load(nbt: NBTTagCompound): Unit = { - val w = nbt.getInteger("width") - val h = nbt.getInteger("height") + val w = nbt.getInteger("width") max 1 min Settings.screenResolutionsByTier(2)._1 + val h = nbt.getInteger("height") max 1 min Settings.screenResolutionsByTier(2)._2 size = (w, h) val b = nbt.getTagList("buffer") for (i <- 0 until math.min(h, b.tagCount)) { - val line = b.tagAt(i).asInstanceOf[NBTTagString].data - set(0, i, line) + b.tagAt(i) match { + case tag: NBTTagString => set(0, i, tag.data) + case _ => + } } - _depth = PackedColor.Depth(nbt.getInteger("depth")) + _depth = PackedColor.Depth(nbt.getInteger("depth") max 0 min PackedColor.Depth.maxId) foreground = nbt.getInteger("foreground") background = nbt.getInteger("background") @@ -183,7 +186,13 @@ class TextBuffer(var width: Int, var height: Int, initialDepth: PackedColor.Dept for (i <- 0 until h) { val rowColor = color(i) for (j <- 0 until w) { - rowColor(j) = c.tagAt(j + i * w).asInstanceOf[NBTTagShort].data + val index = j + i * w + if (index < c.tagCount) { + c.tagAt(index) match { + case tag: NBTTagShort => rowColor(j) = tag.data + case _ => + } + } } } }