diff --git a/assets/opencomputers/textures/font/chars_aliased.png b/assets/opencomputers/textures/font/chars_aliased.png new file mode 100644 index 000000000..10574315b Binary files /dev/null and b/assets/opencomputers/textures/font/chars_aliased.png differ diff --git a/li/cil/oc/OpenComputers.scala b/li/cil/oc/OpenComputers.scala index 09f0a444b..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.4", +@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/Settings.scala b/li/cil/oc/Settings.scala index 26c9a16b9..5d94e0d9a 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/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/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/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 d7c5ffbcb..73c6636a2 100644 --- a/li/cil/oc/common/tileentity/Inventory.scala +++ b/li/cil/oc/common/tileentity/Inventory.scala @@ -109,7 +109,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 a9f4ef825..aaad9bba5 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 @@ -74,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) = { @@ -101,16 +104,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) { diff --git a/li/cil/oc/common/tileentity/Robot.scala b/li/cil/oc/common/tileentity/Robot.scala index ac199972c..88544b646 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() } @@ -313,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/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..160373f68 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 (Settings.get.ignorePower || 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 } @@ -1336,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") @@ -1346,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/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/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") + } } } } 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/LuaStateFactory.scala b/li/cil/oc/util/LuaStateFactory.scala index 934d638ce..47e0febf0 100644 --- a/li/cil/oc/util/LuaStateFactory.scala +++ b/li/cil/oc/util/LuaStateFactory.scala @@ -5,12 +5,14 @@ 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} 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. @@ -27,6 +29,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,8 +80,14 @@ object LuaStateFactory { break() } } + 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 @@ -92,7 +102,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 +155,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 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 _ => + } + } } } } diff --git a/mcmod.info b/mcmod.info index cb7d72513..1b522b049 100644 --- a/mcmod.info +++ b/mcmod.info @@ -2,7 +2,7 @@ { "modid": "OpenComputers", "name": "OpenComputers", - "version": "1.0.4", + "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.", diff --git a/reference.conf b/reference.conf index 429f1c0fb..2d3d090eb 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.